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.rmi.ConnectException;
28 import java.rmi.NotBoundException;
29 import java.rmi.Remote;
30 import java.rmi.RemoteException;
31 import java.rmi.registry.LocateRegistry;
32 import java.rmi.registry.Registry;
33 import java.rmi.server.ExportException;
34 import java.rmi.server.UnicastRemoteObject;
35
36 /**
37 * This class allows to make some service available throw RMI. For each service,
38 * a wrapper will be created which will be put in the RMI registry. This wrapper
39 * will intercept calls to the service and delegate them to it.
40 *
41 * @author Arnaud Thimel - thimel@codelutin.com
42 */
43 public final class ServiceExporter {
44
45 private static final Log log = LogFactory.getLog(ServiceExporter.class);
46
47 // TODO AThimel 12/01/2011 This settings has to be externalized
48 private static final int PORT = 12345;
49
50 /** Does some checks on RMI configuration */
51 protected static void testRmiConfig() {
52 String rmiHost = System.getProperty("java.rmi.server.hostname");
53 if ((rmiHost == null || "".equals(rmiHost.trim()))
54 && log.isWarnEnabled()) {
55 log.warn("Server might not have been initialized properly, " +
56 "please specify '-Djava.rmi.server.hostname=<IP-address>'");
57 }
58 }
59
60 /**
61 * Will look for the RMI registry. It an external registry cannot be found,
62 * a new one will be created.
63 *
64 * @return the registry found or created
65 * @throws RemoteException in case it is not possible to get the registry
66 */
67 protected static Registry getRegistry() throws RemoteException {
68 Registry result;
69 try {
70 result = LocateRegistry.getRegistry(PORT);
71 // To test that registry has been created. An exception will be
72 // thrown if registry cannot be called
73 result.list();
74 } catch (ConnectException ce) {
75 if (log.isWarnEnabled()) {
76 log.warn("Registry not found, creating a new one");
77 }
78 try {
79 result = LocateRegistry.createRegistry(PORT);
80 } catch (ExportException ee) { // This is the particular case when a registry is already running but not on the correct port.
81 if (log.isWarnEnabled()) {
82 log.warn("Unable to create registry, try using the default one", ee);
83 }
84
85 // Try the default port
86 result = LocateRegistry.getRegistry();
87 }
88 }
89 return result;
90 }
91
92 /**
93 * Will register a service using the default name.
94 *
95 * @param serviceInterface the interface used to bind the service. The RMI
96 * name will be generated from this class name
97 * @param instance the service instance to bind
98 * @param <E> some interface class
99 * @throws RemoteException in case the registry is not reachable
100 */
101 public static <E> void registerService(Class<E> serviceInterface, E instance)
102 throws RemoteException {
103 String rmiName = serviceInterface.getName();
104 registerService(rmiName, instance);
105 }
106
107 /**
108 * Will register a service using the given RMI name.
109 *
110 * @param rmiName the RMI name used to bind the service in the registry
111 * @param instance the service instance to bind
112 * @param <E> some interface class
113 * @throws RemoteException in case the registry is not reachable
114 */
115 public static <E> void registerService(String rmiName, E instance)
116 throws RemoteException {
117
118 testRmiConfig();
119
120 // Create the proxy and let him be a stub
121 RemoteMethodExecutorImpl<E> executor =
122 new RemoteMethodExecutorImpl<E>(instance);
123 Remote stub = UnicastRemoteObject.exportObject(executor, 0);
124
125 // Bind into the registry
126 Registry registry = getRegistry();
127 registry.rebind(rmiName, stub);
128 }
129
130 /**
131 * Will unregister a service using the default name.
132 *
133 * @param serviceInterface the interface used to unbind the service. The RMI
134 * name will be generated from this class name
135 * @throws RemoteException in case the registry is not reachable
136 * @throws NotBoundException in case the given name is not bound
137 */
138 public static void unregisterService(Class<?> serviceInterface)
139 throws RemoteException, NotBoundException {
140 String rmiName = serviceInterface.getName();
141 unregisterService(rmiName);
142 }
143
144 /**
145 * Will unregister a service using the given RMI name.
146 *
147 * @param rmiName the RMI name used to unbind the service in the registry
148 * @throws RemoteException in case the registry is not reachable
149 * @throws NotBoundException in case the given name is not bound
150 */
151 public static void unregisterService(String rmiName)
152 throws RemoteException, NotBoundException {
153
154 // Bind into the registry
155 Registry registry = getRegistry();
156 registry.unbind(rmiName);
157 }
158
159 }