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