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