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.sxc;
8   
9   import org.mule.api.DefaultMuleException;
10  import org.mule.api.MuleContext;
11  import org.mule.api.MuleException;
12  import org.mule.api.MuleMessage;
13  import org.mule.api.expression.ExpressionRuntimeException;
14  import org.mule.api.registry.RegistrationException;
15  import org.mule.api.routing.filter.Filter;
16  import org.mule.api.transformer.TransformerException;
17  import org.mule.config.i18n.CoreMessages;
18  import org.mule.module.xml.stax.ReversibleXMLStreamReader;
19  import org.mule.module.xml.transformer.XmlToXMLStreamReader;
20  import org.mule.module.xml.util.NamespaceManager;
21  import org.mule.routing.filters.logic.AndFilter;
22  import org.mule.routing.filters.logic.NotFilter;
23  import org.mule.routing.filters.logic.OrFilter;
24  import org.mule.routing.outbound.FilteringOutboundRouter;
25  
26  import com.envoisolutions.sxc.xpath.XPathBuilder;
27  import com.envoisolutions.sxc.xpath.XPathEvaluator;
28  
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.Map;
32  
33  /**
34   * <code>FilteringRouter</code> is a router that accepts events based on a filter
35   * set.
36   */
37  
38  public class SxcFilteringOutboundRouter extends FilteringOutboundRouter
39  {
40      private final static ThreadLocal<MuleMessage> messages = new ThreadLocal<MuleMessage>();
41      private final static XmlToXMLStreamReader transformer = new XmlToXMLStreamReader();
42  
43      static
44      {
45          transformer.setReversible(true);
46      }
47  
48      private Map<String, String> namespaces;
49      private XPathEvaluator evaluator;
50  
51      private XPathBuilder builder;
52  
53      private NamespaceManager namespaceManager;
54  
55      @Override
56      public void setMuleContext(MuleContext context)
57      {
58          this.muleContext = context;
59          try
60          {
61              namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
62          }
63          catch (RegistrationException e)
64          {
65              throw new ExpressionRuntimeException(CoreMessages.failedToLoad("NamespaceManager"), e);
66          }
67          
68          if (namespaceManager != null)
69          {
70              if (namespaces == null)
71              {
72                  namespaces = new HashMap(namespaceManager.getNamespaces());
73              }
74              else
75              {
76                  namespaces.putAll(namespaceManager.getNamespaces());
77              }
78          }
79      }
80  
81      @Override
82      public void setFilter(Filter filter)
83      {
84          super.setFilter(filter);
85      }
86  
87      protected void addEventHandlers(XPathBuilder builder, Filter filter)
88      {
89          if (filter instanceof SxcFilter)
90          {
91              SxcFilter sxcFilter = ((SxcFilter) filter);
92              sxcFilter.addEventHandler(this, builder);
93          }
94          else if (filter instanceof AndFilter)
95          {
96              AndFilter f = (AndFilter) filter;
97  
98              for (Iterator<?> itr = f.getFilters().iterator(); itr.hasNext();)
99              {
100                 addEventHandlers(builder, (Filter) itr.next());
101             }
102         }
103         else if (filter instanceof OrFilter)
104         {
105             OrFilter f = (OrFilter) filter;
106 
107             for (Iterator<?> itr = f.getFilters().iterator(); itr.hasNext();)
108             {
109                 addEventHandlers(builder, (Filter) itr.next());
110             }
111         }
112         else if (filter instanceof NotFilter)
113         {
114             NotFilter f = (NotFilter) filter;
115 
116             addEventHandlers(builder, f.getFilter());
117         }
118         else
119         {
120             logger.warn("Filter type " + filter.getClass().toString()
121                            + " is not recognized by the SXC router. If it contains child "
122                            + "SXC filters it will not work correctly.");
123         }
124     }
125 
126     protected void initialize() throws Exception
127     {
128         if (evaluator == null)
129         {
130             doInitialize();
131         }
132     }
133 
134     private synchronized void doInitialize()
135     {
136         if (evaluator == null)
137         {
138             builder = new XPathBuilder();
139             builder.setNamespaceContext(namespaces);
140             addEventHandlers(builder, getFilter());
141 
142             evaluator = builder.compile();
143         }
144     }
145 
146     @Override
147     public boolean isMatch(MuleMessage message) throws MuleException
148     {
149         ReversibleXMLStreamReader reader = null;
150         try
151         {
152             initialize();
153             messages.set(message);
154 
155             reader = getXMLStreamReader(message);
156             reader.setTracking(true);
157             evaluator.evaluate(reader);
158         }
159         catch (StopProcessingException e)
160         {
161             // stop processing
162         }
163         catch (Exception e)
164         {
165             throw new DefaultMuleException(e);
166         }
167         finally
168         {
169             messages.set(null);
170 
171             if (reader != null)
172             {
173                 reader.setTracking(false);
174                 reader.reset();
175             }
176         }
177 
178         try
179         {
180             return testMatch(message);
181         }
182         catch (UndefinedMatchException m)
183         {
184             return false;
185         }
186     }
187 
188     public boolean testMatch(MuleMessage message) throws MuleException
189     {
190         return super.isMatch(message);
191     }
192 
193     /**
194      * Gets an XMLStreamReader for this message.
195      * 
196      * @param message
197      * @throws TransformerException
198      */
199     protected ReversibleXMLStreamReader getXMLStreamReader(MuleMessage message) throws TransformerException
200     {
201          ReversibleXMLStreamReader r = (ReversibleXMLStreamReader) transformer.transform(message);
202          
203          if (r != message.getPayload())
204          {
205              message.setPayload(r);
206          }
207          return r;
208     }
209 
210     public Map<String, String> getNamespaces()
211     {
212         return namespaces;
213     }
214 
215     public void setNamespaces(Map<String, String> namespaces)
216     {
217         this.namespaces = namespaces;
218     }
219 
220     public static MuleMessage getCurrentMessage()
221     {
222         return messages.get();
223     }
224 }