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