View Javadoc

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