View Javadoc

1   /*
2    * $Id: EndpointSelector.java 22023 2011-05-30 07:26:22Z 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.routing.outbound;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.endpoint.EndpointNotFoundException;
17  import org.mule.api.endpoint.ImmutableEndpoint;
18  import org.mule.api.endpoint.MalformedEndpointException;
19  import org.mule.api.expression.ExpressionRuntimeException;
20  import org.mule.api.processor.MessageProcessor;
21  import org.mule.api.routing.CouldNotRouteOutboundMessageException;
22  import org.mule.api.routing.RoutingException;
23  import org.mule.config.i18n.CoreMessages;
24  import org.mule.expression.ExpressionConfig;
25  import org.mule.util.StringUtils;
26  
27  import java.util.ArrayList;
28  import java.util.Iterator;
29  import java.util.List;
30  
31  /**
32   * <code>EndpointSelector</code> selects the outgoing endpoint based on a
33   * an expression evaluator  ("header:endpoint" by default).  It will first try to match the
34   * endpoint by name and then by address.
35   * The targets to use can be set on the router itself or be global endpoint definitions.
36   * <pre>
37   * <p/>
38   * &lt;outbound&gt;
39   *      &lt;endpoint-selector-router evaluator="xpath" expression="/MSG/HEADER/NEXT-ADDRESS"&gt;
40   *          &lt;endpoint name="dest1" address="jms://queue1" /&gt;
41   *          &lt;endpoint name="dest2" address="jms://queue2" /&gt;
42   *          &lt;endpoint name="dest3" address="jms://queue3" /&gt;
43   *      &lt;/endpoint-selector-router&gt;
44   * &lt;/outbound&gt;
45   * <p/>
46   * </pre>
47   */
48  public class EndpointSelector extends FilteringOutboundRouter
49  {
50      public static final String DEFAULT_SELECTOR_EVALUATOR = "header";
51      public static final String DEFAULT_SELECTOR_EXPRESSION = "endpoint";
52  
53      private String defaultEndpointName;
54  
55      private ExpressionConfig expressionConfig = new ExpressionConfig(DEFAULT_SELECTOR_EXPRESSION, DEFAULT_SELECTOR_EVALUATOR, null);
56  
57      @Override
58      public MuleEvent route(MuleEvent event) throws RoutingException
59      {
60          MuleMessage message = event.getMessage();
61  
62          List<Object> endpoints;
63          String endpointName;
64  
65          String prop = expressionConfig.getFullExpression(expressionManager);
66          if (!expressionManager.isValidExpression(prop))
67          {
68              throw new CouldNotRouteOutboundMessageException(
69                      CoreMessages.expressionInvalidForProperty("expression", prop), event, null);
70          }
71  
72          Object property = null;
73          try
74          {
75              property = expressionManager.evaluate(prop, message);
76          }
77          catch (ExpressionRuntimeException e)
78          {
79              logger.error(e.getMessage());
80          }
81  
82          if (property == null && getDefaultEndpointName() == null)
83          {
84              throw new CouldNotRouteOutboundMessageException(
85                      CoreMessages.expressionResultWasNull(
86                          expressionConfig.getFullExpression(expressionManager)), event, null);
87          }
88          else if (property == null)
89          {
90              logger.info("Expression: " + prop + " returned null, using default endpoint: " + getDefaultEndpointName());
91              property = getDefaultEndpointName();
92          }
93  
94          if (property instanceof String)
95          {
96              endpoints = new ArrayList<Object>(1);
97              endpoints.add(property);
98          }
99          else if (property instanceof List)
100         {
101             endpoints = (List<Object>) property;
102         }
103         else
104         {
105             throw new CouldNotRouteOutboundMessageException(CoreMessages.propertyIsNotSupportedType(
106                     expressionConfig.getFullExpression(expressionManager),
107                     new Class[]{String.class, List.class}, property.getClass()), event, null);
108         }
109 
110         List<MuleEvent> results = new ArrayList<MuleEvent>(endpoints.size());
111 
112         for (Iterator<Object> iterator = endpoints.iterator(); iterator.hasNext();)
113         {
114             endpointName = iterator.next().toString();
115 
116             if (StringUtils.isEmpty(endpointName))
117             {
118                 throw new CouldNotRouteOutboundMessageException(
119                         CoreMessages.objectIsNull("Endpoint Name: " + expressionConfig.getFullExpression(expressionManager)), event, null);
120             }
121             MessageProcessor ep = null;
122             try
123             {
124                 ep = lookupEndpoint(endpointName);
125                 if (ep == null)
126                 {
127                     throw new CouldNotRouteOutboundMessageException(CoreMessages.objectNotFound("Endpoint",
128                             endpointName), event, null);
129                 }
130                 MuleEvent result = sendRequest(event, message, ep, true);
131                 if (result != null)
132                 {
133                     results.add(result);
134                 }
135             }
136             catch (MuleException e)
137             {
138                 throw new CouldNotRouteOutboundMessageException(event, ep, e);
139             }
140         }
141         return resultsHandler.aggregateResults(results, event, muleContext);
142     }
143 
144     protected MessageProcessor lookupEndpoint(String endpointName) throws MuleException
145     {
146         for (MessageProcessor target : routes)
147         {
148             if (target instanceof ImmutableEndpoint)
149             {
150                 ImmutableEndpoint ep = (ImmutableEndpoint) target;
151                 // Endpoint identifier (deprecated)
152                 if (endpointName.equals(ep.getName()))
153                 {
154                     return target;
155                 }
156                 // Global endpoint
157                 else if (endpointName.equals(ep.getName()))
158                 {
159                     return target;
160                 }
161                 else if (endpointName.equals(ep.getEndpointURI().getUri().toString()))
162                     {
163                         return target;
164                     }
165             }
166         }
167         try
168         {
169             return getMuleContext().getEndpointFactory().getOutboundEndpoint(endpointName);
170         }
171         catch (MalformedEndpointException e)
172         {
173             throw new EndpointNotFoundException(CoreMessages.endpointNotFound(endpointName), e);
174         }
175     }
176 
177     public String getExpression()
178     {
179         return expressionConfig.getExpression();
180     }
181 
182     public void setExpression(String expression)
183     {
184         expressionConfig.setExpression(expression);
185     }
186 
187     public String getCustomEvaluator()
188     {
189         return expressionConfig.getCustomEvaluator();
190     }
191 
192     public void setCustomEvaluator(String customEvaluator)
193     {
194         expressionConfig.setCustomEvaluator(customEvaluator);
195     }
196 
197     public String getEvaluator()
198     {
199         return expressionConfig.getEvaluator();
200     }
201 
202     public void setEvaluator(String evaluator)
203     {
204         expressionConfig.setEvaluator(evaluator);
205     }
206 
207     public String getDefaultEndpointName()
208     {
209         return defaultEndpointName;
210     }
211 
212     public void setDefaultEndpointName(String defaultEndpointName)
213     {
214         this.defaultEndpointName = defaultEndpointName;
215     }
216 }