View Javadoc

1   /*
2    * $Id: RmiConnector.java 22156 2011-06-08 21:36:30Z 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  
11  package org.mule.transport.rmi;
12  
13  import org.mule.api.MessagingException;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.config.MuleProperties;
18  import org.mule.api.construct.FlowConstruct;
19  import org.mule.api.endpoint.EndpointURI;
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.api.lifecycle.InitialisationException;
24  import org.mule.api.transformer.TransformerException;
25  import org.mule.api.transport.MessageReceiver;
26  import org.mule.api.transport.PropertyScope;
27  import org.mule.config.i18n.CoreMessages;
28  import org.mule.transport.AbstractJndiConnector;
29  import org.mule.transport.rmi.i18n.RmiMessages;
30  import org.mule.util.ArrayUtils;
31  import org.mule.util.ClassUtils;
32  import org.mule.util.IOUtils;
33  
34  import java.io.IOException;
35  import java.lang.reflect.Method;
36  import java.net.InetAddress;
37  import java.net.URL;
38  import java.rmi.NotBoundException;
39  import java.rmi.RMISecurityManager;
40  import java.rmi.Remote;
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Iterator;
44  import java.util.List;
45  
46  import javax.naming.NamingException;
47  
48  import org.apache.commons.collections.MapUtils;
49  
50  /**
51   * <code>RmiConnector</code> can bind or send to a given RMI port on a given host.
52   */
53  public class RmiConnector extends AbstractJndiConnector
54  {
55  
56      public static final String RMI = "rmi";
57      public static final int DEFAULT_RMI_muleRegistry_PORT = 1099;
58      public static final String PROPERTY_RMI_SECURITY_POLICY = "securityPolicy";
59      public static final String PROPERTY_RMI_SERVER_CODEBASE = "serverCodebase";
60      public static final String PROPERTY_SERVER_CLASS_NAME = "serverClassName";
61  
62      /**
63       * The property name that explicitly defines which argument types should be
64       * passed to a remote object method invocation. This is a comma-separate list for
65       * fully qualified classnames. If this property is not set on an outbound
66       * endpoint, the argument types will be determined automatically from the payload
67       * of the current message
68       */
69      public static final String PROPERTY_SERVICE_METHOD_PARAM_TYPES = "methodArgumentTypes";
70  
71      /**
72       * The property name for a list of objects used to call a Remote object via an
73       * RMI or EJB MessageReceiver
74       */
75      public static final String PROPERTY_SERVICE_METHOD_PARAMS_LIST = "methodArgumentsList";
76  
77      private String securityPolicy = null;
78  
79      private String serverCodebase = null;
80  
81      private String serverClassName = null;
82  
83      protected long pollingFrequency = 1000L;
84  
85      private SecurityManager securityManager = new RMISecurityManager();
86      
87      public RmiConnector(MuleContext context)
88      {
89          super(context);
90      }
91  
92      @Override
93      protected void doInitialise() throws InitialisationException
94      {
95  
96          if (securityPolicy != null)
97          {
98              System.setProperty("java.security.policy", securityPolicy);
99          }
100 
101         // Set security manager
102         if (securityManager != null)
103         {
104             System.setSecurityManager(securityManager);
105         }
106 
107         initJndiContext();
108     }
109 
110     @Override
111     protected void doDispose()
112     {
113         // template method
114     }
115 
116     @Override
117     protected void doConnect() throws Exception
118     {
119         // template method
120     }
121 
122     @Override
123     protected void doDisconnect() throws Exception
124     {
125         // template method
126     }
127 
128     @Override
129     protected void doStart() throws MuleException
130     {
131         // template method
132     }
133 
134     @Override
135     protected void doStop() throws MuleException
136     {
137         // template method
138     }
139 
140     public String getProtocol()
141     {
142         return RMI;
143     }
144 
145     public String getSecurityPolicy()
146     {
147         return securityPolicy;
148     }
149 
150     public void setSecurityPolicy(String path)
151     {
152         // verify securityPolicy existence
153         if (path != null)
154         {
155             URL url = IOUtils.getResourceAsUrl(path, RmiConnector.class);
156             if (url == null)
157             {
158                 throw new IllegalArgumentException(
159                     "Error on initialization, RMI security policy does not exist");
160             }
161             this.securityPolicy = url.toString();
162         }
163     }
164 
165     public String getServerCodebase()
166     {
167         return (this.serverCodebase);
168     }
169 
170     public void setServerCodebase(String serverCodebase)
171     {
172         this.serverCodebase = serverCodebase;
173     }
174 
175     public String getServerClassName()
176     {
177         return (this.serverClassName);
178     }
179 
180     public void setServerClassName(String serverClassName)
181     {
182         this.serverClassName = serverClassName;
183     }
184 
185     public SecurityManager getSecurityManager()
186     {
187         return securityManager;
188     }
189 
190     public void setSecurityManager(SecurityManager securityManager)
191     {
192         this.securityManager = securityManager;
193     }
194 
195     @Override
196     public MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
197     {
198         final Object[] args = new Object[]{new Long(pollingFrequency)};
199         return getServiceDescriptor().createMessageReceiver(this, flowConstruct, endpoint, args);
200     }
201 
202     /**
203      * Helper method for Dispatchers and Receives to extract the correct method from
204      * a Remote object
205      *
206      * @param remoteObject The remote object on which to invoke the method
207      * @param event The current event being processed
208      * @throws org.mule.api.MuleException
209      * @throws NoSuchMethodException
210      * @throws ClassNotFoundException
211      */
212     public Method getMethodObject(Remote remoteObject, MuleEvent event, OutboundEndpoint outboundEndpoint)
213         throws MuleException, NoSuchMethodException, ClassNotFoundException
214     {
215         EndpointURI endpointUri = outboundEndpoint.getEndpointURI();
216         String methodName = MapUtils.getString(endpointUri.getParams(), MuleProperties.MULE_METHOD_PROPERTY,
217             null);
218 
219         if (null == methodName)
220         {
221             methodName = (String)event.getMessage().removeProperty(MuleProperties.MULE_METHOD_PROPERTY, PropertyScope.INVOCATION);
222 
223             if (null == methodName)
224             {
225                 throw new MessagingException(RmiMessages.messageParamServiceMethodNotSet(), event);
226             }
227         }
228 
229         Class[] argTypes = getArgTypes(event.getMessage().getInvocationProperty(RmiConnector.PROPERTY_SERVICE_METHOD_PARAM_TYPES), event);
230 
231         try
232         {
233             return remoteObject.getClass().getMethod(methodName, argTypes);
234         }
235         catch (NoSuchMethodException e)
236         {
237             throw new NoSuchMethodException(
238                 CoreMessages.methodWithParamsNotFoundOnObject(methodName, ArrayUtils.toString(argTypes),
239                     remoteObject.getClass()).toString());
240         }
241         catch (SecurityException e)
242         {
243             throw e;
244         }
245     }
246 
247     protected Class[] stringsToClasses(Collection strings) throws ClassNotFoundException
248     {
249         Class[] classes = new Class[strings.size()];
250         int index = 0;
251         Iterator string = strings.iterator();
252         while (string.hasNext())
253         {
254             classes[index++] = ClassUtils.loadClass((String) string.next(), getClass());
255         }
256         return classes;
257     }
258 
259     protected Object getRemoteRef(ImmutableEndpoint endpoint)
260         throws IOException, NotBoundException, NamingException, InitialisationException
261     {
262 
263         EndpointURI endpointUri = endpoint.getEndpointURI();
264 
265         String serviceName = endpointUri.getPath();
266         try
267         {
268             // Test if we can find the object locally
269             return getJndiContext().lookup(serviceName);
270         }
271         catch (NamingException e)
272         {
273             // Strip path seperator
274         }
275 
276         try
277         {
278             serviceName = serviceName.substring(1);
279             return getJndiContext().lookup(serviceName);
280         }
281         catch (NamingException e)
282         {
283             // Try with full host and path
284         }
285 
286         int port = endpointUri.getPort();
287         if (port < 1)
288         {
289             if (logger.isWarnEnabled())
290             {
291                 logger.warn("RMI port not set on URI: " + endpointUri + ". Using default port: "
292                             + RmiConnector.DEFAULT_RMI_muleRegistry_PORT);
293             }
294             port = RmiConnector.DEFAULT_RMI_muleRegistry_PORT;
295         }
296 
297         InetAddress inetAddress = InetAddress.getByName(endpointUri.getHost());
298 
299         return getJndiContext(inetAddress.getHostAddress() + ":" + port).lookup(serviceName);
300     }
301 
302     public Remote getRemoteObject(ImmutableEndpoint endpoint)
303         throws IOException, NotBoundException, NamingException, InitialisationException
304     {
305         return (Remote)getRemoteRef(endpoint);
306     }
307 
308     public long getPollingFrequency()
309     {
310         return pollingFrequency;
311     }
312 
313     public void setPollingFrequency(long pollingFrequency)
314     {
315         this.pollingFrequency = pollingFrequency;
316     }
317 
318     protected Class[] getArgTypes(Object args, MuleEvent fromEvent) 
319         throws ClassNotFoundException, TransformerException
320     {
321         Class<?>[] argTypes = null;
322 
323         if (args instanceof List)
324         {
325             // MULE-1794 this used to take the first list entry as a string, splitting it
326             // as for String below.
327             argTypes = stringsToClasses((List) args);
328         }
329         else if (args instanceof String)
330         {
331             argTypes = stringsToClasses(Arrays.asList(((String) args).split(",")));
332         }
333         else
334         {
335             argTypes = ClassUtils.getClassTypes(fromEvent.getMessage().getPayload());
336         }
337 
338         return argTypes;
339     }
340 }