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