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