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