View Javadoc

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