View Javadoc

1   /*
2    * $Id: JsonExpressionEvaluator.java 22391 2011-07-12 12:00:48Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.json;
12  
13  import org.mule.api.MuleMessage;
14  import org.mule.api.MuleRuntimeException;
15  import org.mule.api.expression.ExpressionEvaluator;
16  import org.mule.config.i18n.CoreMessages;
17  import org.mule.util.NumberUtils;
18  
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.codehaus.jackson.JsonNode;
26  import org.codehaus.jackson.node.ArrayNode;
27  import org.codehaus.jackson.node.ObjectNode;
28  import org.codehaus.jackson.node.ValueNode;
29  
30  /**
31   * An expression evaluator to allow users to define json expressions in their mule configuration, i.e.
32   * <code>
33   * #[json:person/addresses[0]/postcode]
34   * </code>
35   * <p/>
36   * See the {@link org.mule.module.json.JsonData} object for mor information about the query syntax.
37   * <p/>
38   * It is also possible to use this evaluator in {@link org.mule.routing.filters.ExpressionFilter} objects. For example
39   * a filter could be defined as -
40   * <p/>
41   * <code>
42   * #[json:person/registered]
43   * </code>
44   * <p/>
45   * Where 'registered' is a boolean value.  It is also possible to filter on the existence of a value i.e.
46   * <p/>
47   * <code>
48   * #[json:person/favouriteColour]
49   * </code>
50   * <p/>
51   * Which would return true if 'favouriteColour' has been set. This evaluator also dds two logic operators you can use
52   * to create more sophisticated boolean expressions; equals and not equals -
53   * <p/>
54   * <code>
55   * #[json:person/favouriteColour = red]
56   * </code>
57   * <p/>
58   * or
59   * <p/>
60   * <code>
61   * #[json:person/favouriteColour != brown]
62   * </code>
63   *
64   * @see org.mule.module.json.JsonData
65   */
66  public class JsonExpressionEvaluator implements ExpressionEvaluator
67  {
68      /**
69       * logger used by this class
70       */
71      protected transient final Log logger = LogFactory.getLog(JsonExpressionEvaluator.class);
72  
73      @Override
74      public Object evaluate(String expression, MuleMessage message)
75      {
76          String compareTo = null;
77          boolean not = false;
78          int start = expression.lastIndexOf("/");
79          if (start == -1)
80          {
81              start = 0;
82          }
83          int i=0;
84          if ((i = expression.indexOf("!=", start)) > -1)
85          {
86              compareTo = expression.substring(i + 2, expression.length()).trim();
87              expression = expression.substring(0, i).trim();
88              not = true;
89          }
90          else if ((i = expression.indexOf("=", start)) > -1)
91          {
92              compareTo = expression.substring(i + 1, expression.length()).trim();
93              expression = expression.substring(0, i).trim();
94          }
95          
96          try
97          {
98              String json = message.getPayloadAsString();
99              JsonData data = new JsonData(json);
100             try
101             {
102                 JsonNode resultNode = data.get(expression);
103                 if (compareTo != null)
104                 {
105                     Object resultValue = resultNode.isValueNode() ? resultNode.getValueAsText() : resultNode;
106                     if (compareTo.equalsIgnoreCase("null"))
107                     {
108                         boolean answer = resultValue == null;
109                         return (not ? !answer : answer);
110                     }
111                     else if (resultValue instanceof Number && NumberUtils.isDigits(compareTo))
112                     {
113                         boolean answer = NumberUtils.createNumber(compareTo).equals(resultValue);
114                         return (not ? !answer : answer);
115                     }
116                     else if (resultValue instanceof Boolean
117                              && (compareTo.equalsIgnoreCase("true") || compareTo.equalsIgnoreCase("false")))
118                     {
119                         boolean answer = resultValue.equals(Boolean.valueOf(compareTo));
120                         return (not ? !answer : answer);
121                     }
122                     else
123                     {
124                         boolean answer = compareTo.equals(resultValue);
125                         return (not ? !answer : answer);
126                     }
127                 }
128                 else
129                 {
130                     return extractResultFromNode(resultNode);
131                 }
132             }
133             catch (IllegalArgumentException e)
134             {
135                 if (compareTo == null)
136                 {
137                     logger.debug("returning null for json expression: " + expression + ": " + e.getMessage());
138                     return null;
139                 }
140                 //If the element does not exist but is matching against 'null' return true, otherwise false
141                 return (compareTo.equalsIgnoreCase("null")) & !not;
142             }
143         }
144         catch (Exception e)
145         {
146             throw new MuleRuntimeException(CoreMessages.failedToProcessExtractorFunction(getName() + ":" + expression), e);
147         }
148     }
149 
150     protected Object extractResultFromNode(JsonNode result)
151     {
152         if (result instanceof ValueNode)
153         {
154             return result.getValueAsText();
155         }
156         if (result instanceof ObjectNode)
157         {
158             return ((ObjectNode) result).toString();
159         }
160         else if (result instanceof ArrayNode)
161         {
162             List<Object> parts = new ArrayList<Object>();
163             for (Iterator<JsonNode> i = result.getElements(); i.hasNext();)
164             {
165                 JsonNode arrayNode = i.next();
166                 parts.add(extractResultFromNode(arrayNode));
167             }
168             return parts;
169         }
170         else
171         {
172             return result;
173         }
174     }
175     
176     @Override
177     public void setName(String name)
178     {
179         throw new UnsupportedOperationException("setName");
180     }
181 
182     @Override
183     public String getName()
184     {
185         return "json";
186     }
187 }