View Javadoc
1   /*
2    * #%L
3    * Nuiton Utils
4    * %%
5    * Copyright (C) 2004 - 2010 CodeLutin
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 3 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20   * #L%
21   */
22  package org.nuiton.util.rmi;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import java.lang.reflect.InvocationHandler;
28  import java.lang.reflect.Method;
29  import java.lang.reflect.Proxy;
30  import java.rmi.ConnectException;
31  import java.rmi.NotBoundException;
32  import java.rmi.RemoteException;
33  import java.rmi.ServerException;
34  import java.rmi.registry.LocateRegistry;
35  import java.rmi.registry.Registry;
36  
37  /**
38   * Factory to create RMI proxies to some given services.
39   *
40   * @author Arnaud Thimel - thimel@codelutin.com
41   */
42  public class RemoteProxyFactory {
43  
44      private static final Log log = LogFactory.getLog(RemoteProxyFactory.class);
45  
46      // TODO AThimel 12/01/2011 This settings has to be externalized
47      protected final static int PORT = 12345;
48  
49      protected final static String REGISTRY_IP = "127.0.0.1";
50  
51      /**
52       * Create a RMI proxy on the wanted service interface. The default RMI name
53       * will be used to find this service in the Registry.
54       *
55       * @param serviceInterface The class of the service proxy to create
56       * @param <T>              some interface class
57       * @return A newly created proxy which interface is &lt;T&gt;
58       * @throws RemoteException   in case the registry is not reachable
59       * @throws NotBoundException if the default RMI name cannot be found in the
60       *                           registry
61       */
62      public static <T> T createProxy(final Class<T> serviceInterface)
63              throws RemoteException, NotBoundException {
64  
65          // The default RMI name will be the FQN of the service interface
66          String rmiName = serviceInterface.getName();
67          T result = createProxy(rmiName, serviceInterface);
68  
69          return result;
70      }
71  
72      /**
73       * Create a RMI proxy on the wanted service interface. The specific given
74       * RMI name will be used to find this service in the Registry.
75       *
76       * @param rmiName          The specific RMI name to use to find the service
77       *                         in the registry
78       * @param serviceInterface The class of the service proxy to create
79       * @param <T>              some interface class
80       * @return A newly created proxy which interface is &lt;T&gt;
81       * @throws RemoteException   in case the registry is not reachable
82       * @throws NotBoundException if the default RMI name cannot be found in the
83       *                           registry
84       */
85      public static <T> T createProxy(String rmiName, Class<T> serviceInterface)
86              throws RemoteException, NotBoundException {
87  
88          // Lookup the registry and the remote executor from the registry
89          Registry registry = LocateRegistry.getRegistry(REGISTRY_IP, PORT);
90          try {
91              registry.list();
92          } catch (ConnectException ce) {
93              // That means the registry is not on the specified port, try the default one
94              registry = LocateRegistry.getRegistry();
95          }
96          final RemoteMethodExecutor stub =
97                  (RemoteMethodExecutor) registry.lookup(rmiName);
98  
99          InvocationHandler handler = new InvocationHandler() {
100             @Override
101             public Object invoke(Object proxy, Method method, Object[] args)
102                     throws Throwable {
103 
104                 // Get parameters types and values to prepare delegate call
105                 String methodName = method.getName();
106                 Class<?>[] parametersType = method.getParameterTypes();
107 
108                 // Delegate the execution and manage business exception cases
109                 Object result;
110                 try {
111                     result = stub.execute(methodName, parametersType, args);
112                 } catch (ServerException se) {
113                     if (log.isInfoEnabled()) {
114                         log.info("Server exception: " + se.getMessage());
115                     }
116                     Throwable cause = se.getCause();
117                     if (cause instanceof RemoteException) {
118                         RemoteException re = (RemoteException) cause;
119                         cause = re.getCause();
120                     }
121                     throw cause;
122                 }
123 
124                 return result;
125             }
126         };
127 
128         // Invocation handler is ready, now create the proxy
129         T proxy = (T) Proxy.newProxyInstance(
130                 ServiceExporter.class.getClassLoader(),
131                 new Class<?>[]{serviceInterface},
132                 handler);
133 
134         return proxy;
135     }
136 
137 }