View Javadoc

1   /*
2    * $Id: ExpressionFilter.java 19365 2010-09-04 03:24:52Z 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  package org.mule.routing.filters;
11  
12  import org.mule.api.MuleContext;
13  import org.mule.api.MuleMessage;
14  import org.mule.api.context.MuleContextAware;
15  import org.mule.api.routing.filter.Filter;
16  import org.mule.expression.ExpressionConfig;
17  
18  import java.text.MessageFormat;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  
23  import static org.mule.util.ClassUtils.equal;
24  import static org.mule.util.ClassUtils.hash;
25  
26  /**
27   * Allows boolean expressions to be executed on a message. Note that when using this filter you must be able to either specify
28   * a boolean expression when using an expression filter or use one of the standard Mule filters.  These can be defined as follows -
29   *
30   * <ul>
31   * <li>RegEx - 'regex:<pattern>': #[regex:'error' [0-9]]</li>
32   * <li>Wildcard - 'wildcard:<pattern>': #[wildcard: *foo*</li>
33   * <li>PayloadType - 'payload-type:<fully qualified class name>': #[payload:javax.jms.TextMessage]</li>
34   * <li>ExceptionType - 'exception-type:<fully qualified class name>': #[exception-type:java.io.FileNotFoundException]</li>
35   * <li>Header - 'header:<boolean expression>': #[header:foo!=null]</li>
36   * </ul>
37   *
38   * Otherwise you can use eny expression filter providing you can define a boolean expression i.e.
39   * <code>
40   * #[xpath:count(/Foo/Bar) == 0]
41   * </code>
42   *
43   * Note that it if the expression is not a boolean expression this filter will return true if the expression returns a result
44   * 
45   */
46  public class ExpressionFilter implements Filter, MuleContextAware
47  {
48      /**
49       * logger used by this class
50       */
51      protected transient final Log logger = LogFactory.getLog(ExpressionFilter.class);
52  
53      private ExpressionConfig config;
54      private String fullExpression;
55      private boolean nullReturnsTrue = false;
56      private MuleContext muleContext;
57  
58      /**
59       * The class-loader that should be used to load any classes used in scripts.
60       * Default to the classloader used to load this filter
61       **/
62      private ClassLoader expressionEvaluationClassLoader = Thread.currentThread().getContextClassLoader();
63      
64      /** For evaluators that are not expression languages we can delegate the execution to another filter */
65      private Filter delegateFilter;
66  
67      public ExpressionFilter(String evaluator, String customEvaluator, String expression)
68      {
69          this.config = new ExpressionConfig(expression, evaluator, customEvaluator);
70      }
71  
72      public ExpressionFilter(String evaluator, String expression)
73      {
74          this.config = new ExpressionConfig(expression, evaluator, null);
75      }
76  
77      public ExpressionFilter(String expression)
78      {
79          this.config = new ExpressionConfig();
80          this.config.parse(expression);
81      }
82  
83      public ExpressionFilter()
84      {
85          super();
86          this.config = new ExpressionConfig();
87      }
88  
89      public void setMuleContext(MuleContext context)
90      {
91          this.muleContext = context;
92      }
93  
94      /**
95       * Check a given message against this filter.
96       *
97       * @param message a non null message to filter.
98       * @return <code>true</code> if the message matches the filter
99       */
100     public boolean accept(MuleMessage message)
101     {
102         String expr = getFullExpression();
103         if (delegateFilter != null)
104         {
105             boolean result = delegateFilter.accept(message);
106             if (logger.isDebugEnabled())
107             {
108                 logger.debug(MessageFormat.format("Result of expression filter: {0} is: {1}", expr, result));
109             }
110             return result;
111         }
112 
113         Object result;
114 
115         // MULE-4797 Because there is no way to specify the class-loader that script
116         // engines use and because scripts when used for expressions are compiled in
117         // runtime rather than at initialization the only way to ensure the correct
118         // class-loader to used is to switch it out here. We may want to consider
119         // passing the class-loader to the ExpressionManager and only doing this for
120         // certain ExpressionEvaluators further in.
121         ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader();
122         try
123         {
124             Thread.currentThread().setContextClassLoader(expressionEvaluationClassLoader);
125             result = muleContext.getExpressionManager().evaluate(expr, message, false);
126         }
127         finally
128         {
129             // Restore original context class-loader
130             Thread.currentThread().setContextClassLoader(originalContextClassLoader);
131         }
132 
133         if (result == null)
134         {
135             return nullReturnsTrue;
136         }
137         else if (result instanceof Boolean)
138         {
139             return (Boolean) result;
140         }
141         else if (result instanceof String)
142         {
143             if(result.toString().toLowerCase().equalsIgnoreCase("false"))
144             {
145                 return false;
146             }
147             else if(result.toString().toLowerCase().equalsIgnoreCase("true"))
148             {
149                 return true;
150             }
151             else
152             {
153                 return !nullReturnsTrue;
154             }
155         }
156         else
157         {
158             logger.warn("Expression: " + expr + ", returned an non-boolean result. Returning: "
159                         + !nullReturnsTrue);
160             return !nullReturnsTrue;
161         }
162     }
163 
164     protected String getFullExpression()
165     {
166         if(fullExpression==null)
167         {
168             //Handle non-expression filters
169             if(config.getEvaluator().equals("header"))
170             {
171                 delegateFilter = new MessagePropertyFilter(config.getExpression());
172             }
173             else if(config.getEvaluator().equals("regex"))
174             {
175                 delegateFilter = new RegExFilter(config.getExpression());
176             }
177             else if(config.getEvaluator().equals("wildcard"))
178             {
179                 delegateFilter = new WildcardFilter(config.getExpression());
180             }
181             else if(config.getEvaluator().equals("payload-type"))
182             {
183                 try
184                 {
185                     delegateFilter = new PayloadTypeFilter(config.getExpression());
186                 }
187                 catch (ClassNotFoundException e)
188                 {
189                     IllegalArgumentException iae = new IllegalArgumentException();
190                     iae.initCause(e);
191                     throw iae;
192                 }
193             }
194             else if(config.getEvaluator().equals("exception-type"))
195             {
196                 try
197                 {
198                     delegateFilter = new ExceptionTypeFilter(config.getExpression());
199                 }
200                 catch (ClassNotFoundException e)
201                 {
202                     IllegalArgumentException iae = new IllegalArgumentException();
203                     iae.initCause(e);
204                     throw iae;
205                 }
206             }
207             else
208             {
209                 //In the case of 'payload' the expression can be null
210                 fullExpression = config.getFullExpression(muleContext.getExpressionManager());
211             }
212         }
213         return fullExpression;
214     }
215 
216     public String getCustomEvaluator()
217     {
218         return config.getCustomEvaluator();
219     }
220 
221     public void setCustomEvaluator(String customEvaluator)
222     {
223         this.config.setCustomEvaluator(customEvaluator);
224         fullExpression=null;        
225     }
226 
227     public String getEvaluator()
228     {
229         return config.getEvaluator();
230     }
231 
232     public void setEvaluator(String evaluator)
233     {
234         this.config.setEvaluator(evaluator);
235         fullExpression=null;
236     }
237 
238     public String getExpression()
239     {
240         return config.getExpression();
241     }
242 
243     public void setExpression(String expression)
244     {
245         this.config.setExpression(expression);
246         fullExpression=null;
247     }
248 
249     public boolean isNullReturnsTrue()
250     {
251         return nullReturnsTrue;
252     }
253 
254     public void setNullReturnsTrue(boolean nullReturnsTrue)
255     {
256         this.nullReturnsTrue = nullReturnsTrue;
257     }
258 
259     @Override
260     public boolean equals(Object obj)
261     {
262         if (this == obj) return true;
263         if (obj == null || getClass() != obj.getClass()) return false;
264 
265         final ExpressionFilter other = (ExpressionFilter) obj;
266         return equal(config, other.config)
267             && equal(delegateFilter, other.delegateFilter)
268             && nullReturnsTrue == other.nullReturnsTrue;
269     }
270 
271     @Override
272     public int hashCode()
273     {
274         return hash(new Object[]{this.getClass(), config, delegateFilter, nullReturnsTrue});
275     }
276 }