View Javadoc

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