001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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 variableStatement, Object result)
166                    throws Exception {
167    
168                    String name = variableStatement.getName();
169    
170                    Object variableResult = _executeStatement(variableStatement);
171    
172                    Map<String, Object> map = _convertObjectToMap(result);
173    
174                    map.put(name.substring(1), variableResult);
175    
176                    return map;
177            }
178    
179            private Object _addVariableStatementList(
180                            Statement variableStatement, Object result, List<Object> results)
181                    throws Exception {
182    
183                    List<Object> list = _convertObjectToList(result);
184    
185                    for (Object object : list) {
186                            if (object instanceof List) {
187                                    Object value = _addVariableStatementList(
188                                            variableStatement, object, results);
189    
190                                    results.add(value);
191                            }
192                            else {
193                                    Object value = _addVariableStatement(variableStatement, object);
194    
195                                    results.add(value);
196                            }
197                    }
198    
199                    return results;
200            }
201    
202            private List<Object> _convertObjectToList(Object object) {
203                    if (!(object instanceof List)) {
204                            String json = JSONFactoryUtil.looseSerialize(object);
205    
206                            object = JSONFactoryUtil.looseDeserialize(json, ArrayList.class);
207                    }
208    
209                    return (List<Object>)object;
210            }
211    
212            private Map<String, Object> _convertObjectToMap(Object object) {
213                    if (!(object instanceof Map)) {
214                            String json = JSONFactoryUtil.looseSerialize(object);
215    
216                            object = JSONFactoryUtil.looseDeserialize(json, HashMap.class);
217                    }
218    
219                    return (Map<String, Object>)object;
220            }
221    
222            private Object _executeStatement(Statement statement) throws Exception {
223                    JSONWebServiceAction jsonWebServiceAction =
224                            JSONWebServiceActionsManagerUtil.getJSONWebServiceAction(
225                                    _request, statement.getMethod(), null,
226                                    statement.getParameterMap());
227    
228                    Object result = jsonWebServiceAction.invoke();
229    
230                    if (result instanceof List) {
231                            result = _populateFlagsList(
232                                    statement.getName(), result, new ArrayList<Object>());
233    
234                            result = _filterResultList(
235                                    statement, result, new ArrayList<Object>());
236                    }
237                    else {
238                            _populateFlags(statement.getName(), result);
239    
240                            result = _filterResult(statement, result);
241                    }
242    
243                    List<Statement> variableStatements = statement.getVariableStatements();
244    
245                    if (variableStatements != null) {
246                            for (Statement variableStatement : variableStatements) {
247                                    if (result instanceof List) {
248                                            result = _addVariableStatementList(
249                                                    variableStatement, result, new ArrayList<Object>());
250                                    }
251                                    else {
252                                            result = _addVariableStatement(variableStatement, result);
253                                    }
254                            }
255                    }
256    
257                    return result;
258            }
259    
260            private Object _filterResult(Statement statement, Object result) {
261                    if (result == null) {
262                            return result;
263                    }
264    
265                    String[] whitelist = statement.getWhitelist();
266    
267                    if (whitelist == null) {
268                            return result;
269                    }
270    
271                    Map<String, Object> map = _convertObjectToMap(result);
272    
273                    Map<String, Object> whitelistMap = new HashMap<String, Object>(
274                            whitelist.length);
275    
276                    for (String key : whitelist) {
277                            Object value = map.get(key);
278    
279                            whitelistMap.put(key, value);
280                    }
281    
282                    return whitelistMap;
283            }
284    
285            private Object _filterResultList(
286                    Statement statement, Object result, List<Object> results) {
287    
288                    List<Object> list = _convertObjectToList(result);
289    
290                    for (Object object : list) {
291                            Object value = _filterResult(statement, object);
292    
293                            results.add(value);
294                    }
295    
296                    return results;
297            }
298    
299            private Statement _parseStatement(
300                    String assignment, Map<String, Object> parameterMap) {
301    
302                    Statement statement = new Statement();
303    
304                    _statements.add(statement);
305    
306                    int x = assignment.indexOf(StringPool.EQUAL);
307    
308                    if (x == -1) {
309                            statement.setMethod(assignment.trim());
310                    }
311                    else {
312                            String name = assignment.substring(0, x).trim();
313    
314                            int y = name.indexOf(StringPool.OPEN_BRACKET);
315    
316                            if (y != -1) {
317                                    String whitelistString = name.substring(
318                                            y + 1, name.length() - 1);
319    
320                                    String[] whiteList = StringUtil.split(whitelistString);
321    
322                                    for (int i = 0; i < whiteList.length; i++) {
323                                            whiteList[i] = whiteList[i].trim();
324                                    }
325    
326                                    statement.setWhitelist(whiteList);
327    
328                                    name = name.substring(0, y);
329                            }
330    
331                            statement.setName(name);
332    
333                            statement.setMethod(assignment.substring(x + 1).trim());
334                    }
335    
336                    statement.setParameterMap(parameterMap);
337    
338                    Set<String> keySet = parameterMap.keySet();
339    
340                    Iterator<String> iterator = keySet.iterator();
341    
342                    while (iterator.hasNext()) {
343                            String key = iterator.next();
344    
345                            if (key.startsWith(StringPool.AT)) {
346                                    String value = (String)parameterMap.get(key);
347    
348                                    iterator.remove();
349    
350                                    List<Flag> flags = statement.getFlags();
351    
352                                    if (flags == null) {
353                                            flags = new ArrayList<Flag>();
354    
355                                            statement.setFlags(flags);
356                                    }
357    
358                                    Flag flag = new Flag();
359    
360                                    flag.setKey(key.substring(1));
361                                    flag.setValue(value);
362    
363                                    flags.add(flag);
364                            }
365                            else if (key.startsWith(StringPool.DOLLAR)) {
366                                    Map<String, Object> map = (Map<String, Object>)parameterMap.get(
367                                            key);
368    
369                                    iterator.remove();
370    
371                                    List<Statement> variableStatements =
372                                            statement.getVariableStatements();
373    
374                                    if (variableStatements == null) {
375                                            variableStatements = new ArrayList<Statement>();
376    
377                                            statement.setVariableStatements(variableStatements);
378                                    }
379    
380                                    Statement variableStatement = _parseStatement(key, map);
381    
382                                    variableStatements.add(variableStatement);
383                            }
384                    }
385    
386                    return statement;
387            }
388    
389            private void _populateFlags(String name, Object object) {
390                    if (name == null) {
391                            return;
392                    }
393    
394                    name = name.concat(StringPool.PERIOD);
395    
396                    for (Statement statement : _statements) {
397                            List<Flag> flags = statement.getFlags();
398    
399                            if (flags == null) {
400                                    continue;
401                            }
402    
403                            for (Flag flag : flags) {
404                                    String value = flag.getValue();
405    
406                                    if ((value == null) || !value.startsWith(name)) {
407                                            continue;
408                                    }
409    
410                                    Map<String, Object> parameterMap = statement.getParameterMap();
411    
412                                    Object propertyValue = BeanUtil.getDeclaredProperty(
413                                            object, value.substring(name.length()));
414    
415                                    parameterMap.put(flag.getKey(), propertyValue);
416    
417                                    flag.setValue(null);
418                            }
419                    }
420            }
421    
422            private List<Object> _populateFlagsList(
423                    String name, Object result, List<Object> results) {
424    
425                    List<Object> list = _convertObjectToList(result);
426    
427                    for (Object object : list) {
428                            if (object instanceof List) {
429                                    Object value = _populateFlagsList(name, object, results);
430    
431                                    results.add(value);
432                            }
433                            else {
434                                    _populateFlags(name, object);
435    
436                                    results.add(object);
437                            }
438                    }
439    
440                    return results;
441            }
442    
443            private String _command;
444            private HttpServletRequest _request;
445            private List<Statement> _statements = new ArrayList<Statement>();
446    
447            private class Flag extends KeyValue<String, String> {
448            }
449    
450            private class Statement {
451    
452                    public List<Flag> getFlags() {
453                            return _flags;
454                    }
455    
456                    public String getMethod() {
457                            return _method;
458                    }
459    
460                    public String getName() {
461                            return _name;
462                    }
463    
464                    public Map<String, Object> getParameterMap() {
465                            return _parameterMap;
466                    }
467    
468                    public List<Statement> getVariableStatements() {
469                            return _variableStatements;
470                    }
471    
472                    public String[] getWhitelist() {
473                            return _whitelist;
474                    }
475    
476                    public void setFlags(List<Flag> flags) {
477                            _flags = flags;
478                    }
479    
480                    public void setMethod(String method) {
481                            _method = method;
482                    }
483    
484                    public void setName(String name) {
485                            _name = name;
486                    }
487    
488                    public void setParameterMap(Map<String, Object> parameterMap) {
489                            _parameterMap = parameterMap;
490                    }
491    
492                    public void setVariableStatements(List<Statement> variableStatements) {
493                            _variableStatements = variableStatements;
494                    }
495    
496                    public void setWhitelist(String[] whitelist) {
497                            _whitelist = whitelist;
498                    }
499    
500                    private List<Flag> _flags;
501                    private String _method;
502                    private String _name;
503                    private Map<String, Object> _parameterMap;
504                    private List<Statement> _variableStatements;
505                    private String[] _whitelist;
506    
507            }
508    
509    }