Package org.jnp.server

Source Code of org.jnp.server.Main$AcceptHandler

/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jnp.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.MarshalledObject;
import java.rmi.Remote;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import javax.net.ServerSocketFactory;

import org.jboss.logging.Logger;
import org.jboss.net.sockets.DefaultSocketFactory;
import org.jboss.util.threadpool.ThreadPool;
import org.jnp.interfaces.MarshalledValuePair;
import org.jnp.interfaces.Naming;

/**
* A main() entry point for running the jnp naming service implementation as
* a standalone process.
*
* @author Rickard Oberg
* @author Scott.Stark@jboss.org
* @version $Revision: 80569 $
*/
public class Main implements MainMBean
{
   // Constants -----------------------------------------------------
  
   // Attributes ----------------------------------------------------
   /** The Naming interface server implementation */
   protected NamingBean theServer;
   protected MarshalledObject serverStub;
   protected boolean isStubExported;
   /** The jnp server socket through which the NamingServer stub is vended */
   protected ServerSocket serverSocket;
   /** An optional custom client socket factory */
   protected RMIClientSocketFactory clientSocketFactory;
   /** An optional custom server socket factory */
   protected RMIServerSocketFactory serverSocketFactory;
   /** An optional custom server socket factory */
   protected ServerSocketFactory jnpServerSocketFactory;
   /** The class name of the optional custom client socket factory */
   protected String clientSocketFactoryName;
   /** The class name of the optional custom server socket factory */
   protected String serverSocketFactoryName;
   /** The class name of the optional custom JNP server socket factory */
   protected String jnpServerSocketFactoryName;
   /** The interface to bind to for the lookup socket. This is useful for
    * multi-homed hosts that want control over which interfaces accept
    * connections */
   protected InetAddress bindAddress;
   /** The interface to bind to for the Naming RMI server */
   protected InetAddress rmiBindAddress;
   /** Should the java.rmi.server.hostname property to rmiBindAddress */
   private boolean enableRmiServerHostname;
   /** The serverSocket listen queue depth */
   protected int backlog = 50;
   /** The jnp protocol listening port. The default is 1099, the same as
    the RMI registry default port. */
   protected int port = 1099;
   /** The RMI port on which the Naming implementation will be exported. The
    default is 0 which means use any available port. */
   protected int rmiPort = 0;
   /** A flag indicating if theServer will be set as the NamingContext.setLocal value */
   protected boolean InstallGlobalService = true;
   /** A flag indicating if theServer will try to use the NamingContext.setLocal value */
   protected boolean UseGlobalService = true;
   protected Logger log;
   /** The thread pool used to handle jnp stub lookup requests */
   private Executor lookupExector;

   // Static --------------------------------------------------------
   public static void main(String[] args)
      throws Exception
   {
      new Main().start();
   }
   // Constructors --------------------------------------------------
   public Main()
   {
      this("org.jboss.naming.Naming");
   }
   public Main(String categoryName)
   {
      // Load properties from properties file
      try
      {
         ClassLoader loader = getClass().getClassLoader();
         InputStream is = loader.getResourceAsStream("jnp.properties");
         System.getProperties().load(is);
      }
      catch (Exception e)
      {
         // Ignore
      }

      // Set configuration from the system properties
      setPort(Integer.getInteger("jnp.port",getPort()).intValue());
      setRmiPort(Integer.getInteger("jnp.rmiPort",getRmiPort()).intValue());
      log = Logger.getLogger(categoryName);
      log.debug("isTraceEnabled: "+log.isTraceEnabled());
   }

   // Public --------------------------------------------------------
   public NamingBean getNamingInfo()
   {
      return theServer;
   }
   /**
    * Set the NamingBean/Naming implementation
    * @param info
    */
   public void setNamingInfo(NamingBean info)
   {
      this.theServer = info;
   }

   @Deprecated
   public void setLookupPool(ThreadPool lookupPool)
   {
      this.lookupExector = new ThreadPoolToExecutor(lookupPool);
   }

   public Executor getLookupExector()
   {
      return lookupExector;
   }
   /**
    * Set the Executor to use for bootstrap socket lookup handling. Note
    * that this must support at least 2 thread to avoid hanging the AcceptHandler
    * accept loop.
    * @param lookupExector - An Executor that supports at least 2 threads
    */
   public void setLookupExector(Executor lookupExector)
   {
      this.lookupExector = lookupExector;
   }

   /** Get the call by value flag for jndi lookups.
    *
    * @return true if all lookups are unmarshalled using the caller's TCL,
    *    false if in VM lookups return the value by reference.
    */
   public boolean getCallByValue()
   {
      return MarshalledValuePair.getEnableCallByReference() == false;
   }
   /** Set the call by value flag for jndi lookups.
    *
    * @param flag - true if all lookups are unmarshalled using the caller's TCL,
    *    false if in VM lookups return the value by reference.
    */
   public void setCallByValue(boolean flag)
   {
      boolean callByValue = ! flag;
      MarshalledValuePair.setEnableCallByReference(callByValue);
   }

   public Object getNamingProxy()
      throws Exception
   {
      return serverStub.get();
   }
   public void setNamingProxy(Object proxy)
      throws IOException
   {
      serverStub = new MarshalledObject(proxy);
   }

   public void setRmiPort(int p)
   {
      rmiPort = p;
   }
   public int getRmiPort()
   {
      return rmiPort;
   }

   public void setPort(int p)
   {
      port = p;
   }
   public int getPort()
   {
      return port;
   }

   public String getBindAddress()
   {
      String address = null;
      if( bindAddress != null )
         address = bindAddress.getHostAddress();
      return address;
   }
   public void setBindAddress(String host) throws UnknownHostException
   {
      if( host == null || host.length() == 0 )
         bindAddress = null;
      else
         bindAddress = InetAddress.getByName(host);
   }

   public String getRmiBindAddress()
   {
      String address = null;
      if( rmiBindAddress != null )
         address = rmiBindAddress.getHostAddress();
      return address;
   }
   public void setRmiBindAddress(String host) throws UnknownHostException
   {
      if( host == null || host.length() == 0 )
         rmiBindAddress = null;
      else
         rmiBindAddress = InetAddress.getByName(host);
   }

  
   public boolean isEnableRmiServerHostname()
   {
      return enableRmiServerHostname;
   }
   public void setEnableRmiServerHostname(boolean enableRmiServerHostname)
   {
      this.enableRmiServerHostname = enableRmiServerHostname;
   }

   public int getBacklog()
   {
      return backlog;
   }
   public void setBacklog(int backlog)
   {
      if( backlog <= 0 )
         backlog = 50;
      this.backlog = backlog;
   }

   public boolean getInstallGlobalService()
   {
      return InstallGlobalService;
   }
   public void setInstallGlobalService(boolean flag)
   {
      this.InstallGlobalService = flag;
   }
   public boolean getUseGlobalService()
   {
      return UseGlobalService;
   }
   public void setUseGlobalService(boolean flag)
   {
      this.UseGlobalService = flag;
   }
  
   public String getClientSocketFactory()
   {
      return clientSocketFactoryName;
   }
   public void setClientSocketFactory(String factoryClassName)
      throws ClassNotFoundException, InstantiationException, IllegalAccessException
   {
      this.clientSocketFactoryName = factoryClassName;
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Class<?> clazz = loader.loadClass(clientSocketFactoryName);
      clientSocketFactory = (RMIClientSocketFactory) clazz.newInstance();
   }
  
   public RMIClientSocketFactory getClientSocketFactoryBean()
   {
      return clientSocketFactory;
   }
   public void setClientSocketFactoryBean(RMIClientSocketFactory factory)
   {
      this.clientSocketFactory = factory;
   }

   public String getServerSocketFactory()
   {
      return serverSocketFactoryName;
   }
   public void setServerSocketFactory(String factoryClassName)
      throws ClassNotFoundException, InstantiationException, IllegalAccessException
   {
      this.serverSocketFactoryName = factoryClassName;
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Class<?> clazz = loader.loadClass(serverSocketFactoryName);
      serverSocketFactory = (RMIServerSocketFactory) clazz.newInstance();
   }

   public RMIServerSocketFactory getServerSocketFactoryBean()
   {
      return serverSocketFactory;
   }
   public void setServerSocketFactoryBean(RMIServerSocketFactory factory)
   {
      this.serverSocketFactory = factory;
   }

   public String getJNPServerSocketFactory()
   {
      return jnpServerSocketFactoryName;
   }
   public void setJNPServerSocketFactory(String factoryClassName)
      throws ClassNotFoundException, InstantiationException, IllegalAccessException
   {
      this.jnpServerSocketFactoryName = factoryClassName;
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Class<?> clazz = loader.loadClass(jnpServerSocketFactoryName);
      jnpServerSocketFactory = (ServerSocketFactory) clazz.newInstance();
   }

   public ServerSocketFactory getJNPServerSocketFactoryBean()
   {
      return jnpServerSocketFactory;
   }
   public void setJNPServerSocketFactoryBean(ServerSocketFactory factory)
   {
      this.jnpServerSocketFactory = factory;
   }

   /**
    * Access the
    */
   public Naming getNamingInstance()
   {
      return theServer.getNamingInstance();
   }

   public void start()
      throws Exception
   {
      log.debug("Begin start");
      // Set the java.rmi.server.hostname to the bind address if not set
      if(rmiBindAddress != null && System.getProperty("java.rmi.server.hostname") == null)
         System.setProperty("java.rmi.server.hostname", rmiBindAddress.getHostAddress());

      // Initialize the custom socket factories with any bind address
      initCustomSocketFactories();
      /* Only export server RMI interface and setup the listening socket if
        the port is >= 0 and an external proxy has not been installed.
        A value < 0 indicates no socket based access
      */
      if( this.serverStub == null && port >= 0 )
      {
         initJnpInvoker();
      }
      // Only bring up the bootstrap listener if there is a naming proxy
      if( this.serverStub != null )
      {
         initBootstrapListener();
      }
      log.debug("End start");
   }

   public void stop()
   {
      try
      {
         // Stop listener and unexport the RMI object
         if( serverSocket != null )
         {
            ServerSocket s = serverSocket;
            serverSocket = null;
            s.close();
         }
         if( isStubExported == true )
            UnicastRemoteObject.unexportObject(theServer.getNamingInstance(), false);
      }
      catch (Exception e)
      {
         log.error("Exception during shutdown", e);
      }
   }

   /** This code should be moved to a seperate invoker in the org.jboss.naming
    *package.
    */
   protected void initJnpInvoker() throws IOException
   {
      log.debug("Creating NamingServer stub, theServer="+theServer
         +",rmiPort="+rmiPort
         +",clientSocketFactory="+clientSocketFactory
         +",serverSocketFactory="+serverSocketFactory);
      Naming instance = getNamingInstance();
      Remote stub = UnicastRemoteObject.exportObject(instance,
            rmiPort, clientSocketFactory, serverSocketFactory);
      log.debug("NamingServer stub: "+stub);
      serverStub = new MarshalledObject(stub);
      isStubExported = true;
   }

   /** Bring up the bootstrap lookup port for obtaining the naming service
    * proxy
    */
   protected void initBootstrapListener()
   {
      // Start listener
      try
      {
         // Get the default ServerSocketFactory is one was not specified
         if( jnpServerSocketFactory == null )
            jnpServerSocketFactory = ServerSocketFactory.getDefault();
         serverSocket = jnpServerSocketFactory.createServerSocket(port, backlog, bindAddress);
         // If an anonymous port was specified get the actual port used
         if( port == 0 )
            port = serverSocket.getLocalPort();
         String msg = "JNDI bootstrap JNP=" + bindAddress + ":" + port
            + ", RMI=" + bindAddress + ":" + rmiPort
            + ", backlog="+backlog;

          if (clientSocketFactory == null)
            msg+= ", no client SocketFactory";
          else
            msg+= ", Client SocketFactory="+clientSocketFactory.toString();

          if (serverSocketFactory == null)
            msg+= ", no server SocketFactory";
          else
            msg+= ", Server SocketFactory="+serverSocketFactory.toString();

         log.debug(msg);
      }
      catch (IOException e)
      {
         log.error("Could not start on port " + port, e);
      }

      if( lookupExector == null  )
      {
         log.debug("Using default newFixedThreadPool(2)");
         lookupExector = Executors.newFixedThreadPool(2, BootstrapThreadFactory.getInstance());
      }
      AcceptHandler handler = new AcceptHandler();
      lookupExector.execute(handler);
   }

   /**
    * Init the clientSocketFactory, serverSocketFactory using the bind address.
    */
   protected void initCustomSocketFactories()
   {
      // Use either the rmiBindAddress or bindAddress for the RMI service
      InetAddress addr = rmiBindAddress != null ? rmiBindAddress : bindAddress;

      if( clientSocketFactory != null && addr != null )
      {
         // See if the client socket supports setBindAddress(String)
         try
         {
            Class<?> csfClass = clientSocketFactory.getClass();
            Class<?>[] parameterTypes = {String.class};
            Method m = csfClass.getMethod("setBindAddress", parameterTypes);
            Object[] args = {addr.getHostAddress()};
            m.invoke(clientSocketFactory, args);
         }
         catch (NoSuchMethodException e)
         {
            log.warn("Socket factory does not support setBindAddress(String)");
            // Go with default address
         }
         catch (Exception e)
         {
            log.warn("Failed to setBindAddress="+addr+" on socket factory", e);
            // Go with default address
         }
      }

      try
      {
         if (serverSocketFactory == null)
            serverSocketFactory = new DefaultSocketFactory(addr);
         else
         {
            if (addr != null)
            {
               // See if the server socket supports setBindAddress(String)
               try
               {
                  Class<?> ssfClass = serverSocketFactory.getClass();
                  Class<?>[] parameterTypes = {String.class};
                  Method m = ssfClass.getMethod("setBindAddress", parameterTypes);
                  Object[] args = {addr.getHostAddress()};
                  m.invoke(serverSocketFactory, args);
               }
               catch (NoSuchMethodException e)
               {
                  log.warn("Socket factory does not support setBindAddress(String)");
                  // Go with default address
               }
               catch (Exception e)
               {
                  log.warn("Failed to setBindAddress="+addr+" on socket factory", e);
                  // Go with default address
               }
            }
         }
      }
      catch (Exception e)
      {
         log.error("operation failed", e);
         serverSocketFactory = null;
      }
   }

   private class AcceptHandler implements Runnable
   {
      public void run()
      {
         boolean trace = log.isTraceEnabled();
         while( serverSocket != null )
         {
            Socket socket = null;
            // Accept a connection
            try
            {
               if( trace )
                  log.trace("Enter accept on: "+serverSocket);
               socket = serverSocket.accept();
               if( trace )
                  log.trace("Accepted bootstrap client: "+socket);
               BootstrapRequestHandler handler = new BootstrapRequestHandler(socket);
               lookupExector.execute(handler);
            }
            catch (IOException e)
            {
               // Stopped by normal means
               if (serverSocket == null)
                  return;
               log.error("Naming accept handler stopping", e);
            }
            catch(Throwable e)
            {
               log.error("Unexpected exception during accept", e);
            }
         }
      }
   }

   private class BootstrapRequestHandler implements Runnable
   {
      private Socket socket;
      BootstrapRequestHandler(Socket socket)
      {
         this.socket = socket;
      }
      public void run()
      {
         // Return the naming server stub
         try
         {
            if(log.isTraceEnabled())
               log.trace("BootstrapRequestHandler.run start");
            OutputStream os = socket.getOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(os);
            out.writeObject(serverStub);
            out.close();
            if(log.isTraceEnabled())
               log.trace("BootstrapRequestHandler.run end");
         }
         catch (IOException ex)
         {
            log.debug("Error writing response to " + socket.getInetAddress(), ex);
         }
         finally
         {
            try
            {
               socket.close();
            } catch (IOException e)
            {
            }
         }
      }
   }
   private static class BootstrapThreadFactory implements ThreadFactory
   {
      private static final AtomicInteger tnumber = new AtomicInteger(1);
      static BootstrapThreadFactory instance;
      static synchronized ThreadFactory getInstance()
      {
         if(instance == null)
            instance = new BootstrapThreadFactory();
         return instance;
      }
      public Thread newThread(Runnable r)
      {
         Thread t = new Thread(r, "Naming Bootstrap#"+tnumber.getAndIncrement());
         return t;
      }
   }
}
TOP

Related Classes of org.jnp.server.Main$AcceptHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.