View Javadoc

1   /*
2    * $Id: DynamicOutboundEndpoint.java 173 2009-11-07 19:41:52Z ross $
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 
121             setEndpointURI(uri);
122 
123             getEndpointURI().initialise();
124             return getEndpointURI();
125         }
126         catch (final Exception e)
127         {
128             throw new DispatchException(CoreMessages.templateCausedMalformedEndpoint(uriTemplate,
129                 newUriString), event, this, e);
130         }
131 
132     }
133 
134     protected String parseURIString(String uri, MuleMessage message)
135     {
136         return this.getMuleContext().getExpressionManager().parse(uri, message, true);
137     }
138 
139     @Override
140     public MuleEvent process(MuleEvent event) throws MuleException
141     {
142         final EndpointURI uri = getEndpointURIForMessage(event);
143         if (endpoint instanceof NullOutboundEndpoint)
144         {
145             builder.setURIBuilder(new URIBuilder(uri));
146             endpoint = builder.buildOutboundEndpoint();
147         }
148         final OutboundEndpoint outboundEndpoint = new DynamicURIOutboundEndpoint(endpoint, uri);
149 
150         return outboundEndpoint.process(event);
151     }
152 
153     @Override
154     public boolean equals(Object o)
155     {
156         return this == o;
157     }
158 
159     @Override
160     public int hashCode()
161     {
162         return System.identityHashCode(this);
163     }
164 
165     protected static class NullOutboundEndpoint extends AbstractEndpoint implements OutboundEndpoint
166     {
167         private static final long serialVersionUID = 7927987219248986540L;
168 
169         NullOutboundEndpoint(MuleContext muleContext, EndpointBuilder builder)
170         {
171             super(createDynamicConnector(muleContext), null, null, Collections.emptyMap(), null, true,
172                 getMessageExchangePattern(builder), 0, "started", null, null, muleContext, null, null, null,
173                 null, true, null);
174         }
175 
176         @Override
177         protected MessageProcessor createMessageProcessorChain(FlowConstruct flowConstruct)
178             throws MuleException
179         {
180             throw new UnsupportedOperationException("createMessageProcessorChain");
181         }
182 
183         public List<String> getResponseProperties()
184         {
185             return Collections.emptyList();
186         }
187 
188         public MuleEvent process(MuleEvent event) throws MuleException
189         {
190             throw new UnsupportedOperationException("process");
191         }
192 
193         static Connector createDynamicConnector(MuleContext muleContext)
194         {
195             try
196             {
197                 return new TransportFactory(muleContext).createConnector(DYNAMIC_URI_PLACEHOLDER);
198             }
199             catch (final TransportFactoryException e)
200             {
201                 // This should never happen
202                 throw new MuleRuntimeException(e);
203             }
204         }
205 
206         static MessageExchangePattern getMessageExchangePattern(EndpointBuilder builder)
207         {
208             if (!(builder instanceof AbstractEndpointBuilder))
209             {
210                 return MessageExchangePattern.ONE_WAY;
211             }
212 
213             return ((AbstractEndpointBuilder) builder).messageExchangePattern;
214         }
215     }
216 
217 }