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