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 <T>
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 <T>
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 }