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