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.DefaultMuleMessage;
10  import org.mule.api.DefaultMuleException;
11  import org.mule.api.MuleEvent;
12  import org.mule.api.MuleException;
13  import org.mule.api.MuleMessage;
14  import org.mule.api.endpoint.EndpointBuilder;
15  import org.mule.api.endpoint.EndpointURI;
16  import org.mule.api.endpoint.OutboundEndpoint;
17  import org.mule.api.processor.MessageRouter;
18  import org.mule.api.registry.RegistrationException;
19  import org.mule.api.routing.CouldNotRouteOutboundMessageException;
20  import org.mule.api.routing.RoutingException;
21  import org.mule.config.i18n.MessageFactory;
22  import org.mule.routing.CorrelationMode;
23  
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
29  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * <code>AbstractRecipientList</code> is used to dispatch a single event to
36   * multiple recipients over the same transport. The recipient targets can be
37   * configured statically or can be obtained from the message payload.
38   */
39  
40  public abstract class AbstractRecipientList extends FilteringOutboundRouter implements MessageRouter
41  {
42      /**
43       * logger used by this class
44       */
45      protected final Log logger = LogFactory.getLog(getClass());
46  
47      private final ConcurrentMap recipientCache = new ConcurrentHashMap();
48  
49      private Boolean synchronous;
50  
51      @Override
52      public MuleEvent route(MuleEvent event)
53          throws RoutingException
54      {
55          MuleMessage message = event.getMessage();
56  
57          List recipients = this.getRecipients(event);
58          List<MuleEvent> results = new ArrayList<MuleEvent>();
59  
60          if (enableCorrelation != CorrelationMode.NEVER)
61          {
62              boolean correlationSet = message.getCorrelationGroupSize() != -1;
63              if (correlationSet && (enableCorrelation == CorrelationMode.IF_NOT_SET))
64              {
65                  logger.debug("CorrelationId is already set, not setting Correlation group size");
66              }
67              else
68              {
69                  // the correlationId will be set by the AbstractOutboundRouter
70                  message.setCorrelationGroupSize(recipients.size());
71              }
72          }
73  
74          OutboundEndpoint endpoint = null;
75          MuleMessage request;
76  
77          for (Iterator iterator = recipients.iterator(); iterator.hasNext();)
78          {
79              Object recipient = iterator.next();
80              // Make a copy of the message. Question is do we do a proper clone? in
81              // which case there
82              // would potentially be multiple messages with the same id...
83              request = new DefaultMuleMessage(message.getPayload(), message, muleContext);
84              try
85              {
86                  endpoint = getRecipientEndpoint(request, recipient);
87  
88                  boolean sync =
89                      (this.synchronous == null ? endpoint.getExchangePattern().hasResponse() : this.synchronous.booleanValue());
90  
91                  if (sync)
92                  {
93                      results.add(sendRequest(event, request, endpoint, true));
94                  }
95                  else
96                  {
97                      sendRequest(event, request, endpoint, false);
98                  }
99              }
100             catch (MuleException e)
101             {
102                 throw new CouldNotRouteOutboundMessageException(event, endpoint, e);
103             }
104         }
105 
106         return resultsHandler.aggregateResults(results, event, muleContext);
107     }
108 
109     protected OutboundEndpoint getRecipientEndpoint(MuleMessage message, Object recipient) throws MuleException
110     {
111         OutboundEndpoint endpoint = null;
112         if (recipient instanceof OutboundEndpoint)
113         {
114             endpoint = (OutboundEndpoint) recipient;
115         }
116         else if (recipient instanceof EndpointURI)
117         {
118             endpoint = getRecipientEndpointFromUri((EndpointURI) recipient);
119         }
120         else if (recipient instanceof String)
121         {
122             endpoint = getRecipientEndpointFromString(message, (String) recipient);
123         }
124         if (null == endpoint)
125         {
126             throw new RegistrationException(MessageFactory.createStaticMessage("Failed to create endpoint for: " + recipient));
127         }
128 
129         OutboundEndpoint existingEndpoint = (OutboundEndpoint) recipientCache.putIfAbsent(recipient, endpoint);
130         if (existingEndpoint != null)
131         {
132             endpoint = existingEndpoint;
133         }
134         return endpoint;
135     }
136 
137     protected OutboundEndpoint getRecipientEndpointFromUri(EndpointURI uri)
138             throws MuleException
139     {
140         OutboundEndpoint endpoint = null;
141         if (null != getMuleContext() && null != getMuleContext().getRegistry())
142         {
143             endpoint = buildOutboundEndpoint(uri.getAddress());
144         }
145         if (null != endpoint)
146         {
147             muleContext.getRegistry().applyLifecycle(endpoint);
148         }
149         return endpoint;
150     }
151 
152     protected OutboundEndpoint getRecipientEndpointFromString(MuleMessage message, String recipient)
153             throws MuleException
154     {
155         OutboundEndpoint endpoint = (OutboundEndpoint) recipientCache.get(recipient);
156         if (null == endpoint && null != getMuleContext() && null != getMuleContext().getRegistry())
157         {
158             endpoint = buildOutboundEndpoint(recipient);
159         }
160         return endpoint;
161     }
162 
163     protected OutboundEndpoint buildOutboundEndpoint(String recipient) throws MuleException
164     {
165         EndpointBuilder endpointBuilder = getMuleContext().getEndpointFactory().getEndpointBuilder(recipient);
166 
167         try
168         {
169             endpointBuilder = (EndpointBuilder) endpointBuilder.clone();
170             endpointBuilder.setTransactionConfig(transactionConfig);
171         }
172         catch (CloneNotSupportedException e)
173         {
174             throw new DefaultMuleException(e);
175         }
176 
177         return endpointBuilder.buildOutboundEndpoint();
178     }
179 
180     public Boolean getSynchronous()
181     {
182         return synchronous;
183     }
184 
185     public void setSynchronous(Boolean synchronous)
186     {
187         this.synchronous = synchronous;
188     }
189 
190     @Override
191     public boolean isDynamicRoutes()
192     {
193         return true;
194     }
195 
196     protected abstract List getRecipients(MuleEvent event) throws CouldNotRouteOutboundMessageException;
197 
198 }