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.api.MuleContext;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleException;
12  import org.mule.api.MuleMessage;
13  import org.mule.api.annotations.param.Payload;
14  import org.mule.api.endpoint.EndpointBuilder;
15  import org.mule.api.endpoint.EndpointURI;
16  import org.mule.api.endpoint.MalformedEndpointException;
17  import org.mule.api.transport.PropertyScope;
18  import org.mule.config.endpoint.AnnotatedEndpointData;
19  import org.mule.endpoint.MuleEndpointURI;
20  import org.mule.transport.AbstractConnector;
21  import org.mule.transport.service.TransportFactory;
22  import org.mule.util.BeanUtils;
23  import org.mule.util.TemplateParser;
24  import org.mule.util.UriParamFilter;
25  
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.ibeans.annotation.Call;
32  import org.ibeans.annotation.param.HeaderParam;
33  import org.ibeans.api.channel.CHANNEL;
34  
35  /**
36   * <p>
37   * A dynamic outbound endpoint defined when using the {@link Call} annotation. A
38   * CallOutboundEndpoint is generated when the call method has a one or more payloads
39   * defined using {@link Payload} annotation or one or more headers defined using the
40   * {@link HeaderParam} annotation. annotations.
41   * <p/>
42   * <p>
43   * The endpoint scheme is the only part of the URI that cannot be replaced at
44   * runtime.
45   * </p>
46   *
47   * @see CallRequestEndpoint
48   */
49  public class CallOutboundEndpoint extends org.mule.endpoint.DynamicOutboundEndpoint
50  {
51      public static final String NULL_PARAM = "null.param";
52  
53      /**
54       * logger used by this class
55       */
56      protected transient final Log logger = LogFactory.getLog(CallOutboundEndpoint.class);
57  
58      private static final long serialVersionUID = 1861985949279708638L;
59  
60      //The parser used to parse the @Call uri template
61      protected TemplateParser parser = TemplateParser.createCurlyBracesStyleParser();
62  
63      private UriParamFilter filter = new UriParamFilter();
64  
65      public CallOutboundEndpoint(MuleContext context, AnnotatedEndpointData epData) throws MalformedEndpointException
66      {
67          super(createBuilder(context, epData), epData.getAddress());
68      }
69  
70      private synchronized static EndpointBuilder createBuilder(MuleContext context, AnnotatedEndpointData epData)
71      {
72          try
73          {
74              String address = epData.getAddress();
75              int i = address.indexOf(":/");
76              String scheme;
77              if (i > -1)
78              {
79                  scheme = address.substring(0, i);
80                  address = scheme + "://dynamic";
81                  //This is used for creating the connector, since we don't know if the actual URI address is a vaild URI.
82                  EndpointURI tempUri = new MuleEndpointURI(address, context);
83                  AbstractConnector cnn = null;
84  
85                  if (epData.getConnectorName() != null)
86                  {
87                      cnn = (AbstractConnector) context.getRegistry().lookupConnector(epData.getConnectorName());
88                  }
89                  if (cnn == null)
90                  {
91                      cnn = (AbstractConnector) new TransportFactory(context).createConnector(tempUri);
92                      if (epData.getConnectorName() != null)
93                      {
94                          cnn.setName(epData.getConnectorName());
95                      }
96                      context.getRegistry().registerConnector(cnn);
97                  }
98  
99                  //This allows connector properties to be set as properties on the endpoint
100                 Map props = epData.getProperties();
101                 if (props == null)
102                 {
103                     props = new HashMap();
104                 }
105                 else
106                 {
107                     BeanUtils.populateWithoutFail(cnn, props, false);
108                 }
109                 EndpointBuilder builder = context.getEndpointFactory().getEndpointBuilder(address);
110                 builder.setConnector(cnn);
111                 builder.setName(epData.getName());
112                 builder.setProperties(props);
113 
114                 return builder;
115 
116 
117             }
118             else
119             {
120                 throw new IllegalArgumentException("When defining a dynamic endpoint the endpoint scheme must be set i.e. http://{dynamic}");
121             }
122         }
123         catch (Exception e)
124         {
125             throw new RuntimeException(e);
126         }
127     }
128 
129     @Override
130     protected void validateUriTemplate(String uri) throws MalformedEndpointException
131     {
132         //TODO
133     }
134 
135     @Override
136     protected String parseURIString(String uri, MuleMessage message)
137     {
138         //We do additional processing here to parse the URI template
139         Map<String, Object> props = getPropertiesForUriTemplate(message);
140 
141         String newUriString = parser.parse(props, uri);
142         //Remove optional params completely if null
143         newUriString = filter.filterParamsByValue(newUriString, NULL_PARAM);
144 
145         return super.parseURIString(newUriString, message);
146     }
147 
148     protected Map<String, Object> getPropertiesForUriTemplate(MuleMessage message)
149     {
150         Map<String, Object> props = (Map) message.getOutboundProperty(CHANNEL.URI_PARAM_PROPERTIES);
151         if (props == null)
152         {
153             throw new IllegalStateException(CHANNEL.URI_PARAM_PROPERTIES + " not set on message");
154         }
155         return props;
156     }
157 
158     @Override
159     public MuleEvent process(MuleEvent event) throws MuleException
160     {
161         MuleEvent result = super.process(event);
162         if (result != null)
163         {
164             result.getMessage().setProperty(CHANNEL.CALL_URI_PROPERTY, result.getEndpoint().getEndpointURI().toString(), PropertyScope.OUTBOUND);
165         }
166         return result;
167     }
168 }