001
014
015 package com.liferay.portal.jsonwebservice.action;
016
017 import com.liferay.portal.kernel.json.JSONFactoryUtil;
018 import com.liferay.portal.kernel.json.JSONIncludesManagerUtil;
019 import com.liferay.portal.kernel.json.JSONSerializable;
020 import com.liferay.portal.kernel.json.JSONSerializer;
021 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
022 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
023 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManagerUtil;
024 import com.liferay.portal.kernel.util.CamelCaseUtil;
025 import com.liferay.portal.kernel.util.CharPool;
026 import com.liferay.portal.kernel.util.StringPool;
027 import com.liferay.portal.kernel.util.StringUtil;
028 import com.liferay.portal.kernel.util.Validator;
029
030 import java.io.IOException;
031
032 import java.util.ArrayList;
033 import java.util.HashMap;
034 import java.util.Iterator;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Set;
038
039 import javax.servlet.http.HttpServletRequest;
040
041 import jodd.bean.BeanUtil;
042
043 import jodd.servlet.ServletUtil;
044
045 import jodd.util.NameValue;
046
047
051 public class JSONWebServiceInvokerAction implements JSONWebServiceAction {
052
053 public JSONWebServiceInvokerAction(HttpServletRequest request) {
054 _request = request;
055
056 _command = request.getParameter("cmd");
057
058 if (_command == null) {
059 try {
060 _command = ServletUtil.readRequestBody(request);
061 }
062 catch (IOException ioe) {
063 throw new IllegalArgumentException(ioe);
064 }
065 }
066 }
067
068 public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
069 return null;
070 }
071
072 public Object invoke() throws Exception {
073 Object command = JSONFactoryUtil.looseDeserializeSafe(_command);
074
075 List<Object> list = null;
076
077 boolean batchMode = false;
078
079 if (command instanceof List) {
080 list = (List<Object>)command;
081
082 batchMode = true;
083 }
084 else if (command instanceof Map) {
085 list = new ArrayList<Object>(1);
086
087 list.add(command);
088
089 batchMode = false;
090 }
091 else {
092 throw new IllegalArgumentException();
093 }
094
095 for (int i = 0; i < list.size(); i++) {
096 Map<String, Map<String, Object>> map =
097 (Map<String, Map<String, Object>>)list.get(i);
098
099 if (map.isEmpty()) {
100 throw new IllegalArgumentException();
101 }
102
103 Set<Map.Entry<String, Map<String, Object>>> entrySet =
104 map.entrySet();
105
106 Iterator<Map.Entry<String, Map<String, Object>>> iterator =
107 entrySet.iterator();
108
109 Map.Entry<String, Map<String, Object>> entry = iterator.next();
110
111 Statement statement = _parseStatement(
112 null, entry.getKey(), entry.getValue());
113
114 Object result = _executeStatement(statement);
115
116 list.set(i, result);
117 }
118
119 Object result = null;
120
121 if (batchMode == false) {
122 result = list.get(0);
123 }
124 else {
125 result = list;
126 }
127
128 return new InvokerResult(result);
129 }
130
131 public class InvokerResult implements JSONSerializable {
132
133 public String toJSONString() {
134 if (_result == null) {
135 return JSONFactoryUtil.getNullJSON();
136 }
137
138 JSONSerializer jsonSerializer =
139 JSONFactoryUtil.createJSONSerializer();
140
141 jsonSerializer.exclude("*.class");
142
143 for (Statement statement : _statements) {
144 if (_includes != null) {
145 for (String include : _includes) {
146 jsonSerializer.include(include);
147 }
148 }
149
150 String name = statement.getName();
151
152 if (name == null) {
153 continue;
154 }
155
156 String includeName = name.substring(1);
157
158 _checkJSONSerializerIncludeName(includeName);
159
160 jsonSerializer.include(includeName);
161 }
162
163 return jsonSerializer.serialize(_result);
164 }
165
166 public Object getResult() {
167 return _result;
168 }
169
170 private InvokerResult(Object result) {
171 _result = result;
172 }
173
174 private Object _result;
175
176 }
177
178 private void _addInclude(Statement statement, String name) {
179 if (_includes == null) {
180 _includes = new ArrayList<String>();
181 }
182
183 StringBuilder sb = new StringBuilder();
184
185 while (statement._parentStatement != null) {
186 String statementName = statement.getName().substring(1);
187
188 sb.insert(0, statementName + StringPool.PERIOD);
189
190 statement = statement._parentStatement;
191 }
192
193 sb.append(name);
194
195 _includes.add(sb.toString());
196 }
197
198 private Object _addVariableStatement(
199 Statement variableStatement, Object result)
200 throws Exception {
201
202 Statement statement = variableStatement.getParentStatement();
203
204 result = _populateFlags(statement, result);
205
206 String name = variableStatement.getName();
207
208 Object variableResult = _executeStatement(variableStatement);
209
210 Map<String, Object> map = _convertObjectToMap(statement, result, null);
211
212 if (!variableStatement.isInner()) {
213 map.put(name.substring(1), variableResult);
214
215 return map;
216 }
217
218 int index = name.indexOf(".$");
219
220 String innerObjectName = name.substring(0, index);
221
222 if (innerObjectName.contains(StringPool.PERIOD)) {
223 throw new IllegalArgumentException(
224 "Inner properties with more than 1 level are not supported");
225 }
226
227 Object innerObject = map.get(innerObjectName);
228
229 String innerPropertyName = name.substring(index + 2);
230
231 if (innerObject instanceof List) {
232 List<Object> innerList = (List<Object>)innerObject;
233
234 List<Object> newInnerList = new ArrayList<Object>(innerList.size());
235
236 for (Object innerListElement : innerList) {
237 Map<String, Object> newInnerListElement = _convertObjectToMap(
238 statement, innerListElement, innerObjectName);
239
240 newInnerListElement.put(innerPropertyName, variableResult);
241
242 newInnerList.add(newInnerListElement);
243 }
244
245 map.put(innerObjectName, newInnerList);
246 }
247 else {
248 Map<String, Object> innerMap = _convertObjectToMap(
249 statement, innerObject, innerObjectName);
250
251 innerMap.put(innerPropertyName, variableResult);
252
253 map.put(innerObjectName, innerMap);
254 }
255
256 return map;
257 }
258
259 private Object _addVariableStatementList(
260 Statement variableStatement, Object result, List<Object> results)
261 throws Exception {
262
263 List<Object> list = _convertObjectToList(result);
264
265 for (Object object : list) {
266 if (object instanceof List) {
267 Object value = _addVariableStatementList(
268 variableStatement, object, results);
269
270 results.add(value);
271 }
272 else {
273 Object value = _addVariableStatement(variableStatement, object);
274
275 results.add(value);
276 }
277 }
278
279 return results;
280 }
281
282 private void _checkJSONSerializerIncludeName(String includeName) {
283 if (includeName.contains(StringPool.STAR)) {
284 throw new IllegalArgumentException(
285 includeName + " has special characters");
286 }
287 }
288
289 private List<Object> _convertObjectToList(Object object) {
290 if (!(object instanceof List)) {
291 String json = JSONFactoryUtil.looseSerialize(object);
292
293 object = JSONFactoryUtil.looseDeserialize(json, ArrayList.class);
294 }
295
296 return (List<Object>)object;
297 }
298
299 private Map<String, Object> _convertObjectToMap(
300 Statement statement, Object object, String prefix) {
301
302 if (object instanceof Map) {
303 return (Map<String, Object>)object;
304 }
305
306 JSONSerializer jsonSerializer = JSONFactoryUtil.createJSONSerializer();
307
308 jsonSerializer.exclude("class");
309
310 String json = jsonSerializer.serialize(object);
311
312 Class<?> clazz = object.getClass();
313
314 object = JSONFactoryUtil.looseDeserialize(json, HashMap.class);
315
316 String[] includes = JSONIncludesManagerUtil.lookupIncludes(clazz);
317
318 for (String include : includes) {
319 if (Validator.isNotNull(prefix)) {
320 include = prefix + StringPool.PERIOD + include;
321 }
322
323 _addInclude(statement, include);
324 }
325
326 return (Map<String, Object>)object;
327 }
328
329 private Object _executeStatement(Statement statement) throws Exception {
330 JSONWebServiceAction jsonWebServiceAction =
331 JSONWebServiceActionsManagerUtil.getJSONWebServiceAction(
332 _request, statement.getMethod(), null,
333 statement.getParameterMap());
334
335 Object result = jsonWebServiceAction.invoke();
336
337 result = _filterResult(statement, result);
338
339 List<Statement> variableStatements = statement.getVariableStatements();
340
341 if (variableStatements == null) {
342 return result;
343 }
344
345 for (Statement variableStatement : variableStatements) {
346 boolean innerStatement = variableStatement.isInner();
347
348 if (innerStatement) {
349 result = variableStatement.push(result);
350 }
351
352 if (result instanceof List) {
353 result = _addVariableStatementList(
354 variableStatement, result, new ArrayList<Object>());
355
356 variableStatement.setExecuted(true);
357
358 if (innerStatement) {
359 result = variableStatement.pop(result);
360 }
361 }
362 else {
363 if (innerStatement) {
364 result = variableStatement.pop(result);
365 }
366
367 result = _addVariableStatement(variableStatement, result);
368
369 variableStatement.setExecuted(true);
370 }
371 }
372
373 return result;
374 }
375
376 private Object _filterResult(Statement statement, Object result) {
377 if (result instanceof List) {
378 result = _filterResultList(
379 statement, result, new ArrayList<Object>());
380 }
381 else {
382 result = _filterResultObject(statement, result);
383 }
384
385 return result;
386 }
387
388 private Object _filterResultList(
389 Statement statement, Object result, List<Object> results) {
390
391 List<Object> list = _convertObjectToList(result);
392
393 for (Object object : list) {
394 Object value = _filterResultObject(statement, object);
395
396 results.add(value);
397 }
398
399 return results;
400 }
401
402 private Object _filterResultObject(Statement statement, Object result) {
403 if (result == null) {
404 return result;
405 }
406
407 String[] whitelist = statement.getWhitelist();
408
409 if (whitelist == null) {
410 return result;
411 }
412
413 Map<String, Object> map = _convertObjectToMap(statement, result, null);
414
415 Map<String, Object> whitelistMap = new HashMap<String, Object>(
416 whitelist.length);
417
418 for (String key : whitelist) {
419 Object value = map.get(key);
420
421 whitelistMap.put(key, value);
422 }
423
424 return whitelistMap;
425 }
426
427 private Statement _parseStatement(
428 Statement parentStatement, String assignment,
429 Map<String, Object> statementBody) {
430
431 Statement statement = new Statement(parentStatement);
432
433 _statements.add(statement);
434
435 int x = assignment.indexOf(StringPool.EQUAL);
436
437 if (x == -1) {
438 statement.setMethod(assignment.trim());
439 }
440 else {
441 String name = assignment.substring(0, x).trim();
442
443 int y = name.indexOf(StringPool.OPEN_BRACKET);
444
445 if (y != -1) {
446 String whitelistString = name.substring(
447 y + 1, name.length() - 1);
448
449 String[] whiteList = StringUtil.split(whitelistString);
450
451 for (int i = 0; i < whiteList.length; i++) {
452 whiteList[i] = whiteList[i].trim();
453 }
454
455 statement.setWhitelist(whiteList);
456
457 name = name.substring(0, y);
458 }
459
460 statement.setName(name);
461
462 statement.setMethod(assignment.substring(x + 1).trim());
463 }
464
465 HashMap<String, Object> parameterMap = new HashMap<String, Object>(
466 statementBody.size());
467
468 statement.setParameterMap(parameterMap);
469
470 for (String key : statementBody.keySet()) {
471 if (key.startsWith(StringPool.AT)) {
472 String value = (String)statementBody.get(key);
473
474 List<Flag> flags = statement.getFlags();
475
476 if (flags == null) {
477 flags = new ArrayList<Flag>();
478
479 statement.setFlags(flags);
480 }
481
482 Flag flag = new Flag();
483
484 flag.setName(key.substring(1));
485 flag.setValue(value);
486
487 flags.add(flag);
488 }
489 else if (key.startsWith(StringPool.DOLLAR) || key.contains(".$")) {
490 Map<String, Object> map =
491 (Map<String, Object>)statementBody.get(key);
492
493 List<Statement> variableStatements =
494 statement.getVariableStatements();
495
496 if (variableStatements == null) {
497 variableStatements = new ArrayList<Statement>();
498
499 statement.setVariableStatements(variableStatements);
500 }
501
502 Statement variableStatement = _parseStatement(
503 statement, key, map);
504
505 variableStatements.add(variableStatement);
506 }
507 else {
508 Object value = statementBody.get(key);
509
510 parameterMap.put(CamelCaseUtil.normalizeCamelCase(key), value);
511 }
512 }
513
514 return statement;
515 }
516
517 private Object _populateFlags(Statement statement, Object result) {
518 if (result instanceof List) {
519 result = _populateFlagsList(
520 statement.getName(), result, new ArrayList<Object>());
521 }
522 else {
523 _populateFlagsObject(statement.getName(), result);
524 }
525
526 return result;
527 }
528
529 private List<Object> _populateFlagsList(
530 String name, Object result, List<Object> results) {
531
532 List<Object> list = _convertObjectToList(result);
533
534 for (Object object : list) {
535 if (object instanceof List) {
536 Object value = _populateFlagsList(name, object, results);
537
538 results.add(value);
539 }
540 else {
541 _populateFlagsObject(name, object);
542
543 results.add(object);
544 }
545 }
546
547 return results;
548 }
549
550 private void _populateFlagsObject(String name, Object object) {
551 if (name == null) {
552 return;
553 }
554
555 String pushedName = null;
556
557 int index = name.indexOf(CharPool.PERIOD);
558
559 if (index != -1) {
560 pushedName = name.substring(0, index + 1);
561 }
562
563 name = name.concat(StringPool.PERIOD);
564
565 for (Statement statement : _statements) {
566 if (statement.isExecuted()) {
567 continue;
568 }
569
570 List<Flag> flags = statement.getFlags();
571
572 if (flags == null) {
573 continue;
574 }
575
576 for (Flag flag : flags) {
577 String value = flag.getValue();
578
579 if (value == null) {
580 continue;
581 }
582
583 if (value.startsWith(name)) {
584 Map<String, Object> parameterMap =
585 statement.getParameterMap();
586
587 Object propertyValue = BeanUtil.getDeclaredProperty(
588 object, value.substring(name.length()));
589
590 parameterMap.put(flag.getName(), propertyValue);
591 }
592 else if (statement.isPushed() && value.startsWith(pushedName)) {
593 Map<String, Object> parameterMap =
594 statement.getParameterMap();
595
596 Object propertyValue = BeanUtil.getDeclaredProperty(
597 statement._pushTarget,
598 value.substring(pushedName.length()));
599
600 parameterMap.put(flag.getName(), propertyValue);
601 }
602 }
603 }
604 }
605
606 private String _command;
607 private List<String> _includes;
608 private HttpServletRequest _request;
609 private List<Statement> _statements = new ArrayList<Statement>();
610
611 private class Flag extends NameValue<String, String> {
612 }
613
614 private class Statement {
615
616 public List<Flag> getFlags() {
617 return _flags;
618 }
619
620 public String getMethod() {
621 return _method;
622 }
623
624 public String getName() {
625 return _name;
626 }
627
628 public Map<String, Object> getParameterMap() {
629 return _parameterMap;
630 }
631
632 public Statement getParentStatement() {
633 return _parentStatement;
634 }
635
636 public List<Statement> getVariableStatements() {
637 return _variableStatements;
638 }
639
640 public String[] getWhitelist() {
641 return _whitelist;
642 }
643
644 public boolean isExecuted() {
645 return _executed;
646 }
647
648 public boolean isInner() {
649 return _inner;
650 }
651
652 public boolean isPushed() {
653 if (_pushTarget != null) {
654 return true;
655 }
656
657 return false;
658 }
659
660 public Object push(Object result) {
661 if (_parentStatement == null) {
662 return null;
663 }
664
665 _pushTarget = result;
666
667 Statement statement = getParentStatement();
668
669 String variableName = getName();
670
671 int index = variableName.indexOf(".$");
672
673 String beanName = variableName.substring(0, index);
674
675 result = BeanUtil.getDeclaredProperty(result, beanName);
676
677 statement.setName(
678 statement.getName() + StringPool.PERIOD + beanName);
679
680 variableName = variableName.substring(index + 1);
681
682 setName(variableName);
683
684 return result;
685 }
686
687 public Object pop(Object result) {
688 if (_pushTarget == null) {
689 return null;
690 }
691
692 Statement statement = getParentStatement();
693
694 String statementName = statement.getName();
695
696 int index = statementName.lastIndexOf('.');
697
698 String beanName = statementName.substring(index + 1);
699
700 statementName = statementName.substring(0, index);
701
702 statement.setName(statementName);
703
704 setName(beanName + StringPool.PERIOD + getName());
705
706 BeanUtil.setDeclaredProperty(_pushTarget, beanName, result);
707
708 result = _pushTarget;
709
710 _pushTarget = null;
711
712 return result;
713 }
714
715 public void setExecuted(boolean executed) {
716 _executed = executed;
717 }
718
719 public void setFlags(List<Flag> flags) {
720 _flags = flags;
721 }
722
723 public void setMethod(String method) {
724 _method = method;
725 }
726
727 public void setName(String name) {
728 if (name.contains(".$")) {
729 _inner = true;
730 }
731 else {
732 _inner = false;
733 }
734
735 _name = name;
736 }
737
738 public void setParameterMap(Map<String, Object> parameterMap) {
739 _parameterMap = parameterMap;
740 }
741
742 public void setVariableStatements(List<Statement> variableStatements) {
743 _variableStatements = variableStatements;
744 }
745
746 public void setWhitelist(String[] whitelist) {
747 _whitelist = whitelist;
748 }
749
750 private Statement(Statement parentStatement) {
751 _parentStatement = parentStatement;
752 }
753
754 private boolean _executed;
755 private List<Flag> _flags;
756 private boolean _inner;
757 private String _method;
758 private String _name;
759 private Map<String, Object> _parameterMap;
760 private Statement _parentStatement;
761 private Object _pushTarget;
762 private List<Statement> _variableStatements;
763 private String[] _whitelist;
764
765 }
766
767 }