001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jnp.server;
023:
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.ObjectOutputStream;
027: import java.io.OutputStream;
028: import java.lang.reflect.Method;
029: import java.net.InetAddress;
030: import java.net.ServerSocket;
031: import java.net.Socket;
032: import java.net.UnknownHostException;
033: import java.rmi.MarshalledObject;
034: import java.rmi.Remote;
035: import java.rmi.server.RMIClientSocketFactory;
036: import java.rmi.server.RMIServerSocketFactory;
037: import java.rmi.server.UnicastRemoteObject;
038:
039: import javax.net.ServerSocketFactory;
040:
041: import org.jboss.logging.Logger;
042: import org.jboss.net.sockets.DefaultSocketFactory;
043: import org.jboss.util.threadpool.BasicThreadPool;
044: import org.jboss.util.threadpool.ThreadPool;
045: import org.jnp.interfaces.Naming;
046:
047: /**
048: * A main() entry point for running the jnp naming service implementation as
049: * a standalone process.
050: *
051: * @author Rickard Oberg
052: * @author Scott.Stark@jboss.org
053: * @version $Revision: 60231 $
054: */
055: public class Main implements MainMBean {
056: // Constants -----------------------------------------------------
057:
058: // Attributes ----------------------------------------------------
059: /** The Naming interface server implementation */
060: protected NamingBean theServer;
061: protected MarshalledObject serverStub;
062: protected boolean isStubExported;
063: /** The jnp server socket through which the NamingServer stub is vended */
064: protected ServerSocket serverSocket;
065: /** An optional custom client socket factory */
066: protected RMIClientSocketFactory clientSocketFactory;
067: /** An optional custom server socket factory */
068: protected RMIServerSocketFactory serverSocketFactory;
069: /** An optional custom server socket factory */
070: protected ServerSocketFactory jnpServerSocketFactory;
071: /** The class name of the optional custom client socket factory */
072: protected String clientSocketFactoryName;
073: /** The class name of the optional custom server socket factory */
074: protected String serverSocketFactoryName;
075: /** The class name of the optional custom JNP server socket factory */
076: protected String jnpServerSocketFactoryName;
077: /** The interface to bind to for the lookup socket. This is useful for
078: * multi-homed hosts that want control over which interfaces accept
079: * connections */
080: protected InetAddress bindAddress;
081: /** The interface to bind to for the Naming RMI server */
082: protected InetAddress rmiBindAddress;
083: /** The serverSocket listen queue depth */
084: protected int backlog = 50;
085: /** The jnp protocol listening port. The default is 1099, the same as
086: the RMI registry default port. */
087: protected int port = 1099;
088: /** The RMI port on which the Naming implementation will be exported. The
089: default is 0 which means use any available port. */
090: protected int rmiPort = 0;
091: /** A flag indicating if theServer will be set as the NamingContext.setLocal value */
092: protected boolean InstallGlobalService = true;
093: /** A flag indicating if theServer will try to use the NamingContext.setLocal value */
094: protected boolean UseGlobalService = true;
095: protected Logger log;
096: /** The thread pool used to handle jnp stub lookup requests */
097: protected ThreadPool lookupPool;
098:
099: // Static --------------------------------------------------------
100: public static void main(String[] args) throws Exception {
101: new Main().start();
102: }
103:
104: // Constructors --------------------------------------------------
105: public Main() {
106: this ("org.jboss.naming.Naming");
107: }
108:
109: public Main(String categoryName) {
110: // Load properties from properties file
111: try {
112: ClassLoader loader = getClass().getClassLoader();
113: InputStream is = loader
114: .getResourceAsStream("jnp.properties");
115: System.getProperties().load(is);
116: } catch (Exception e) {
117: // Ignore
118: }
119:
120: // Set configuration from the system properties
121: setPort(Integer.getInteger("jnp.port", getPort()).intValue());
122: setRmiPort(Integer.getInteger("jnp.rmiPort", getRmiPort())
123: .intValue());
124: log = Logger.getLogger(categoryName);
125: }
126:
127: // Public --------------------------------------------------------
128: public NamingBean getNamingInfo() {
129: return theServer;
130: }
131:
132: public void setNamingInfo(NamingBean info) {
133: this .theServer = info;
134: }
135:
136: public ThreadPool getLookupPool() {
137: return lookupPool;
138: }
139:
140: public void setLookupPool(ThreadPool lookupPool) {
141: this .lookupPool = lookupPool;
142: }
143:
144: public void setNamingProxy(Object proxy) throws IOException {
145: serverStub = new MarshalledObject(proxy);
146: }
147:
148: public void setRmiPort(int p) {
149: rmiPort = p;
150: }
151:
152: public int getRmiPort() {
153: return rmiPort;
154: }
155:
156: public void setPort(int p) {
157: port = p;
158: }
159:
160: public int getPort() {
161: return port;
162: }
163:
164: public String getBindAddress() {
165: String address = null;
166: if (bindAddress != null)
167: address = bindAddress.getHostAddress();
168: return address;
169: }
170:
171: public void setBindAddress(String host) throws UnknownHostException {
172: if (host == null || host.length() == 0)
173: bindAddress = null;
174: else
175: bindAddress = InetAddress.getByName(host);
176: }
177:
178: public String getRmiBindAddress() {
179: String address = null;
180: if (rmiBindAddress != null)
181: address = rmiBindAddress.getHostAddress();
182: return address;
183: }
184:
185: public void setRmiBindAddress(String host)
186: throws UnknownHostException {
187: if (host == null || host.length() == 0)
188: rmiBindAddress = null;
189: else
190: rmiBindAddress = InetAddress.getByName(host);
191: }
192:
193: public int getBacklog() {
194: return backlog;
195: }
196:
197: public void setBacklog(int backlog) {
198: if (backlog <= 0)
199: backlog = 50;
200: this .backlog = backlog;
201: }
202:
203: public boolean getInstallGlobalService() {
204: return InstallGlobalService;
205: }
206:
207: public void setInstallGlobalService(boolean flag) {
208: this .InstallGlobalService = flag;
209: }
210:
211: public boolean getUseGlobalService() {
212: return UseGlobalService;
213: }
214:
215: public void setUseGlobalService(boolean flag) {
216: this .UseGlobalService = flag;
217: }
218:
219: public String getClientSocketFactory() {
220: return clientSocketFactoryName;
221: }
222:
223: public void setClientSocketFactory(String factoryClassName)
224: throws ClassNotFoundException, InstantiationException,
225: IllegalAccessException {
226: this .clientSocketFactoryName = factoryClassName;
227: ClassLoader loader = Thread.currentThread()
228: .getContextClassLoader();
229: Class clazz = loader.loadClass(clientSocketFactoryName);
230: clientSocketFactory = (RMIClientSocketFactory) clazz
231: .newInstance();
232: }
233:
234: public RMIClientSocketFactory getClientSocketFactoryBean() {
235: return clientSocketFactory;
236: }
237:
238: public void setClientSocketFactoryBean(
239: RMIClientSocketFactory factory) {
240: this .clientSocketFactory = factory;
241: }
242:
243: public String getServerSocketFactory() {
244: return serverSocketFactoryName;
245: }
246:
247: public void setServerSocketFactory(String factoryClassName)
248: throws ClassNotFoundException, InstantiationException,
249: IllegalAccessException {
250: this .serverSocketFactoryName = factoryClassName;
251: ClassLoader loader = Thread.currentThread()
252: .getContextClassLoader();
253: Class clazz = loader.loadClass(serverSocketFactoryName);
254: serverSocketFactory = (RMIServerSocketFactory) clazz
255: .newInstance();
256: }
257:
258: public RMIServerSocketFactory getServerSocketFactoryBean() {
259: return serverSocketFactory;
260: }
261:
262: public void setServerSocketFactoryBean(
263: RMIServerSocketFactory factory) {
264: this .serverSocketFactory = factory;
265: }
266:
267: public String getJNPServerSocketFactory() {
268: return jnpServerSocketFactoryName;
269: }
270:
271: public void setJNPServerSocketFactory(String factoryClassName)
272: throws ClassNotFoundException, InstantiationException,
273: IllegalAccessException {
274: this .jnpServerSocketFactoryName = factoryClassName;
275: ClassLoader loader = Thread.currentThread()
276: .getContextClassLoader();
277: Class clazz = loader.loadClass(jnpServerSocketFactoryName);
278: jnpServerSocketFactory = (ServerSocketFactory) clazz
279: .newInstance();
280: }
281:
282: public ServerSocketFactory getJNPServerSocketFactoryBean() {
283: return jnpServerSocketFactory;
284: }
285:
286: public void setJNPServerSocketFactoryBean(
287: ServerSocketFactory factory) {
288: this .jnpServerSocketFactory = factory;
289: }
290:
291: public Naming getNamingInstance() {
292: return theServer.getNamingInstance();
293: }
294:
295: public void start() throws Exception {
296:
297: // Initialize the custom socket factories with any bind address
298: initCustomSocketFactories();
299: /* Only export server RMI interface and setup the listening socket if
300: the port is >= 0 and an external proxy has not been installed.
301: A value < 0 indicates no socket based access
302: */
303: if (this .serverStub == null && port >= 0) {
304: initJnpInvoker();
305: }
306: // Only bring up the bootstrap listener if there is a naming proxy
307: if (this .serverStub != null) {
308: initBootstrapListener();
309: }
310: }
311:
312: public void stop() {
313: try {
314: // Stop listener and unexport the RMI object
315: if (serverSocket != null) {
316: ServerSocket s = serverSocket;
317: serverSocket = null;
318: s.close();
319: }
320: if (isStubExported == true)
321: UnicastRemoteObject.unexportObject(theServer
322: .getNamingInstance(), false);
323: } catch (Exception e) {
324: log.error("Exception during shutdown", e);
325: }
326: }
327:
328: /** This code should be moved to a seperate invoker in the org.jboss.naming
329: *package.
330: */
331: protected void initJnpInvoker() throws IOException {
332: log.debug("Creating NamingServer stub, theServer=" + theServer
333: + ",rmiPort=" + rmiPort + ",clientSocketFactory="
334: + clientSocketFactory + ",serverSocketFactory="
335: + serverSocketFactory);
336: Remote stub = UnicastRemoteObject.exportObject(
337: getNamingInstance(), rmiPort, clientSocketFactory,
338: serverSocketFactory);
339: log.debug("NamingServer stub: " + stub);
340: serverStub = new MarshalledObject(stub);
341: }
342:
343: /** Bring up the bootstrap lookup port for obtaining the naming service
344: * proxy
345: */
346: protected void initBootstrapListener() {
347: // Start listener
348: try {
349: // Get the default ServerSocketFactory is one was not specified
350: if (jnpServerSocketFactory == null)
351: jnpServerSocketFactory = ServerSocketFactory
352: .getDefault();
353: serverSocket = jnpServerSocketFactory.createServerSocket(
354: port, backlog, bindAddress);
355: // If an anonymous port was specified get the actual port used
356: if (port == 0)
357: port = serverSocket.getLocalPort();
358: String msg = "JNDI bootstrap JNP=" + bindAddress + ":"
359: + port + ", RMI=" + bindAddress + ":" + rmiPort
360: + ", backlog=" + backlog;
361:
362: if (clientSocketFactory == null)
363: msg += ", no client SocketFactory";
364: else
365: msg += ", Client SocketFactory="
366: + clientSocketFactory.toString();
367:
368: if (serverSocketFactory == null)
369: msg += ", no server SocketFactory";
370: else
371: msg += ", Server SocketFactory="
372: + serverSocketFactory.toString();
373:
374: log.debug(msg);
375: } catch (IOException e) {
376: log.error("Could not start on port " + port, e);
377: }
378:
379: if (lookupPool == null)
380: lookupPool = new BasicThreadPool("NamingBootstrap Pool");
381: AcceptHandler handler = new AcceptHandler();
382: lookupPool.run(handler);
383: }
384:
385: /**
386: * Init the clientSocketFactory, serverSocketFactory using the bind address.
387: */
388: protected void initCustomSocketFactories() {
389: // Use either the rmiBindAddress or bindAddress for the RMI service
390: InetAddress addr = rmiBindAddress != null ? rmiBindAddress
391: : bindAddress;
392:
393: if (clientSocketFactory != null && addr != null) {
394: // See if the client socket supports setBindAddress(String)
395: try {
396: Class csfClass = clientSocketFactory.getClass();
397: Class[] parameterTypes = { String.class };
398: Method m = csfClass.getMethod("setBindAddress",
399: parameterTypes);
400: Object[] args = { addr.getHostAddress() };
401: m.invoke(clientSocketFactory, args);
402: } catch (NoSuchMethodException e) {
403: log
404: .warn("Socket factory does not support setBindAddress(String)");
405: // Go with default address
406: } catch (Exception e) {
407: log.warn("Failed to setBindAddress=" + addr
408: + " on socket factory", e);
409: // Go with default address
410: }
411: }
412:
413: try {
414: if (serverSocketFactory == null)
415: serverSocketFactory = new DefaultSocketFactory(addr);
416: else {
417: if (addr != null) {
418: // See if the server socket supports setBindAddress(String)
419: try {
420: Class ssfClass = serverSocketFactory.getClass();
421: Class[] parameterTypes = { String.class };
422: Method m = ssfClass.getMethod("setBindAddress",
423: parameterTypes);
424: Object[] args = { addr.getHostAddress() };
425: m.invoke(serverSocketFactory, args);
426: } catch (NoSuchMethodException e) {
427: log
428: .warn("Socket factory does not support setBindAddress(String)");
429: // Go with default address
430: } catch (Exception e) {
431: log.warn("Failed to setBindAddress=" + addr
432: + " on socket factory", e);
433: // Go with default address
434: }
435: }
436: }
437: } catch (Exception e) {
438: log.error("operation failed", e);
439: serverSocketFactory = null;
440: }
441: }
442:
443: private class AcceptHandler implements Runnable {
444: public void run() {
445: boolean trace = log.isTraceEnabled();
446: while (serverSocket != null) {
447: Socket socket = null;
448: // Accept a connection
449: try {
450: socket = serverSocket.accept();
451: if (trace)
452: log.trace("Accepted bootstrap client: "
453: + socket);
454: BootstrapRequestHandler handler = new BootstrapRequestHandler(
455: socket);
456: lookupPool.run(handler);
457: } catch (IOException e) {
458: // Stopped by normal means
459: if (serverSocket == null)
460: return;
461: log.error("Naming accept handler stopping", e);
462: } catch (Throwable e) {
463: log.error("Unexpected exception during accept", e);
464: }
465: }
466: }
467: }
468:
469: private class BootstrapRequestHandler implements Runnable {
470: private Socket socket;
471:
472: BootstrapRequestHandler(Socket socket) {
473: this .socket = socket;
474: }
475:
476: public void run() {
477: // Return the naming server stub
478: try {
479: OutputStream os = socket.getOutputStream();
480: ObjectOutputStream out = new ObjectOutputStream(os);
481: out.writeObject(serverStub);
482: out.close();
483: } catch (IOException ex) {
484: log.debug("Error writing response to "
485: + socket.getInetAddress(), ex);
486: } finally {
487: try {
488: socket.close();
489: } catch (IOException e) {
490: }
491: }
492: }
493: }
494: }
|