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