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