View Javadoc

1   /*
2    * $Id: AbstractMatchingRouter.java 22573 2011-07-29 23:52:45Z julien.eluard $
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.routing;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.OptimizedRequestContext;
15  import org.mule.api.AnnotatedObject;
16  import org.mule.api.MessagingException;
17  import org.mule.api.MuleEvent;
18  import org.mule.api.MuleException;
19  import org.mule.api.MuleMessage;
20  import org.mule.api.MuleSession;
21  import org.mule.api.lifecycle.Disposable;
22  import org.mule.api.lifecycle.Initialisable;
23  import org.mule.api.lifecycle.InitialisationException;
24  import org.mule.api.processor.MessageProcessor;
25  import org.mule.api.routing.MatchableMessageProcessor;
26  import org.mule.api.routing.MatchingRouter;
27  import org.mule.api.routing.TransformingMatchable;
28  import org.mule.config.i18n.CoreMessages;
29  
30  import java.util.Collections;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.concurrent.ConcurrentHashMap;
35  import java.util.concurrent.CopyOnWriteArrayList;
36  
37  import javax.xml.namespace.QName;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  
42  /**
43   * <code>AbstractRouterCollection</code> provides common method implementations of router collections for in
44   * and outbound routers.
45   */
46  
47  public class AbstractMatchingRouter implements MatchingRouter, AnnotatedObject
48  {
49      /**
50       * logger used by this class
51       */
52      protected final transient Log logger = LogFactory.getLog(getClass());
53  
54      @SuppressWarnings("unchecked")
55      protected List<MatchableMessageProcessor> matchableRoutes = new CopyOnWriteArrayList();
56      protected boolean matchAll = false;
57      protected MessageProcessor defaultRoute;
58      private final Map<QName, Object> annotations = new ConcurrentHashMap<QName, Object>();
59  
60      public MuleEvent process(MuleEvent event) throws MuleException
61      {
62          MuleMessage message = event.getMessage();
63          MuleSession session = event.getSession();
64          MuleEvent result;
65          boolean matchfound = false;
66  
67          for (Iterator iterator = matchableRoutes.iterator(); iterator.hasNext();)
68          {
69              MatchableMessageProcessor outboundRouter = (MatchableMessageProcessor) iterator.next();
70  
71              final MuleEvent eventToRoute;
72  
73              boolean copyEvent = false;
74              // Create copy of message for router 1..n-1 if matchAll="true" or if
75              // routers require copy because it may mutate payload before match is
76              // chosen
77              if (iterator.hasNext())
78              {
79                  if (isMatchAll())
80                  {
81                      copyEvent = true;
82                  }
83                  else if (outboundRouter instanceof TransformingMatchable)
84                  {
85                      copyEvent = ((TransformingMatchable) outboundRouter).isTransformBeforeMatch();
86                  }
87              }
88  
89              if (copyEvent)
90              {
91                  if (((DefaultMuleMessage) message).isConsumable())
92                  {
93                      throw new MessagingException(CoreMessages.cannotCopyStreamPayload(message.getPayload().getClass().getName()), event);
94                  }
95                  eventToRoute = OptimizedRequestContext.criticalSetEvent(event);
96              }
97              else
98              {
99                  eventToRoute = event;
100             }
101 
102             if (outboundRouter.isMatch(eventToRoute.getMessage()))
103             {
104                 matchfound = true;
105                 result = outboundRouter.process(event);
106                 if (!isMatchAll())
107                 {
108                     return result;
109                 }
110             }
111         }
112 
113         if (!matchfound && defaultRoute != null)
114         {
115             if (logger.isDebugEnabled())
116             {
117                 logger.debug("Message did not match any routers on: " + session.getFlowConstruct().getName()
118                              + " invoking catch all strategy");
119             }
120             return processDefaultRoute(event);
121         }
122         else if (!matchfound)
123         {
124             logger.warn("Message did not match any routers on: "
125                         + session.getFlowConstruct().getName()
126                         + " and there is no catch all strategy configured on this router.  Disposing message "
127                         + message);
128         }
129         return event;
130     }
131     
132     protected MuleEvent processDefaultRoute(MuleEvent event) throws MuleException
133     {
134         return defaultRoute.process(event);
135     }
136 
137     public boolean isMatchAll()
138     {
139         return matchAll;
140     }
141 
142     public void setMatchAll(boolean matchAll)
143     {
144         this.matchAll = matchAll;
145     }
146 
147     public void addRoute(MatchableMessageProcessor matchable)
148     {
149         matchableRoutes.add(matchable);
150     }
151 
152     public void removeRoute(MatchableMessageProcessor matchable)
153     {
154         matchableRoutes.remove(matchable);
155     }
156 
157     public void setDefaultRoute(MessageProcessor defaultRoute)
158     {
159         this.defaultRoute = defaultRoute;
160     }
161 
162     public List<MatchableMessageProcessor> getRoutes()
163     {
164         return matchableRoutes;
165     }
166 
167     public MessageProcessor getDefaultRoute()
168     {
169         return defaultRoute;
170     }
171 
172     public void initialise() throws InitialisationException
173     {
174         for (MatchableMessageProcessor route : matchableRoutes)
175         {
176             if (route instanceof Initialisable)
177             {
178                 ((Initialisable) route).initialise();
179             }
180         }
181     }
182 
183     public void dispose()
184     {
185         for (MatchableMessageProcessor route : matchableRoutes)
186         {
187             if (route instanceof Disposable)
188             {
189                 ((Disposable) route).dispose();
190             }
191         }
192     }
193 
194     public final Object getAnnotation(QName name)
195     {
196         return annotations.get(name);
197     }
198 
199     public final Map<QName, Object> getAnnotations()
200     {
201         return Collections.unmodifiableMap(annotations);
202     }
203 
204     public synchronized final void setAnnotations(Map<QName, Object> newAnnotations)
205     {
206         annotations.clear();
207         annotations.putAll(newAnnotations);
208     }
209 }