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 @Override
141 public String toJSONString() {
142 if (_result == null) {
143 return JSONFactoryUtil.getNullJSON();
144 }
145
146 JSONSerializer jsonSerializer =
147 JSONFactoryUtil.createJSONSerializer();
148
149 jsonSerializer.exclude("*.class");
150
151 for (Statement statement : _statements) {
152 if (_includes != null) {
153 for (String include : _includes) {
154 jsonSerializer.include(include);
155 }
156 }
157
158 String name = statement.getName();
159
160 if (name == null) {
161 continue;
162 }
163
164 String includeName = name.substring(1);
165
166 _checkJSONSerializerIncludeName(includeName);
167
168 jsonSerializer.include(includeName);
169 }
170
171 return jsonSerializer.serialize(_result);
172 }
173
174 public Object getResult() {
175 return _result;
176 }
177
178 private InvokerResult(Object result) {
179 _result = result;
180 }
181
182 private Object _result;
183
184 }
185
186 private void _addInclude(Statement statement, String name) {
187 if (_includes == null) {
188 _includes = new ArrayList<String>();
189 }
190
191 StringBuilder sb = new StringBuilder();
192
193 while (statement._parentStatement != null) {
194 String statementName = statement.getName().substring(1);
195
196 sb.insert(0, statementName + StringPool.PERIOD);
197
198 statement = statement._parentStatement;
199 }
200
201 sb.append(name);
202
203 _includes.add(sb.toString());
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 void _checkJSONSerializerIncludeName(String includeName) {
292 if (includeName.contains(StringPool.STAR)) {
293 throw new IllegalArgumentException(
294 includeName + " has special characters");
295 }
296 }
297
298 private List<Object> _convertObjectToList(Object object) {
299 if (object == null) {
300 return null;
301 }
302
303 if (object instanceof List) {
304 return (List<Object>)object;
305 }
306
307 if (object instanceof Iterable) {
308 List<Object> list = new ArrayList<Object>();
309
310 Iterable<?> iterable = (Iterable<?>)object;
311
312 Iterator<?> iterator = iterable.iterator();
313
314 while (iterator.hasNext()) {
315 list.add(iterator.next());
316 }
317
318 return list;
319 }
320
321 Class<?> clazz = object.getClass();
322
323 if (!clazz.isArray()) {
324 return null;
325 }
326
327 Class<?> componentType = clazz.getComponentType();
328
329 if (!componentType.isPrimitive()) {
330 return ListUtil.toList((Object[])object);
331 }
332
333 List<Object> list = new ArrayList<Object>();
334
335 for (int i = 0; i < Array.getLength(object); i++) {
336 list.add(Array.get(object, i));
337 }
338
339 return list;
340 }
341
342 private Map<String, Object> _convertObjectToMap(
343 Statement statement, Object object, String prefix) {
344
345 if (object instanceof Map) {
346 return (Map<String, Object>)object;
347 }
348
349 Class<?> clazz = object.getClass();
350
351 HashMap<Object, Object> destinationMap = new HashMap<Object, Object>();
352
353 BeanCopy beanCopy = BeanCopy.beans(object, destinationMap);
354
355 beanCopy.exclude(JSONIncludesManagerUtil.lookupExcludes(clazz));
356
357 beanCopy.copy();
358
359 object = destinationMap;
360
361 String[] includes = JSONIncludesManagerUtil.lookupIncludes(clazz);
362
363 for (String include : includes) {
364 if (Validator.isNotNull(prefix)) {
365 include = prefix + StringPool.PERIOD + include;
366 }
367
368 _addInclude(statement, include);
369 }
370
371 return (Map<String, Object>)object;
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<String, Object>(
463 whitelist.length);
464
465 for (String key : whitelist) {
466 Object value = map.get(key);
467
468 whitelistMap.put(key, value);
469 }
470
471 return whitelistMap;
472 }
473
474 private Statement _parseStatement(
475 Statement parentStatement, String assignment,
476 Map<String, Object> statementBody) {
477
478 Statement statement = new Statement(parentStatement);
479
480 _statements.add(statement);
481
482 int x = assignment.indexOf(StringPool.EQUAL);
483
484 if (x == -1) {
485 statement.setMethod(assignment.trim());
486 }
487 else {
488 String name = assignment.substring(0, x).trim();
489
490 int y = name.indexOf(StringPool.OPEN_BRACKET);
491
492 if (y != -1) {
493 String whitelistString = name.substring(
494 y + 1, name.length() - 1);
495
496 String[] whiteList = StringUtil.split(whitelistString);
497
498 for (int i = 0; i < whiteList.length; i++) {
499 whiteList[i] = whiteList[i].trim();
500 }
501
502 statement.setWhitelist(whiteList);
503
504 name = name.substring(0, y);
505 }
506
507 statement.setName(name);
508
509 statement.setMethod(assignment.substring(x + 1).trim());
510 }
511
512 HashMap<String, Object> parameterMap = new HashMap<String, Object>(
513 statementBody.size());
514
515 statement.setParameterMap(parameterMap);
516
517 for (String key : statementBody.keySet()) {
518 if (key.startsWith(StringPool.AT)) {
519 String value = (String)statementBody.get(key);
520
521 List<Flag> flags = statement.getFlags();
522
523 if (flags == null) {
524 flags = new ArrayList<Flag>();
525
526 statement.setFlags(flags);
527 }
528
529 Flag flag = new Flag();
530
531 flag.setName(key.substring(1));
532 flag.setValue(value);
533
534 flags.add(flag);
535 }
536 else if (key.startsWith(StringPool.DOLLAR) || key.contains(".$")) {
537 Map<String, Object> map =
538 (Map<String, Object>)statementBody.get(key);
539
540 List<Statement> variableStatements =
541 statement.getVariableStatements();
542
543 if (variableStatements == null) {
544 variableStatements = new ArrayList<Statement>();
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 = statementBody.get(key);
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 Map<String, Object> parameterMap =
634 statement.getParameterMap();
635
636 Object propertyValue = BeanUtil.getDeclaredProperty(
637 object, value.substring(name.length()));
638
639 parameterMap.put(flag.getName(), propertyValue);
640 }
641 else if (statement.isPushed() && value.startsWith(pushedName)) {
642 Map<String, Object> parameterMap =
643 statement.getParameterMap();
644
645 Object propertyValue = BeanUtil.getDeclaredProperty(
646 statement._pushTarget,
647 value.substring(pushedName.length()));
648
649 parameterMap.put(flag.getName(), propertyValue);
650 }
651 }
652 }
653 }
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 push(Object result) {
710 if (_parentStatement == null) {
711 return null;
712 }
713
714 _pushTarget = result;
715
716 Statement statement = getParentStatement();
717
718 String variableName = getName();
719
720 int index = variableName.indexOf(".$");
721
722 String beanName = variableName.substring(0, index);
723
724 result = BeanUtil.getDeclaredProperty(result, beanName);
725
726 statement.setName(
727 statement.getName() + StringPool.PERIOD + beanName);
728
729 variableName = variableName.substring(index + 1);
730
731 setName(variableName);
732
733 return result;
734 }
735
736 public Object pop(Object result) {
737 if (_pushTarget == null) {
738 return null;
739 }
740
741 Statement statement = getParentStatement();
742
743 String statementName = statement.getName();
744
745 int index = statementName.lastIndexOf('.');
746
747 String beanName = statementName.substring(index + 1);
748
749 statementName = statementName.substring(0, index);
750
751 statement.setName(statementName);
752
753 setName(beanName + StringPool.PERIOD + getName());
754
755 BeanUtil.setDeclaredProperty(_pushTarget, beanName, result);
756
757 result = _pushTarget;
758
759 _pushTarget = null;
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 }