View Javadoc

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