Source code: org/jnp/server/Main.java
1 /*
2 * Distributable under LGPL license.
3 * See terms of license at gnu.org.
4 *
5 * Copyright 1999 by dreamBean Software,
6 * All rights reserved.
7 */
8 package org.jnp.server;
9
10 import java.io.InputStream;
11 import java.io.IOException;
12 import java.io.ObjectOutputStream;
13 import java.net.InetAddress;
14 import java.net.Socket;
15 import java.net.ServerSocket;
16 import java.net.UnknownHostException;
17 import java.net.URL;
18 import java.rmi.Remote;
19 import java.rmi.MarshalledObject;
20 import java.rmi.server.RMIClientSocketFactory;
21 import java.rmi.server.RMIServerSocketFactory;
22 import java.rmi.server.UnicastRemoteObject;
23 import java.lang.reflect.Method;
24 import javax.net.ServerSocketFactory;
25
26 import org.apache.log4j.Category;
27 import org.apache.log4j.PropertyConfigurator;
28
29 import org.jnp.interfaces.Naming;
30 import org.jnp.interfaces.NamingContext;
31 import org.jboss.net.sockets.DefaultSocketFactory;
32
33 /** A main() entry point for running the jnp naming service implementation as
34 a standalone process.
35
36 @author oberg
37 @author Scott.Stark@jboss.org
38 @version $Revision: 1.12.2.6 $
39 */
40 public class Main implements Runnable, MainMBean
41 {
42 // Constants -----------------------------------------------------
43
44 // Attributes ----------------------------------------------------
45 /** The Naming interface server implementation */
46 protected NamingServer theServer;
47 protected MarshalledObject serverStub;
48 /** The jnp server socket through which the NamingServer stub is vended */
49 protected ServerSocket serverSocket;
50 /** An optional custom client socket factory */
51 protected RMIClientSocketFactory clientSocketFactory;
52 /** An optional custom server socket factory */
53 protected RMIServerSocketFactory serverSocketFactory;
54 /** An optional custom server socket factory */
55 protected ServerSocketFactory jnpServerSocketFactory;
56 /** The class name of the optional custom client socket factory */
57 protected String clientSocketFactoryName;
58 /** The class name of the optional custom server socket factory */
59 protected String serverSocketFactoryName;
60 /** The class name of the optional custom JNP server socket factory */
61 protected String jnpServerSocketFactoryName;
62 /** The interface to bind to for the lookup socket. This is useful for
63 * multi-homed hosts that want control over which interfaces accept
64 * connections.
65 */
66 protected InetAddress bindAddress;
67 /** The interface to bind to for the Naming RMI server.
68 */
69 protected InetAddress rmiBindAddress;
70 /** The serverSocket listen queue depth */
71 protected int backlog = 50;
72 /** The jnp protocol listening port. The default is 1099, the same as
73 the RMI registry default port. */
74 protected int port = 1099;
75 /** The RMI port on which the Naming implementation will be exported. The
76 default is 0 which means use any available port. */
77 protected int rmiPort = 0;
78 /** A flag indicating if theServer will be set as the NamingContext.setLocal value */
79 protected boolean InstallGlobalService = true;
80 protected Category log;
81
82 // Static --------------------------------------------------------
83 public static void main(String[] args)
84 throws Exception
85 {
86 // Make sure the config file can be found
87 ClassLoader loader = Thread.currentThread().getContextClassLoader();
88 URL url = loader.getResource("log4j.properties");
89 if( url == null )
90 System.err.println("Failed to find log4j.properties");
91 else
92 PropertyConfigurator.configure(url);
93 new Main().start();
94 }
95
96 // Constructors --------------------------------------------------
97 public Main()
98 {
99 this("org.jboss.naming.Naming");
100 }
101 public Main(String categoryName)
102 {
103 // Load properties from properties file
104 try
105 {
106 ClassLoader loader = getClass().getClassLoader();
107 InputStream is = loader.getResourceAsStream("jnp.properties");
108 System.getProperties().load(is);
109 }
110 catch (Exception e)
111 {
112 // Ignore
113 }
114
115 // Set configuration from the system properties
116 setPort(Integer.getInteger("jnp.port",getPort()).intValue());
117 setRmiPort(Integer.getInteger("jnp.rmiPort",getRmiPort()).intValue());
118 log = Category.getInstance(categoryName);
119 }
120
121 // Public --------------------------------------------------------
122 public Naming getServer()
123 {
124 return theServer;
125 }
126
127 public void setRmiPort(int p)
128 {
129 rmiPort = p;
130 }
131 public int getRmiPort()
132 {
133 return rmiPort;
134 }
135
136 public void setPort(int p)
137 {
138 port = p;
139 }
140 public int getPort()
141 {
142 return port;
143 }
144
145 public String getBindAddress()
146 {
147 String address = null;
148 if( bindAddress != null )
149 address = bindAddress.getHostAddress();
150 return address;
151 }
152 public void setBindAddress(String host) throws UnknownHostException
153 {
154 if( host == null || host.length() == 0 )
155 bindAddress = null;
156 else
157 bindAddress = InetAddress.getByName(host);
158 }
159
160 public String getRmiBindAddress()
161 {
162 String address = null;
163 if( rmiBindAddress != null )
164 address = rmiBindAddress.getHostAddress();
165 return address;
166 }
167 public void setRmiBindAddress(String host) throws UnknownHostException
168 {
169 if( host == null || host.length() == 0 )
170 rmiBindAddress = null;
171 else
172 rmiBindAddress = InetAddress.getByName(host);
173 }
174
175 public int getBacklog()
176 {
177 return backlog;
178 }
179 public void setBacklog(int backlog)
180 {
181 if( backlog <= 0 )
182 backlog = 50;
183 this.backlog = backlog;
184 }
185
186 public boolean getInstallGlobalService()
187 {
188 return InstallGlobalService;
189 }
190 public void setInstallGlobalService(boolean flag)
191 {
192 this.InstallGlobalService = flag;
193 }
194
195 public String getClientSocketFactory()
196 {
197 return clientSocketFactoryName;
198 }
199 public void setClientSocketFactory(String factoryClassName)
200 throws ClassNotFoundException, InstantiationException, IllegalAccessException
201 {
202 this.clientSocketFactoryName = factoryClassName;
203 ClassLoader loader = Thread.currentThread().getContextClassLoader();
204 Class clazz = loader.loadClass(clientSocketFactoryName);
205 clientSocketFactory = (RMIClientSocketFactory) clazz.newInstance();
206 }
207
208 public String getServerSocketFactory()
209 {
210 return serverSocketFactoryName;
211 }
212 public void setServerSocketFactory(String factoryClassName)
213 throws ClassNotFoundException, InstantiationException, IllegalAccessException
214 {
215 this.serverSocketFactoryName = factoryClassName;
216 ClassLoader loader = Thread.currentThread().getContextClassLoader();
217 Class clazz = loader.loadClass(serverSocketFactoryName);
218 serverSocketFactory = (RMIServerSocketFactory) clazz.newInstance();
219 }
220
221 public void setJNPServerSocketFactory(String factoryClassName)
222 throws ClassNotFoundException, InstantiationException, IllegalAccessException
223 {
224 this.jnpServerSocketFactoryName = factoryClassName;
225 ClassLoader loader = Thread.currentThread().getContextClassLoader();
226 Class clazz = loader.loadClass(jnpServerSocketFactoryName);
227 jnpServerSocketFactory = (ServerSocketFactory) clazz.newInstance();
228 }
229
230 public void start()
231 throws Exception
232 {
233 log.info("Starting jnp server");
234 // Create the local naming service instance if it does not exist
235 if( theServer == null )
236 {
237 theServer = new NamingServer();
238 if( InstallGlobalService == true )
239 {
240 // Set local server reference
241 NamingContext.setLocal(theServer);
242 }
243 }
244
245 /* Only export server RMI interface and setup the listening socket if
246 the port is >= 0. A value < 0 indicates the socket based access
247 */
248 if( this.port >= 0 )
249 initJnpInvoker();
250 }
251
252 public void stop()
253 {
254 try
255 {
256 log.info("Stopping");
257 // Stop listener and unexport the RMI object
258 if( serverSocket != null )
259 {
260 UnicastRemoteObject.unexportObject(theServer, false);
261 ServerSocket s = serverSocket;
262 serverSocket = null;
263 s.close();
264 }
265 log.info("Stopped");
266 }
267 catch (Exception e)
268 {
269 log.error("Exception during shutdown", e);
270 }
271 }
272
273 // Runnable implementation ---------------------------------------
274 public void run()
275 {
276 Socket socket = null;
277
278 // Accept a connection
279 try
280 {
281 socket = serverSocket.accept();
282 } catch (IOException e)
283 {
284 if (serverSocket == null)
285 return; // Stopped by normal means
286
287 log.error("Naming stopped", e);
288 log.info("Restarting naming");
289 try
290 {
291 start();
292 } catch (Exception ex)
293 {
294 log.error("Restart failed", ex);
295 return;
296 }
297 }
298
299 // Create a new thread to accept the next connection
300 listen();
301
302 // Return the naming server stub
303 try
304 {
305 ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
306 out.writeObject(serverStub);
307 }
308 catch (IOException ex)
309 {
310 log.error("Error writing response", ex);
311 }
312 finally
313 {
314 try
315 {
316 socket.close();
317 } catch (IOException e)
318 {
319 }
320 }
321 }
322
323 // Y overrides ---------------------------------------------------
324
325 // Package protected ---------------------------------------------
326
327 // Protected -----------------------------------------------------
328
329 protected void listen()
330 {
331 Thread t = new Thread(this, "JNP Server");
332 t.start();
333 }
334
335 /** This code should be moved to a seperate invoker in the org.jboss.naming
336 *package.
337 */
338 protected void initJnpInvoker() throws IOException
339 {
340 // Use either the rmiBindAddress or bindAddress for the RMI service
341 InetAddress addr = rmiBindAddress;
342 if( addr == null )
343 addr = bindAddress;
344 // If there is an address we need a socket factory
345 if( addr != null )
346 {
347 // If there is no serverSocketFactory use a default
348 if( serverSocketFactory == null )
349 serverSocketFactory = new DefaultSocketFactory(addr);
350 else
351 {
352 // See if the server socket supports setBindAddress(String)
353 try
354 {
355 Class[] parameterTypes = {String.class};
356 Class ssfClass = serverSocketFactory.getClass();
357 Method m = ssfClass.getMethod("setBindAddress", parameterTypes);
358 Object[] args = {bindAddress.getHostAddress()};
359 m.invoke(serverSocketFactory, args);
360 }
361 catch (NoSuchMethodException e)
362 {
363 log.warn("Socket factory does not support setBindAddress(String)");
364 // Go with default address
365 }
366 catch (Exception e)
367 {
368 log.warn("Failed to setBindAddress="+bindAddress+" on socket factory", e);
369 // Go with default address
370 }
371 }
372 }
373 log.debug("Creating NamingServer stub, theServer="+theServer
374 +",rmiPort="+rmiPort+",clientSocketFactory="+clientSocketFactory
375 +",serverSocketFactory="+serverSocketFactory);
376 Remote stub = UnicastRemoteObject.exportObject(theServer, rmiPort,
377 clientSocketFactory, serverSocketFactory);
378 log.debug("NamingServer stub: "+stub);
379 serverStub = new MarshalledObject(stub);
380
381 // Start listener
382 try
383 {
384 // Get the default ServerSocketFactory is one was not specified
385 if( jnpServerSocketFactory == null )
386 jnpServerSocketFactory = ServerSocketFactory.getDefault();
387 serverSocket = jnpServerSocketFactory.createServerSocket(port, backlog, bindAddress);
388 // If an anonymous port was specified get the actual port used
389 if( port == 0 )
390 port = serverSocket.getLocalPort();
391 String msg = "Started jnpPort=" + port +", rmiPort=" + rmiPort
392 + ", backlog="+backlog+", bindAddress="+bindAddress
393 + ", Client SocketFactory="+clientSocketFactory
394 + ", Server SocketFactory="+serverSocketFactory;
395 log.info(msg);
396 listen();
397 }
398 catch (IOException e)
399 {
400 log.error("Could not start on port " + port, e);
401 }
402 }
403
404 // Private -------------------------------------------------------
405
406 // Inner classes -------------------------------------------------
407 }