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 (String key : statementBody.keySet()) {
517 if (key.startsWith(StringPool.AT)) {
518 String value = (String)statementBody.get(key);
519
520 List<Flag> flags = statement.getFlags();
521
522 if (flags == null) {
523 flags = new ArrayList<>();
524
525 statement.setFlags(flags);
526 }
527
528 Flag flag = new Flag();
529
530 flag.setName(key.substring(1));
531 flag.setValue(value);
532
533 flags.add(flag);
534 }
535 else if (key.startsWith(StringPool.DOLLAR) || key.contains(".$")) {
536 Map<String, Object> map =
537 (Map<String, Object>)statementBody.get(key);
538
539 List<Statement> variableStatements =
540 statement.getVariableStatements();
541
542 if (variableStatements == null) {
543 variableStatements = new ArrayList<>();
544
545 statement.setVariableStatements(variableStatements);
546 }
547
548 Statement variableStatement = _parseStatement(
549 statement, key, map);
550
551 variableStatements.add(variableStatement);
552 }
553 else {
554 Object value = statementBody.get(key);
555
556 parameterMap.put(CamelCaseUtil.normalizeCamelCase(key), value);
557 }
558 }
559
560 return statement;
561 }
562
563 private Object _populateFlags(Statement statement, Object result) {
564 List<Object> listResult = _convertObjectToList(result);
565
566 if (listResult != null) {
567 result = _populateFlagsList(
568 statement.getName(), listResult, new ArrayList<Object>());
569 }
570 else {
571 _populateFlagsObject(statement.getName(), result);
572 }
573
574 return result;
575 }
576
577 private List<Object> _populateFlagsList(
578 String name, List<Object> list, List<Object> results) {
579
580 for (Object object : list) {
581 List<Object> listObject = _convertObjectToList(object);
582
583 if (listObject != null) {
584 Object value = _populateFlagsList(name, listObject, results);
585
586 results.add(value);
587 }
588 else {
589 _populateFlagsObject(name, object);
590
591 results.add(object);
592 }
593 }
594
595 return results;
596 }
597
598 private void _populateFlagsObject(String name, Object object) {
599 if (name == null) {
600 return;
601 }
602
603 String pushedName = null;
604
605 int index = name.indexOf(CharPool.PERIOD);
606
607 if (index != -1) {
608 pushedName = name.substring(0, index + 1);
609 }
610
611 name = name.concat(StringPool.PERIOD);
612
613 for (Statement statement : _statements) {
614 if (statement.isExecuted()) {
615 continue;
616 }
617
618 List<Flag> flags = statement.getFlags();
619
620 if (flags == null) {
621 continue;
622 }
623
624 for (Flag flag : flags) {
625 String value = flag.getValue();
626
627 if (value == null) {
628 continue;
629 }
630
631 if (value.startsWith(name)) {
632 Map<String, Object> parameterMap =
633 statement.getParameterMap();
634
635 Object propertyValue = BeanUtil.getDeclaredProperty(
636 object, value.substring(name.length()));
637
638 parameterMap.put(flag.getName(), propertyValue);
639 }
640 else if (statement.isPushed() && value.startsWith(pushedName)) {
641 Map<String, Object> parameterMap =
642 statement.getParameterMap();
643
644 Object propertyValue = BeanUtil.getDeclaredProperty(
645 statement._pushTarget,
646 value.substring(pushedName.length()));
647
648 parameterMap.put(flag.getName(), propertyValue);
649 }
650 }
651 }
652 }
653
654 private static final JsonSerializer _jsonSerializer = new JsonSerializer();
655
656 private final String _command;
657 private List<String> _includes;
658 private final HttpServletRequest _request;
659 private final List<Statement> _statements = new ArrayList<>();
660
661 private class Flag extends NameValue<String, String> {
662 }
663
664 private class Statement {
665
666 public List<Flag> getFlags() {
667 return _flags;
668 }
669
670 public String getMethod() {
671 return _method;
672 }
673
674 public String getName() {
675 return _name;
676 }
677
678 public Map<String, Object> getParameterMap() {
679 return _parameterMap;
680 }
681
682 public Statement getParentStatement() {
683 return _parentStatement;
684 }
685
686 public List<Statement> getVariableStatements() {
687 return _variableStatements;
688 }
689
690 public String[] getWhitelist() {
691 return _whitelist;
692 }
693
694 public boolean isExecuted() {
695 return _executed;
696 }
697
698 public boolean isInner() {
699 return _inner;
700 }
701
702 public boolean isPushed() {
703 if (_pushTarget != null) {
704 return true;
705 }
706
707 return false;
708 }
709
710 public Object pop(Object result) {
711 if (_pushTarget == null) {
712 return null;
713 }
714
715 Statement statement = getParentStatement();
716
717 String statementName = statement.getName();
718
719 int index = statementName.lastIndexOf('.');
720
721 String beanName = statementName.substring(index + 1);
722
723 statementName = statementName.substring(0, index);
724
725 statement.setName(statementName);
726
727 setName(beanName + StringPool.PERIOD + getName());
728
729 BeanUtil.setDeclaredProperty(_pushTarget, beanName, result);
730
731 result = _pushTarget;
732
733 _pushTarget = null;
734
735 return result;
736 }
737
738 public Object push(Object result) {
739 if (_parentStatement == null) {
740 return null;
741 }
742
743 _pushTarget = result;
744
745 Statement statement = getParentStatement();
746
747 String variableName = getName();
748
749 int index = variableName.indexOf(".$");
750
751 String beanName = variableName.substring(0, index);
752
753 result = BeanUtil.getDeclaredProperty(result, beanName);
754
755 statement.setName(
756 statement.getName() + StringPool.PERIOD + beanName);
757
758 variableName = variableName.substring(index + 1);
759
760 setName(variableName);
761
762 return result;
763 }
764
765 public void setExecuted(boolean executed) {
766 _executed = executed;
767 }
768
769 public void setFlags(List<Flag> flags) {
770 _flags = flags;
771 }
772
773 public void setMethod(String method) {
774 _method = method;
775 }
776
777 public void setName(String name) {
778 if (name.contains(".$")) {
779 _inner = true;
780 }
781 else {
782 _inner = false;
783 }
784
785 _name = name;
786 }
787
788 public void setParameterMap(Map<String, Object> parameterMap) {
789 _parameterMap = parameterMap;
790 }
791
792 public void setVariableStatements(List<Statement> variableStatements) {
793 _variableStatements = variableStatements;
794 }
795
796 public void setWhitelist(String[] whitelist) {
797 _whitelist = whitelist;
798 }
799
800 private Statement(Statement parentStatement) {
801 _parentStatement = parentStatement;
802 }
803
804 private boolean _executed;
805 private List<Flag> _flags;
806 private boolean _inner;
807 private String _method;
808 private String _name;
809 private Map<String, Object> _parameterMap;
810 private Statement _parentStatement;
811 private Object _pushTarget;
812 private List<Statement> _variableStatements;
813 private String[] _whitelist;
814
815 }
816
817 }