View Javadoc

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