001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    
027    import java.io.IOException;
028    
029    import java.util.ArrayList;
030    import java.util.HashMap;
031    import java.util.Iterator;
032    import java.util.List;
033    import java.util.Map;
034    import java.util.Set;
035    
036    import javax.servlet.http.HttpServletRequest;
037    
038    import jodd.bean.BeanUtil;
039    
040    import jodd.servlet.ServletUtil;
041    
042    import jodd.util.KeyValue;
043    
044    /**
045     * @author Igor Spasic
046     * @author Eduardo Lundgren
047     */
048    public class JSONWebServiceInvokerAction implements JSONWebServiceAction {
049    
050            public JSONWebServiceInvokerAction(HttpServletRequest request) {
051                    _request = request;
052    
053                    _command = request.getParameter("cmd");
054    
055                    if (_command == null) {
056                            try {
057                                    _command = ServletUtil.readRequestBody(request);
058                            }
059                            catch (IOException ioe) {
060                                    throw new IllegalArgumentException(ioe);
061                            }
062                    }
063            }
064    
065            public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
066                    return null;
067            }
068    
069            public Object invoke() throws Exception {
070                    Object command = JSONFactoryUtil.looseDeserializeSafe(_command);
071    
072                    List<Object> list = null;
073    
074                    boolean batchMode = false;
075    
076                    if (command instanceof List) {
077                            list = (List<Object>)command;
078    
079                            batchMode = true;
080                    }
081                    else if (command instanceof Map) {
082                            list = new ArrayList<Object>(1);
083    
084                            list.add(command);
085    
086                            batchMode = false;
087                    }
088                    else {
089                            throw new IllegalArgumentException();
090                    }
091    
092                    for (int i = 0; i < list.size(); i++) {
093                            Map<String, Map<String, Object>> map =
094                                    (Map<String, Map<String, Object>>)list.get(i);
095    
096                            if (map.isEmpty()) {
097                                    throw new IllegalArgumentException();
098                            }
099    
100                            Set<Map.Entry<String, Map<String, Object>>> entrySet =
101                                    map.entrySet();
102    
103                            Iterator<Map.Entry<String, Map<String, Object>>> iterator =
104                                    entrySet.iterator();
105    
106                            Map.Entry<String, Map<String, Object>> entry = iterator.next();
107    
108                            Statement statement = _parseStatement(
109                                    entry.getKey(), entry.getValue());
110    
111                            Object result = _executeStatement(statement);
112    
113                            list.set(i, result);
114                    }
115    
116                    Object result = null;
117    
118                    if (batchMode == false) {
119                            result = list.get(0);
120                    }
121                    else {
122                            result = list;
123                    }
124    
125                    return new InvokerResult(result);
126            }
127    
128            public class InvokerResult implements JSONSerializable {
129    
130                    public String toJSONString() {
131                            if (_result == null) {
132                                    return JSONFactoryUtil.getNullJSON();
133                            }
134    
135                            JSONSerializer jsonSerializer =
136                                    JSONFactoryUtil.createJSONSerializer();
137    
138                            jsonSerializer.exclude("*.class");
139    
140                            for (Statement statement : _statements) {
141                                    String name = statement.getName();
142    
143                                    if (name == null) {
144                                            continue;
145                                    }
146    
147                                    String includeName = name.substring(1);
148    
149                                    _checkJSONSerializerIncludeName(includeName);
150    
151                                    jsonSerializer.include(includeName);
152                            }
153    
154                            return jsonSerializer.serialize(_result);
155                    }
156    
157                    public Object getResult() {
158                            return _result;
159                    }
160    
161                    private InvokerResult(Object result) {
162                            _result = result;
163                    }
164    
165                    private Object _result;
166    
167            }
168    
169            private Object _addVariableStatement(
170                            Statement statement, Statement variableStatement, Object result)
171                    throws Exception {
172    
173                    result = _populateFlags(statement, result);
174    
175                    String name = variableStatement.getName();
176    
177                    Object variableResult = _executeStatement(variableStatement);
178    
179                    Map<String, Object> map = _convertObjectToMap(result);
180    
181                    map.put(name.substring(1), variableResult);
182    
183                    return map;
184            }
185    
186            private Object _addVariableStatementList(
187                            Statement statement, Statement variableStatement, Object result,
188                            List<Object> results)
189                    throws Exception {
190    
191                    List<Object> list = _convertObjectToList(result);
192    
193                    for (Object object : list) {
194                            if (object instanceof List) {
195                                    Object value = _addVariableStatementList(
196                                            statement, variableStatement, object, results);
197    
198                                    results.add(value);
199                            }
200                            else {
201                                    Object value = _addVariableStatement(
202                                            statement, variableStatement, object);
203    
204                                    results.add(value);
205                            }
206                    }
207    
208                    return results;
209            }
210    
211            private void _checkJSONSerializerIncludeName(String includeName) {
212                    if (includeName.contains(StringPool.STAR)) {
213                            throw new IllegalArgumentException(
214                                    includeName + " has special characters");
215                    }
216            }
217    
218            private List<Object> _convertObjectToList(Object object) {
219                    if (!(object instanceof List)) {
220                            String json = JSONFactoryUtil.looseSerialize(object);
221    
222                            object = JSONFactoryUtil.looseDeserialize(json, ArrayList.class);
223                    }
224    
225                    return (List<Object>)object;
226            }
227    
228            private Map<String, Object> _convertObjectToMap(Object object) {
229                    if (!(object instanceof Map)) {
230                            String json = JSONFactoryUtil.looseSerialize(object);
231    
232                            object = JSONFactoryUtil.looseDeserialize(json, HashMap.class);
233                    }
234    
235                    return (Map<String, Object>)object;
236            }
237    
238            private Object _executeStatement(Statement statement) throws Exception {
239                    JSONWebServiceAction jsonWebServiceAction =
240                            JSONWebServiceActionsManagerUtil.getJSONWebServiceAction(
241                                    _request, statement.getMethod(), null,
242                                    statement.getParameterMap());
243    
244                    Object result = jsonWebServiceAction.invoke();
245    
246                    result = _filterResult(statement, result);
247    
248                    List<Statement> variableStatements = statement.getVariableStatements();
249    
250                    if (variableStatements != null) {
251                            for (Statement variableStatement : variableStatements) {
252                                    if (result instanceof List) {
253                                            result = _addVariableStatementList(
254                                                    statement, variableStatement, result,
255                                                    new ArrayList<Object>());
256                                    }
257                                    else {
258                                            result = _addVariableStatement(
259                                                    statement, variableStatement, result);
260                                    }
261                            }
262                    }
263    
264                    return result;
265            }
266    
267            private Object _filterResult(Statement statement, Object result) {
268                    if (result instanceof List) {
269                            result = _filterResultList(
270                                    statement, result, new ArrayList<Object>());
271                    }
272                    else {
273                            result = _filterResultObject(statement, result);
274                    }
275    
276                    return result;
277            }
278    
279            private Object _filterResultList(
280                    Statement statement, Object result, List<Object> results) {
281    
282                    List<Object> list = _convertObjectToList(result);
283    
284                    for (Object object : list) {
285                            Object value = _filterResultObject(statement, object);
286    
287                            results.add(value);
288                    }
289    
290                    return results;
291            }
292    
293            private Object _filterResultObject(Statement statement, Object result) {
294                    if (result == null) {
295                            return result;
296                    }
297    
298                    String[] whitelist = statement.getWhitelist();
299    
300                    if (whitelist == null) {
301                            return result;
302                    }
303    
304                    Map<String, Object> map = _convertObjectToMap(result);
305    
306                    Map<String, Object> whitelistMap = new HashMap<String, Object>(
307                            whitelist.length);
308    
309                    for (String key : whitelist) {
310                            Object value = map.get(key);
311    
312                            whitelistMap.put(key, value);
313                    }
314    
315                    return whitelistMap;
316            }
317    
318            private Statement _parseStatement(
319                    String assignment, Map<String, Object> statementBody) {
320    
321                    Statement statement = new Statement();
322    
323                    _statements.add(statement);
324    
325                    int x = assignment.indexOf(StringPool.EQUAL);
326    
327                    if (x == -1) {
328                            statement.setMethod(assignment.trim());
329                    }
330                    else {
331                            String name = assignment.substring(0, x).trim();
332    
333                            int y = name.indexOf(StringPool.OPEN_BRACKET);
334    
335                            if (y != -1) {
336                                    String whitelistString = name.substring(
337                                            y + 1, name.length() - 1);
338    
339                                    String[] whiteList = StringUtil.split(whitelistString);
340    
341                                    for (int i = 0; i < whiteList.length; i++) {
342                                            whiteList[i] = whiteList[i].trim();
343                                    }
344    
345                                    statement.setWhitelist(whiteList);
346    
347                                    name = name.substring(0, y);
348                            }
349    
350                            statement.setName(name);
351    
352                            statement.setMethod(assignment.substring(x + 1).trim());
353                    }
354    
355                    HashMap<String, Object> parameterMap = new HashMap<String, Object>(
356                            statementBody.size());
357    
358                    statement.setParameterMap(parameterMap);
359    
360                    for (String key : statementBody.keySet()) {
361                            if (key.startsWith(StringPool.AT)) {
362                                    String value = (String)statementBody.get(key);
363    
364                                    List<Flag> flags = statement.getFlags();
365    
366                                    if (flags == null) {
367                                            flags = new ArrayList<Flag>();
368    
369                                            statement.setFlags(flags);
370                                    }
371    
372                                    Flag flag = new Flag();
373    
374                                    flag.setKey(key.substring(1));
375                                    flag.setValue(value);
376    
377                                    flags.add(flag);
378                            }
379                            else if (key.startsWith(StringPool.DOLLAR)) {
380                                    Map<String, Object> map =
381                                            (Map<String, Object>)statementBody.get(key);
382    
383                                    List<Statement> variableStatements =
384                                            statement.getVariableStatements();
385    
386                                    if (variableStatements == null) {
387                                            variableStatements = new ArrayList<Statement>();
388    
389                                            statement.setVariableStatements(variableStatements);
390                                    }
391    
392                                    Statement variableStatement = _parseStatement(key, map);
393    
394                                    variableStatements.add(variableStatement);
395                            }
396                            else {
397                                    Object value = statementBody.get(key);
398    
399                                    parameterMap.put(CamelCaseUtil.normalizeCamelCase(key), value);
400                            }
401                    }
402    
403                    return statement;
404            }
405    
406            private Object _populateFlags(Statement statement, Object result) {
407                    if (result instanceof List) {
408                            result = _populateFlagsList(
409                                    statement.getName(), result, new ArrayList<Object>());
410                    }
411                    else {
412                            _populateFlagsObject(statement.getName(), result);
413                    }
414    
415                    return result;
416            }
417    
418            private List<Object> _populateFlagsList(
419                    String name, Object result, List<Object> results) {
420    
421                    List<Object> list = _convertObjectToList(result);
422    
423                    for (Object object : list) {
424                            if (object instanceof List) {
425                                    Object value = _populateFlagsList(name, object, results);
426    
427                                    results.add(value);
428                            }
429                            else {
430                                    _populateFlagsObject(name, object);
431    
432                                    results.add(object);
433                            }
434                    }
435    
436                    return results;
437            }
438    
439            private void _populateFlagsObject(String name, Object object) {
440                    if (name == null) {
441                            return;
442                    }
443    
444                    name = name.concat(StringPool.PERIOD);
445    
446                    for (Statement statement : _statements) {
447                            List<Flag> flags = statement.getFlags();
448    
449                            if (flags == null) {
450                                    continue;
451                            }
452    
453                            for (Flag flag : flags) {
454                                    String value = flag.getValue();
455    
456                                    if ((value == null) || !value.startsWith(name)) {
457                                            continue;
458                                    }
459    
460                                    Map<String, Object> parameterMap = statement.getParameterMap();
461    
462                                    Object propertyValue = BeanUtil.getDeclaredProperty(
463                                            object, value.substring(name.length()));
464    
465                                    parameterMap.put(flag.getKey(), propertyValue);
466                            }
467                    }
468            }
469    
470            private String _command;
471            private HttpServletRequest _request;
472            private List<Statement> _statements = new ArrayList<Statement>();
473    
474            private class Flag extends KeyValue<String, String> {
475            }
476    
477            private class Statement {
478    
479                    public List<Flag> getFlags() {
480                            return _flags;
481                    }
482    
483                    public String getMethod() {
484                            return _method;
485                    }
486    
487                    public String getName() {
488                            return _name;
489                    }
490    
491                    public Map<String, Object> getParameterMap() {
492                            return _parameterMap;
493                    }
494    
495                    public List<Statement> getVariableStatements() {
496                            return _variableStatements;
497                    }
498    
499                    public String[] getWhitelist() {
500                            return _whitelist;
501                    }
502    
503                    public void setFlags(List<Flag> flags) {
504                            _flags = flags;
505                    }
506    
507                    public void setMethod(String method) {
508                            _method = method;
509                    }
510    
511                    public void setName(String name) {
512                            _name = name;
513                    }
514    
515                    public void setParameterMap(Map<String, Object> parameterMap) {
516                            _parameterMap = parameterMap;
517                    }
518    
519                    public void setVariableStatements(List<Statement> variableStatements) {
520                            _variableStatements = variableStatements;
521                    }
522    
523                    public void setWhitelist(String[] whitelist) {
524                            _whitelist = whitelist;
525                    }
526    
527                    private List<Flag> _flags;
528                    private String _method;
529                    private String _name;
530                    private Map<String, Object> _parameterMap;
531                    private List<Statement> _variableStatements;
532                    private String[] _whitelist;
533    
534            }
535    
536    }