View Javadoc

1   /*
2    * $Id: DynamicOutboundEndpoint.java 20465 2010-12-05 18:14:15Z mike.schilling $
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.endpoint;
12  
13  import java.util.Collections;
14  import java.util.List;
15  
16  import org.apache.commons.logging.Log;
17  import org.apache.commons.logging.LogFactory;
18  import org.mule.MessageExchangePattern;
19  import org.mule.api.MuleContext;
20  import org.mule.api.MuleEvent;
21  import org.mule.api.MuleException;
22  import org.mule.api.MuleMessage;
23  import org.mule.api.MuleRuntimeException;
24  import org.mule.api.construct.FlowConstruct;
25  import org.mule.api.endpoint.EndpointBuilder;
26  import org.mule.api.endpoint.EndpointURI;
27  import org.mule.api.endpoint.MalformedEndpointException;
28  import org.mule.api.endpoint.OutboundEndpoint;
29  import org.mule.api.expression.ExpressionManager;
30  import org.mule.api.expression.ExpressionRuntimeException;
31  import org.mule.api.processor.MessageProcessor;
32  import org.mule.api.transport.Connector;
33  import org.mule.api.transport.DispatchException;
34  import org.mule.config.i18n.CoreMessages;
35  import org.mule.transport.service.TransportFactory;
36  import org.mule.transport.service.TransportFactoryException;
37  
38  /**
39   * An Outbound endpoint who's URI will be constructed based on the current message.
40   * This allows for the destination of a message to change based on the contents of
41   * the message. Note that this endpoint ONLY substitutes the URI, but other config
42   * elements such as the connector (and scheme), transformers, filters, etc do not
43   * change. You cannot change an endpoint scheme dynamically so you can't switch
44   * between HTTP and JMS for example using the same dynamic endpoint.
45   */
46  public class DynamicOutboundEndpoint extends DynamicURIOutboundEndpoint
47  {
48      public static final String DYNAMIC_URI_PLACEHOLDER = "dynamic://endpoint";
49  
50      /**
51       * logger used by this class
52       */
53      protected transient final Log logger = LogFactory.getLog(DynamicOutboundEndpoint.class);
54  
55      private static final long serialVersionUID = 8861985949279708638L;
56  
57      /**
58       * The URI template used to construct the actual URI to send the message to.
59       */
60      protected String uriTemplate;
61  
62      private final EndpointBuilder builder;
63  
64      public DynamicOutboundEndpoint(MuleContext muleContext, EndpointBuilder builder, String uriTemplate)
65          throws MalformedEndpointException
66      {
67          super(new NullOutboundEndpoint(muleContext, builder));
68          this.builder = builder;
69          this.uriTemplate = uriTemplate;
70          validateUriTemplate(uriTemplate);
71      }
72  
73      @Override
74      public String getAddress()
75      {
76          final EndpointURI uri = getEndpointURI();
77          if (uri != null)
78          {
79              return uri.getUri().toString();
80          }
81          else
82          {
83              return uriTemplate;
84          }
85      }
86  
87      protected void validateUriTemplate(String uri) throws MalformedEndpointException
88      {
89          if (uri.indexOf(":") > uri.indexOf(ExpressionManager.DEFAULT_EXPRESSION_PREFIX))
90          {
91              throw new MalformedEndpointException(CoreMessages.dynamicEndpointsMustSpecifyAScheme(), uri);
92          }
93      }
94  
95      protected EndpointURI getEndpointURIForMessage(MuleEvent event) throws DispatchException
96      {
97          if (logger.isDebugEnabled())
98          {
99              logger.debug("Uri before parsing is: " + uriTemplate);
100         }
101 
102         String newUriString = uriTemplate;
103         try
104         {
105             newUriString = parseURIString(newUriString, event.getMessage());
106         }
107         catch (final ExpressionRuntimeException e)
108         {
109             throw new DispatchException(event, this, e);
110         }
111 
112         if (logger.isDebugEnabled())
113         {
114             logger.debug("Uri after parsing is: " + newUriString);
115         }
116 
117         try
118         {
119             final MuleEndpointURI uri = new MuleEndpointURI(newUriString, getMuleContext());
120             uri.initialise();
121             setEndpointURI(uri);
122             return getEndpointURI();
123         }
124         catch (final Exception e)
125         {
126             throw new DispatchException(CoreMessages.templateCausedMalformedEndpoint(uriTemplate,
127                 newUriString), event, this, e);
128         }
129 
130     }
131 
132     protected String parseURIString(String uri, MuleMessage message)
133     {
134         return this.getMuleContext().getExpressionManager().parse(uri, message, true);
135     }
136 
137     @Override
138     public MuleEvent process(MuleEvent event) throws MuleException
139     {
140         final EndpointURI uri = getEndpointURIForMessage(event);
141         if (endpoint instanceof NullOutboundEndpoint)
142         {
143             builder.setURIBuilder(new URIBuilder(uri));
144             endpoint = builder.buildOutboundEndpoint();
145         }
146         final OutboundEndpoint outboundEndpoint = new DynamicURIOutboundEndpoint(endpoint, uri);
147 
148         return outboundEndpoint.process(event);
149     }
150 
151     @Override
152     public boolean equals(Object o)
153     {
154         return this == o;
155     }
156 
157     @Override
158     public int hashCode()
159     {
160         return System.identityHashCode(this);
161     }
162 
163     protected static class NullOutboundEndpoint extends AbstractEndpoint implements OutboundEndpoint
164     {
165         private static final long serialVersionUID = 7927987219248986540L;
166 
167         NullOutboundEndpoint(MuleContext muleContext, EndpointBuilder builder)
168         {
169             super(createDynamicConnector(muleContext), null, null, Collections.emptyMap(), null, true,
170                 getMessageExchangePattern(builder), 0, "started", null, null, muleContext, null, null, null,
171                 null, true, null);
172         }
173 
174         @Override
175         protected MessageProcessor createMessageProcessorChain(FlowConstruct flowConstruct)
176             throws MuleException
177         {
178             throw new UnsupportedOperationException("createMessageProcessorChain");
179         }
180 
181         public List<String> getResponseProperties()
182         {
183             return Collections.emptyList();
184         }
185 
186         public MuleEvent process(MuleEvent event) throws MuleException
187         {
188             throw new UnsupportedOperationException("process");
189         }
190 
191         static Connector createDynamicConnector(MuleContext muleContext)
192         {
193             try
194             {
195                 return new TransportFactory(muleContext).createConnector(DYNAMIC_URI_PLACEHOLDER);
196             }
197             catch (final TransportFactoryException e)
198             {
199                 // This should never happen
200                 throw new MuleRuntimeException(e);
201             }
202         }
203 
204         static MessageExchangePattern getMessageExchangePattern(EndpointBuilder builder)
205         {
206             if (!(builder instanceof AbstractEndpointBuilder))
207             {
208                 return MessageExchangePattern.ONE_WAY;
209             }
210 
211             return ((AbstractEndpointBuilder) builder).messageExchangePattern;
212         }
213     }
214 
215 }