View Javadoc

1   /*
2    * $Id: DynamicRequestEndpoint.java 19726 2010-09-25 02:17:05Z rossmason $
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  package org.mule.module.ibeans.spi.support;
11  
12  import org.mule.DefaultMuleMessage;
13  import org.mule.MessageExchangePattern;
14  import org.mule.api.MessagingException;
15  import org.mule.api.MuleContext;
16  import org.mule.api.MuleEvent;
17  import org.mule.api.MuleException;
18  import org.mule.api.MuleMessage;
19  import org.mule.api.MuleRuntimeException;
20  import org.mule.api.config.MuleProperties;
21  import org.mule.api.construct.FlowConstruct;
22  import org.mule.api.endpoint.EndpointBuilder;
23  import org.mule.api.endpoint.EndpointURI;
24  import org.mule.api.endpoint.InboundEndpoint;
25  import org.mule.api.endpoint.MalformedEndpointException;
26  import org.mule.api.expression.ExpressionManager;
27  import org.mule.api.processor.MessageProcessor;
28  import org.mule.api.transport.Connector;
29  import org.mule.config.i18n.CoreMessages;
30  import org.mule.endpoint.DefaultInboundEndpoint;
31  import org.mule.endpoint.DynamicOutboundEndpoint;
32  import org.mule.endpoint.DynamicURIInboundEndpoint;
33  import org.mule.endpoint.MuleEndpointURI;
34  import org.mule.endpoint.URIBuilder;
35  import org.mule.transport.service.TransportFactory;
36  import org.mule.transport.service.TransportFactoryException;
37  import org.mule.util.TemplateParser;
38  
39  import java.util.Collections;
40  import java.util.HashMap;
41  import java.util.List;
42  import java.util.Map;
43  
44  import org.apache.commons.logging.Log;
45  import org.apache.commons.logging.LogFactory;
46  
47  /**
48   * A dynamic request endpoint is used in conjunction with the {@link org.ibeans.annotation.Call} annotation when there are no {@link org.ibeans.annotation.param.Body},
49   * {@link org.ibeans.annotation.param.BodyParam} or {@link org.ibeans.annotation.param.HeaderParam} annotations
50   * on a method and allows a dynamic {@link org.mule.api.endpoint.InboundEndpoint} to be created.  This endpoint is then used via the Mule {@link org.mule.api.transport.MessageRequester}
51   * interface to make a specific request to a transport for a message.
52   */
53  public class DynamicRequestEndpoint extends DynamicURIInboundEndpoint
54  {
55      public static final String EVAL_PARAM_PROPERTY = "eval.param";
56      /**
57       * logger used by this class
58       */
59      protected transient final Log logger = LogFactory.getLog(DynamicRequestEndpoint.class);
60      private static final long serialVersionUID = 8861985949279708638L;
61  
62      protected TemplateParser parser = TemplateParser.createCurlyBracesStyleParser();
63  
64      /**
65       * The URI template used to construct the actual URI to send the message to.
66       */
67      protected String uriTemplate;
68  
69      private EndpointBuilder builder;
70  
71     public DynamicRequestEndpoint(MuleContext muleContext, EndpointBuilder builder, String uriTemplate) throws MalformedEndpointException
72      {
73          super(new NullInboundEndpoint(muleContext));
74          this.builder = builder;
75          this.uriTemplate = uriTemplate;
76          validateUriTemplate(uriTemplate);
77      }
78  
79      protected void validateUriTemplate(String uri) throws MalformedEndpointException
80      {
81          if (uri.indexOf(":") > uri.indexOf(ExpressionManager.DEFAULT_EXPRESSION_PREFIX))
82          {
83              throw new MalformedEndpointException(CoreMessages.dynamicEndpointsMustSpecifyAScheme(), uri);
84          }
85      }
86  
87      protected Map<String, Object> getPropertiesForTemplate(MuleMessage message)
88      {
89          Map<String, Object> props = new HashMap<String, Object>();
90          // Also add the endpoint properties so that users can set fallback values
91          // when the property is not set on the event
92          props.putAll(this.getProperties());
93          for (String propertyKey : message.getOutboundPropertyNames())
94          {
95              props.put(propertyKey, message.getOutboundProperty(propertyKey));
96          }
97          return props;
98      }
99  
100     protected EndpointURI getEndpointURIForMessage(MuleEvent event) throws MessagingException
101     {
102         if (logger.isDebugEnabled())
103         {
104             logger.debug("Uri before parsing is: " + uriTemplate);
105         }
106 
107         Map<String, Object> props = getPropertiesForTemplate(event.getMessage());
108 
109         String newUriString = parser.parse(props, uriTemplate);
110         Object evalParam = props.get(EVAL_PARAM_PROPERTY);
111         if (evalParam != null)
112         {
113             newUriString = parseURIString(newUriString, new DefaultMuleMessage(evalParam, getMuleContext()));
114         }
115         else
116         {
117             newUriString = parseURIString(newUriString, event.getMessage());
118         }
119         if (logger.isDebugEnabled())
120         {
121             logger.debug("Uri after parsing is: " + newUriString);
122         }
123 
124         try
125         {
126             setEndpointURI(new MuleEndpointURI(newUriString, getMuleContext()));
127 
128             if (!newUriString.startsWith(getEndpointURI().getFullScheme()))
129             {
130                 throw new MessagingException(CoreMessages.schemeCannotChangeForRouter(
131                         this.getEndpointURI().getScheme(), getEndpointURI().getScheme()), event);
132             }
133             getEndpointURI().initialise();
134             return getEndpointURI();
135         }
136         catch (Exception e)
137         {
138             throw new MessagingException(
139                     CoreMessages.templateCausedMalformedEndpoint(uriTemplate, newUriString),
140                     event, e);
141         }
142 
143     }
144 
145     protected String parseURIString(String uri, MuleMessage message)
146     {
147         return this.getMuleContext().getExpressionManager().parse(uri, message, true);
148     }
149 
150     public MuleMessage request(long timeout, MuleEvent event) throws Exception
151     {
152         EndpointURI uri = getEndpointURIForMessage(event);
153 
154         if (endpoint instanceof NullInboundEndpoint)
155         {
156             builder.setURIBuilder(new URIBuilder(uri));
157             endpoint = builder.buildInboundEndpoint();
158         }
159         InboundEndpoint inboundEndpoint = new DynamicURIInboundEndpoint(endpoint, uri);
160 
161         if (event.getMessage().getInvocationProperty(MuleProperties.MULE_CREDENTIALS_PROPERTY) != null)
162         {
163             inboundEndpoint.getProperties().put(MuleProperties.MULE_CREDENTIALS_PROPERTY, event.getMessage().getInvocationProperty(MuleProperties.MULE_CREDENTIALS_PROPERTY));
164         }
165         return super.request(timeout);
166     }
167 
168     @Override
169     public boolean equals(Object o)
170     {
171         if (this == o)
172         {
173             return true;
174         }
175         if (o == null || getClass() != o.getClass())
176         {
177             return false;
178         }
179         if (!super.equals(o))
180         {
181             return false;
182         }
183 
184         DynamicRequestEndpoint that = (DynamicRequestEndpoint) o;
185 
186         return !(uriTemplate != null ? !uriTemplate.equals(that.uriTemplate) : that.uriTemplate != null);
187 
188     }
189 
190     @Override
191     public int hashCode()
192     {
193         int result = 0;
194         result = 31 * result + (uriTemplate != null ? uriTemplate.hashCode() : 0);
195         return result;
196     }
197 
198     protected static class NullInboundEndpoint extends DefaultInboundEndpoint implements InboundEndpoint
199     {
200         NullInboundEndpoint(MuleContext muleContext)
201         {
202             super(createDynamicConnector(muleContext), null, null, new HashMap(), null, true, MessageExchangePattern.ONE_WAY, 0, "started", null, null, muleContext, null, null, null, null, true, null);
203         }
204 
205         @Override
206         public MessageProcessor createMessageProcessorChain(FlowConstruct flowContruct) throws MuleException
207         {
208             throw new UnsupportedOperationException("createMessageProcessorChain");
209         }
210 
211         public List<String> getResponseProperties()
212         {
213             return Collections.emptyList();
214         }
215 
216         @SuppressWarnings("unused")
217         public MuleEvent process(MuleEvent event) throws MuleException
218         {
219             throw new UnsupportedOperationException("process");
220         }
221 
222         static Connector createDynamicConnector(MuleContext muleContext)
223         {
224             try
225             {
226                 return new TransportFactory(muleContext).createConnector(DynamicOutboundEndpoint.DYNAMIC_URI_PLACEHOLDER);
227             }
228             catch (TransportFactoryException e)
229             {
230                 //This should never happen
231                 throw new MuleRuntimeException(e);
232             }
233         }
234     }
235 
236 
237 }