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.config;
8   
9   import org.mule.DefaultMuleEvent;
10  import org.mule.api.EndpointAnnotationParser;
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.MuleRuntimeException;
16  import org.mule.api.component.InterfaceBinding;
17  import org.mule.api.endpoint.ImmutableEndpoint;
18  import org.mule.api.endpoint.InboundEndpoint;
19  import org.mule.api.endpoint.OutboundEndpoint;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.module.ibeans.spi.MuleCallAnnotationHandler;
22  import org.mule.module.ibeans.spi.MuleIBeansPlugin;
23  import org.mule.module.ibeans.spi.support.DynamicRequestInterfaceBinding;
24  import org.mule.util.annotation.AnnotationMetaData;
25  import org.mule.util.annotation.AnnotationUtils;
26  
27  import java.lang.annotation.Annotation;
28  import java.lang.reflect.InvocationHandler;
29  import java.lang.reflect.Method;
30  import java.lang.reflect.Proxy;
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.ibeans.annotation.Call;
41  import org.ibeans.annotation.Template;
42  import org.ibeans.annotation.param.Body;
43  import org.ibeans.annotation.param.BodyParam;
44  import org.ibeans.annotation.param.HeaderParam;
45  import org.ibeans.api.IBeanInvoker;
46  import org.ibeans.api.IBeansException;
47  import org.ibeans.impl.IntegrationBeanInvocationHandler;
48  import org.ibeans.impl.InvokeAnnotationHandler;
49  import org.ibeans.impl.TemplateAnnotationHandler;
50  
51  /**
52   * TODO
53   */
54  public class IBeanBinding implements InterfaceBinding
55  {
56  
57      private static final Log logger = LogFactory.getLog(IBeanBinding.class);
58  
59      private Class interfaceClass;
60  
61      // The endpoint used to actually dispatch the message
62      protected OutboundEndpoint endpoint;
63  
64      protected IBeanFlowConstruct flow;
65  
66      protected MuleIBeansPlugin plugin;
67      
68      protected MuleContext muleContext;
69  
70      public IBeanBinding(IBeanFlowConstruct flow, MuleContext muleContext, MuleIBeansPlugin plugin)
71      {
72          this.flow = flow;
73          this.muleContext = muleContext;
74          this.plugin = plugin;
75      }
76  
77      public String getMethod()
78      {
79          throw new UnsupportedOperationException();
80      }
81  
82      public void setMethod(String method)
83      {
84          throw new UnsupportedOperationException();
85      }
86  
87      public MuleEvent process(MuleEvent event) throws MessagingException
88      {
89          try
90          {
91              return endpoint.process(new DefaultMuleEvent(event.getMessage(), endpoint, event.getSession()));
92          }
93          catch (MessagingException e)
94          {
95              throw e;
96          }
97          catch (MuleException e)
98          {
99              throw new MessagingException(e.getI18nMessage(), event, e);
100         }
101     }
102 
103     public void setInterface(Class interfaceClass)
104     {
105         this.interfaceClass = interfaceClass;
106     }
107 
108     public Class getInterface()
109     {
110         return interfaceClass;
111     }
112 
113     public Object createProxy(Object target)
114     {
115         Map<String, String> evals = new HashMap<String, String>();
116         try
117         {
118             IBeanInvoker<MuleCallAnnotationHandler, TemplateAnnotationHandler, InvokeAnnotationHandler> invoker = plugin.getIBeanInvoker();
119             invoker.getCallHandler().setFlow(flow);
120 
121             List<AnnotationMetaData> annos = AnnotationUtils.getAllMethodAnnotations(getInterface());
122             for (AnnotationMetaData metaData : annos)
123             {
124                 if (metaData.getAnnotation() instanceof Call)
125                 {
126                     Collection c = muleContext.getRegistry().lookupObjects(EndpointAnnotationParser.class);
127                     String scheme;
128                     boolean http;
129                     String uri = ((Call) metaData.getAnnotation()).uri();
130                     int i = uri.indexOf(":/");
131                     if (i == -1)
132                     {
133                         scheme = "dynamic";
134                     }
135                     else
136                     {
137                         scheme = uri.substring(0, i);
138                     }
139                     http = scheme.contains("http");
140 
141                     Map metaInfo = new HashMap();
142                     //By setting the connectorName we ensure that only one connector is created for each iBean
143                     metaInfo.put("connectorName", metaData.getClazz().getSimpleName() + "." + scheme); //RM*  THis affects the connector name generation + "#" + target.hashCode());
144 
145                     for (Iterator iterator = c.iterator(); iterator.hasNext();)
146                     {
147                         EndpointAnnotationParser parser = (EndpointAnnotationParser) iterator.next();
148                         if (parser.supports(metaData.getAnnotation(), metaData.getClazz(), metaData.getMember()))
149                         {
150                             InterfaceBinding binding;
151                             Method method = (Method) metaData.getMember();
152                             boolean callChannel = false;
153                             Annotation ann;
154                             //This is a little messy, but we need to detect whether we are doing a Mule 'send' or Mule 'request' call.
155                             //Request calls get data from a resource such as DB, email inbox or message queue. These types of request will
156                             //not have any payload or headers defined.
157                             //The other way to handle this is to introduce a new annotation to explicitly handle this (See the Get annotation).
158                             //The issue is it may be difficult for the user to understand the difference between @Call and @Get. Instead we figure it out
159                             //here.
160                             for (int x = 0; x < method.getParameterAnnotations().length; x++)
161                             {
162                                 ann = method.getParameterAnnotations()[x][0];
163                                 if (ann.annotationType().equals(Body.class) ||
164                                         ann.annotationType().equals(BodyParam.class) ||
165                                         ann.annotationType().equals(HeaderParam.class))
166                                 {
167 
168                                     callChannel = true;
169 
170                                     break;
171                                 }
172                             }
173                             //TODO remove the HTTP hack above. Its required becuase HTTP request on the dispatcher
174                             //don't honour authenitcation for some reason.  Also even though there may not be any headers
175                             //defined we still need to attach some headers to the HTTP method. This is very difficult when
176                             //using request
177                             if (callChannel || http)
178                             {
179                                 OutboundEndpoint endpoint = parser.parseOutboundEndpoint(metaData.getAnnotation(), metaInfo);
180                                 binding = new CallInterfaceBinding(this.flow);
181                                 binding.setEndpoint(endpoint);
182                             }
183                             else
184                             {
185                                 InboundEndpoint endpoint = parser.parseInboundEndpoint(metaData.getAnnotation(), Collections.EMPTY_MAP);
186                                 binding = new DynamicRequestInterfaceBinding();
187                                 binding.setEndpoint(endpoint);
188                             }
189 
190                             binding.setInterface(getInterface());
191                             binding.setMethod(metaData.getMember().toString());
192                             invoker.getCallHandler().addRouterForInterface(binding);
193 
194                         }
195                     }
196                 }
197                 else if (metaData.getAnnotation() instanceof Template)
198                 {
199                     evals.put(metaData.getMember().toString(), ((Template) metaData.getAnnotation()).value());
200                 }
201             }
202 
203             if (evals.size() > 0)
204             {
205                 invoker.getTemplateHandler().setEvals(evals);
206             }
207 
208             Object proxy = Proxy.newProxyInstance(getInterface().getClassLoader(), new Class[]{getInterface()}, createInvocationHandler());
209             if (logger.isDebugEnabled())
210             {
211                 logger.debug("Have proxy?: " + (null != proxy));
212             }
213             return proxy;
214 
215         }
216         catch (Exception e)
217         {
218             throw new MuleRuntimeException(CoreMessages.failedToCreateProxyFor(target), e);
219         }
220     }
221 
222     public void setEndpoint(ImmutableEndpoint e)
223     {
224         endpoint = (OutboundEndpoint) e;
225     }
226 
227     public String toString()
228     {
229         final StringBuffer sb = new StringBuffer();
230         sb.append("IBeanBinding");
231         sb.append(", interface=").append(interfaceClass);
232         sb.append('}');
233         return sb.toString();
234     }
235 
236     public ImmutableEndpoint getEndpoint()
237     {
238         return endpoint;
239     }
240 
241     protected InvocationHandler createInvocationHandler() throws IBeansException
242     {
243         return new IntegrationBeanInvocationHandler(interfaceClass, plugin);
244     }
245 }