Save This Page
Home » jnpserver-sources » org.jnp.interfaces » [javadoc | source]
    1   /*
    2     * JBoss, Home of Professional Open Source
    3     * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4     * by the @authors tag. See the copyright.txt in the distribution for a
    5     * full listing of individual contributors.
    6     *
    7     * This is free software; you can redistribute it and/or modify it
    8     * under the terms of the GNU Lesser General Public License as
    9     * published by the Free Software Foundation; either version 2.1 of
   10     * the License, or (at your option) any later version.
   11     *
   12     * This software 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 GNU
   15     * Lesser General Public License for more details.
   16     *
   17     * You should have received a copy of the GNU Lesser General Public
   18     * License along with this software; if not, write to the Free
   19     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21     */
   22   package org.jnp.interfaces;
   23   
   24   import java.io.BufferedInputStream;
   25   import java.io.IOException;
   26   import java.io.ObjectInputStream;
   27   import java.lang.ref.WeakReference;
   28   import java.lang.reflect.Constructor;
   29   import java.lang.reflect.InvocationTargetException;
   30   import java.net.DatagramPacket;
   31   import java.net.InetAddress;
   32   import java.net.MulticastSocket;
   33   import java.net.Socket;
   34   import java.net.InetSocketAddress;
   35   import java.rmi.ConnectException;
   36   import java.rmi.MarshalledObject;
   37   import java.rmi.NoSuchObjectException;
   38   import java.rmi.RemoteException;
   39   import java.security.AccessController;
   40   import java.security.PrivilegedActionException;
   41   import java.security.PrivilegedExceptionAction;
   42   import java.util.ArrayList;
   43   import java.util.Arrays;
   44   import java.util.Collection;
   45   import java.util.Enumeration;
   46   import java.util.Hashtable;
   47   import java.util.Iterator;
   48   import java.util.StringTokenizer;
   49   import java.util.concurrent.ConcurrentHashMap;
   50   
   51   import javax.naming.Binding;
   52   import javax.naming.CannotProceedException;
   53   import javax.naming.CommunicationException;
   54   import javax.naming.ConfigurationException;
   55   import javax.naming.Context;
   56   import javax.naming.InitialContext;
   57   import javax.naming.InvalidNameException;
   58   import javax.naming.LinkRef;
   59   import javax.naming.Name;
   60   import javax.naming.NameParser;
   61   import javax.naming.NamingEnumeration;
   62   import javax.naming.NamingException;
   63   import javax.naming.NotContextException;
   64   import javax.naming.ContextNotEmptyException;
   65   import javax.naming.Reference;
   66   import javax.naming.Referenceable;
   67   import javax.naming.ServiceUnavailableException;
   68   import javax.naming.event.EventContext;
   69   import javax.naming.event.NamingListener;
   70   import javax.naming.spi.NamingManager;
   71   import javax.naming.spi.ResolveResult;
   72   import javax.net.SocketFactory;
   73   
   74   import org.jboss.logging.Logger;
   75   
   76   /**
   77    * This class provides the jnp provider Context implementation. It is a Context
   78    * interface wrapper for a RMI Naming instance that is obtained from either the
   79    * local server instance or by locating the server given by the
   80    * Context.PROVIDER_URL value.
   81    *
   82    * This class also serves as the jnp url resolution context. jnp style urls
   83    * passed to the
   84    * @author oberg
   85    * @author scott.stark@jboss.org
   86    * @version $Revision: 88357 $
   87    */
   88   public class NamingContext
   89      implements EventContext, java.io.Serializable
   90   {
   91      // Constants -----------------------------------------------------
   92      /**
   93       * @since 1.7
   94       */
   95      static final long serialVersionUID = 8906455608484282128L;
   96      /**
   97       * The javax.net.SocketFactory impl to use for the bootstrap socket
   98       */
   99      public static final String JNP_SOCKET_FACTORY = "jnp.socketFactory";
  100      /**
  101       * The local address to bind the connected bootstrap socket to
  102       */
  103      public static final String JNP_LOCAL_ADDRESS = "jnp.localAddress";
  104      /**
  105       * The local port to bind the connected bootstrap socket to
  106       */
  107      public static final String JNP_LOCAL_PORT = "jnp.localPort";
  108      /**
  109       * A flag to disable the broadcast discovery queries
  110       */
  111      public static final String JNP_DISABLE_DISCOVERY = "jnp.disableDiscovery";
  112      /**
  113       * The cluster partition discovery should be restricted to
  114       */
  115      public static final String JNP_PARTITION_NAME = "jnp.partitionName";
  116      /**
  117       * The multicast IP/address to which the discovery query is sent
  118       */
  119      public static final String JNP_DISCOVERY_GROUP = "jnp.discoveryGroup";
  120      /**
  121       * The port to which the discovery query is sent
  122       */
  123      public static final String JNP_DISCOVERY_PORT = "jnp.discoveryPort";
  124   
  125      /** The time-to-live for the multicast discovery packets */
  126      public static final String JNP_DISCOVERY_TTL = "jnp.discoveryTTL";
  127   
  128      /**
  129       * The time in MS to wait for a discovery query response
  130       */
  131      public static final String JNP_DISCOVERY_TIMEOUT = "jnp.discoveryTimeout";
  132      /**
  133       * An internal property added by parseNameForScheme if the input name uses a
  134       * url prefix that was removed during cannonicalization. This is needed to
  135       * avoid modification of the incoming Name.
  136       */
  137      public static final String JNP_PARSED_NAME = "jnp.parsedName";
  138      /**
  139       * A flag indicating the style of names passed to NamingManager method.
  140       * True for api expected relative names, false for absolute names as used
  141       * historically by the jboss naming implementation.
  142       */
  143      public static final String JNP_USE_RELATIVE_NAME = "jnp.useRelativeName";
  144      /**
  145       * An integer that controls the number of connection retry attempts will
  146       * be made on the initial connection to the naming server. This only applies
  147       * to ConnectException failures. A value <= 1 means that only one attempt
  148       * will be made.
  149       */ 
  150      public static final String JNP_MAX_RETRIES = "jnp.maxRetries";
  151      /**
  152       * The Naming instance to use for the root Context creation
  153       */ 
  154      public static final String JNP_NAMING_INSTANCE = "jnp.namingInstance";
  155      /**
  156       * The name to associate with Naming instance to use for the root Context
  157       */ 
  158      public static final String JNP_NAMING_INSTANCE_NAME = "jnp.namingInstanceName";
  159   
  160      /**
  161       * Global JNP disable discovery system property: -Djboss.global.jnp.disableDiscover=[true|false]
  162       * At the VM level, this property controls how disable discovery behaves in 
  163       * absence of per context jnp.disableDiscovery property.  
  164       */
  165      private static final boolean GLOBAL_JNP_DISABLE_DISCOVERY = Boolean.valueOf(System.getProperty("jboss.global.jnp.disableDiscovery", "false"));
  166      
  167      /**
  168       * The default discovery multicast information
  169       */
  170      public final static String DEFAULT_DISCOVERY_GROUP_ADDRESS = "230.0.0.4";
  171      public final static int DEFAULT_DISCOVERY_GROUP_PORT = 1102;
  172      public final static int DEFAULT_DISCOVERY_TIMEOUT = 5000;
  173   
  174      /**
  175       * An obsolete constant replaced by the JNP_MAX_RETRIES value
  176       */
  177      public static int MAX_RETRIES = 1;
  178      /**
  179       * The JBoss logging interface
  180       */
  181      private static Logger log = Logger.getLogger(NamingContext.class);
  182   
  183      // Static --------------------------------------------------------
  184      /** HAJNDI keyed by partition name */
  185      private static Hashtable<String, Naming> haServers = new Hashtable<String, Naming>();
  186      private static RuntimePermission GET_HA_NAMING_SERVER = new RuntimePermission("org.jboss.naming.NamingContext.getHANamingServerForPartition");
  187      private static RuntimePermission SET_HA_NAMING_SERVER = new RuntimePermission("org.jboss.naming.NamingContext.setHANamingServerForPartition");
  188      public static void setHANamingServerForPartition(String partitionName, Naming haServer)
  189      {
  190         SecurityManager security = System.getSecurityManager();
  191         if(security != null)
  192            security.checkPermission(SET_HA_NAMING_SERVER);
  193         haServers.put(partitionName, haServer);
  194      }
  195   
  196      public static void removeHANamingServerForPartition(String partitionName)
  197      {
  198         SecurityManager security = System.getSecurityManager();
  199         if(security != null)
  200            security.checkPermission(SET_HA_NAMING_SERVER);
  201         haServers.remove(partitionName);
  202      }
  203   
  204      public static Naming getHANamingServerForPartition(String partitionName)
  205      {
  206         SecurityManager security = System.getSecurityManager();
  207         if(security != null)
  208            security.checkPermission(GET_HA_NAMING_SERVER);
  209         return (Naming) haServers.get(partitionName);
  210      }
  211   
  212      /**
  213       * The jvm local server used for non-transport access to the naming
  214       * server
  215       * @see #checkRef(Hashtable)
  216       * @see {@linkplain LocalOnlyContextFactory}
  217       */
  218      private static Naming localServer;
  219      private static RuntimePermission GET_LOCAL_SERVER = new RuntimePermission("org.jboss.naming.NamingContext.getLocal");
  220      private static RuntimePermission SET_LOCAL_SERVER = new RuntimePermission("org.jboss.naming.NamingContext.setLocal");
  221      private static int HOST_INDEX = 0;
  222      private static int PORT_INDEX = 1;
  223   
  224      // Attributes ----------------------------------------------------
  225      Naming naming;
  226      Hashtable env;
  227      Name prefix;
  228   
  229      NameParser parser = new NamingParser();
  230      
  231      // Static --------------------------------------------------------
  232      
  233      // Cache of naming server stubs
  234      // This is a critical optimization in the case where new InitialContext
  235      // is performed often. The server stub will be shared between all those
  236      // calls, which will improve performance.
  237      // Weak references are used so if no contexts use a particular server
  238      // it will be removed from the cache.
  239      static ConcurrentHashMap<InetSocketAddress, WeakReference<Naming>> cachedServers
  240         = new ConcurrentHashMap<InetSocketAddress, WeakReference<Naming>>();
  241   
  242      /**
  243       * @deprecated use {@link #addServer(InetSocketAddress, Naming)}
  244       * @param name
  245       * @param server
  246       */
  247      static void addServer(String name, Naming server)
  248      {
  249         Object[] hostAndPort = {name, 0};
  250         parseHostPort(name, hostAndPort, 0);
  251         String host = (String) hostAndPort[HOST_INDEX];
  252         Integer port = (Integer) hostAndPort[PORT_INDEX];
  253         InetSocketAddress addr = new InetSocketAddress(host, port);
  254         addServer(addr, server);
  255      }
  256      static void addServer(InetSocketAddress addr, Naming server)
  257      {
  258         // Add server to map
  259         synchronized (NamingContext.class)
  260         {
  261            WeakReference<Naming> ref = new WeakReference<Naming>(server);
  262            cachedServers.put(addr, ref);
  263         }
  264      }
  265   
  266      static Naming getServer(String host, int port, Hashtable serverEnv)
  267         throws NamingException
  268      {
  269         // Check the server cache for a host:port entry
  270         InetSocketAddress key = new InetSocketAddress(host, port);
  271         WeakReference<Naming> ref = cachedServers.get(key);
  272         Naming server;
  273         if (ref != null)
  274         {
  275            server = (Naming) ref.get();
  276            if (server != null)
  277            {
  278               // JBAS-4622. Ensure the env for the request has the
  279               // hostKey so we can remove the cache entry if there is a failure
  280               serverEnv.put("hostKey", key);
  281               return server;
  282            }
  283         }
  284   
  285         // Server not found; add it to cache
  286         try
  287         {
  288            SocketFactory factory = loadSocketFactory(serverEnv);
  289            Socket s;
  290   
  291            try
  292            {
  293               InetAddress localAddr = null;
  294               int localPort = 0;
  295               String localAddrStr = (String) serverEnv.get(JNP_LOCAL_ADDRESS);
  296               String localPortStr = (String) serverEnv.get(JNP_LOCAL_PORT);
  297               if (localAddrStr != null)
  298                  localAddr = InetAddress.getByName(localAddrStr);
  299               if (localPortStr != null)
  300                  localPort = Integer.parseInt(localPortStr);
  301               s = factory.createSocket(host, port, localAddr, localPort);
  302            }
  303            catch (IOException e)
  304            {
  305               NamingException ex = new ServiceUnavailableException("Failed to connect to server " + key);
  306               ex.setRootCause(e);
  307               throw ex;
  308            }
  309   
  310            // Get stub from naming server
  311            BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
  312            ObjectInputStream in = new ObjectInputStream(bis);
  313            MarshalledObject stub = (MarshalledObject) in.readObject();
  314            server = (Naming) stub.get();
  315            s.close();
  316   
  317            // Add it to cache
  318            addServer(key, server);
  319            serverEnv.put("hostKey", key);
  320   
  321            return server;
  322         }
  323         catch (IOException e)
  324         {
  325            if(log.isTraceEnabled())
  326               log.trace("Failed to retrieve stub from server " + key, e);
  327            NamingException ex = new CommunicationException("Failed to retrieve stub from server " + key);
  328            ex.setRootCause(e);
  329            throw ex;
  330         }
  331         catch (Exception e)
  332         {
  333            if(log.isTraceEnabled())
  334               log.trace("Failed to connect server " + key, e);
  335            NamingException ex = new CommunicationException("Failed to connect to server " + key);
  336            ex.setRootCause(e);
  337            throw ex;
  338         }
  339      }
  340   
  341      /**
  342       * Create a SocketFactory based on the JNP_SOCKET_FACTORY property in the
  343       * given env. If JNP_SOCKET_FACTORY is not specified default to the
  344       * TimedSocketFactory.
  345       */
  346      static SocketFactory loadSocketFactory(Hashtable serverEnv)
  347         throws ClassNotFoundException, IllegalAccessException,
  348         InstantiationException, InvocationTargetException
  349      {
  350         SocketFactory factory = null;
  351   
  352         // Get the socket factory classname
  353         String socketFactoryName = (String) serverEnv.get(JNP_SOCKET_FACTORY);
  354         if (socketFactoryName == null ||
  355            socketFactoryName.equals(TimedSocketFactory.class.getName()))
  356         {
  357            factory = new TimedSocketFactory(serverEnv);
  358            return factory;
  359         }
  360   
  361         /* Create the socket factory. Look for a ctor that accepts a
  362          Hashtable and if not found use the default ctor.
  363          */
  364         ClassLoader loader = Thread.currentThread().getContextClassLoader();
  365         Class factoryClass = loader.loadClass(socketFactoryName);
  366         try
  367         {
  368            Class[] ctorSig = {Hashtable.class};
  369            Constructor ctor = factoryClass.getConstructor(ctorSig);
  370            Object[] ctorArgs = {serverEnv};
  371            factory = (SocketFactory) ctor.newInstance(ctorArgs);
  372         }
  373         catch (NoSuchMethodException e)
  374         {
  375            // Use the default ctor
  376            factory = (SocketFactory) factoryClass.newInstance();
  377         }
  378         return factory;
  379      }
  380   
  381      static void removeServer(Hashtable serverEnv)
  382      {
  383         String host = "localhost";
  384         int port = 1099;
  385         
  386         // Locate naming service
  387         if (serverEnv.get(Context.PROVIDER_URL) != null)
  388         {
  389            String providerURL = (String) serverEnv.get(Context.PROVIDER_URL);
  390   
  391            StringTokenizer tokenizer = new StringTokenizer(providerURL, ", ");
  392            while (tokenizer.hasMoreElements())
  393            {
  394               String url = tokenizer.nextToken();
  395   
  396               try
  397               {
  398                  // Parse the url into a host:port form, stripping any protocol
  399                  Name urlAsName = new NamingParser().parse(url);
  400                  String server = parseNameForScheme(urlAsName, null);
  401                  if (server != null)
  402                     url = server;
  403                  
  404                  Object[] hostAndPort = {url, 1099};
  405                  parseHostPort(url, hostAndPort, 1099);
  406                  host = (String) hostAndPort[HOST_INDEX];
  407                  port = (Integer) hostAndPort[PORT_INDEX];
  408   
  409                  // Remove server from map
  410                  synchronized (NamingContext.class)
  411                  {
  412                     InetSocketAddress key = new InetSocketAddress(host, port);
  413                     cachedServers.remove(key);
  414                  }
  415               }
  416               catch (NamingException ignored)
  417               {
  418               }
  419            }
  420         }
  421         
  422         // JBAS-4622. Always do this.
  423         Object hostKey = serverEnv.remove("hostKey");
  424         if (hostKey != null)
  425         {
  426            synchronized (NamingContext.class)
  427            {
  428               cachedServers.remove(hostKey);
  429            }
  430         }
  431      }
  432   
  433      /**
  434       * Called to remove any url scheme atoms and extract the naming service
  435       * hostname:port information.
  436       * @param n the name component to the parsed. After returning n will have all
  437       * scheme related atoms removed.
  438       * @return the naming service hostname:port information string if name
  439       *         contained the host information.
  440       */
  441      static String parseNameForScheme(Name n, Hashtable nameEnv)
  442         throws InvalidNameException
  443      {
  444         String serverInfo = null;
  445         if (n.size() > 0)
  446         {
  447            String scheme = n.get(0);
  448            int schemeLength = 0;
  449            if (scheme.startsWith("java:"))
  450               schemeLength = 5;
  451            else if (scheme.startsWith("jnp:"))
  452               schemeLength = 4;
  453            else if (scheme.startsWith("jnps:"))
  454               schemeLength = 5;
  455            else if (scheme.startsWith("jnp-http:"))
  456               schemeLength = 9;
  457            else if (scheme.startsWith("jnp-https:"))
  458               schemeLength = 10;
  459            if (schemeLength > 0)
  460            {
  461               // Make a copy of the name to avoid 
  462               n = (Name) n.clone();
  463               String suffix = scheme.substring(schemeLength);
  464               if (suffix.length() == 0)
  465               {
  466                  // Scheme was "url:/..."
  467                  n.remove(0);
  468                  if (n.size() > 1 && n.get(0).equals(""))
  469                  {
  470                     // Scheme was "url://hostname:port/..."
  471                     // Get hostname:port value for the naming server
  472                     serverInfo = n.get(1);
  473                     n.remove(0);
  474                     n.remove(0);
  475                     // If n is a empty atom remove it or else a '/' will result
  476                     if (n.size() == 1 && n.get(0).length() == 0)
  477                        n.remove(0);
  478                  }
  479               }
  480               else
  481               {
  482                  // Scheme was "url:foo" -> reinsert "foo"
  483                  n.remove(0);
  484                  n.add(0, suffix);
  485               }
  486               if (nameEnv != null)
  487                  nameEnv.put(JNP_PARSED_NAME, n);
  488            }
  489         }
  490         return serverInfo;
  491      }
  492   
  493      public static Naming getLocal()
  494      {
  495         SecurityManager security = System.getSecurityManager();
  496         if(security != null)
  497            security.checkPermission(GET_LOCAL_SERVER);
  498         return localServer;
  499      }
  500      public static void setLocal(Naming server)
  501      {
  502         SecurityManager security = System.getSecurityManager();
  503         if(security != null)
  504            security.checkPermission(SET_LOCAL_SERVER);
  505         localServer = server;
  506      }
  507   
  508      // Constructors --------------------------------------------------
  509      public NamingContext(Hashtable e, Name baseName, Naming server)
  510         throws NamingException
  511      {
  512         if (baseName == null)
  513            this.prefix = parser.parse("");
  514         else
  515            this.prefix = baseName;
  516   
  517         if (e != null)
  518            this.env = (Hashtable) e.clone();
  519         else
  520            this.env = new Hashtable();
  521   
  522         this.naming = server;
  523      }
  524   
  525      // Public --------------------------------------------------------
  526      public Naming getNaming()
  527      {
  528         return this.naming;
  529      }
  530   
  531      public void setNaming(Naming server)
  532      {
  533         this.naming = server;
  534      }
  535   
  536      // Context implementation ----------------------------------------
  537      public void rebind(String name, Object obj)
  538         throws NamingException
  539      {
  540         rebind(getNameParser(name).parse(name), obj);
  541      }
  542   
  543      public void rebind(Name name, Object obj)
  544         throws NamingException
  545      {
  546         Hashtable refEnv = getEnv(name);
  547         checkRef(refEnv);
  548         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  549         if (parsedName != null)
  550            name = parsedName;
  551   
  552         // Allow state factories to change the stored object
  553         obj = getStateToBind(obj, name, refEnv);
  554   
  555         try
  556         {
  557            String className = null;
  558            
  559            // Referenceable
  560            if (obj instanceof Referenceable)
  561               obj = ((Referenceable) obj).getReference();
  562   
  563            if (!(obj instanceof Reference))
  564            {
  565               if( obj != null )
  566                  className = obj.getClass().getName();
  567               obj = createMarshalledValuePair(obj);
  568            }
  569            else
  570            {
  571               className = ((Reference) obj).getClassName();
  572            }
  573            try
  574            {
  575               naming.rebind(getAbsoluteName(name), obj, className);
  576            }
  577            catch (RemoteException re)
  578            {
  579               // Check for JBAS-4574.
  580               if (handleStaleNamingStub(re, refEnv))
  581               {
  582                  // try again with new naming stub                  
  583                  naming.rebind(getAbsoluteName(name), obj, className);
  584               }
  585               else
  586               {
  587                  // Not JBAS-4574. Throw exception and let outer logic handle it.
  588                  throw re;
  589               }            
  590            }
  591         }
  592         catch (CannotProceedException cpe)
  593         {
  594            cpe.setEnvironment(refEnv);
  595            Context cctx = NamingManager.getContinuationContext(cpe);
  596            cctx.rebind(cpe.getRemainingName(), obj);
  597         }
  598         catch (IOException e)
  599         {
  600            naming = null;
  601            removeServer(refEnv);
  602            NamingException ex = new CommunicationException();
  603            ex.setRootCause(e);
  604            throw ex;
  605         }
  606      }
  607   
  608      public void bind(String name, Object obj)
  609         throws NamingException
  610      {
  611         bind(getNameParser(name).parse(name), obj);
  612      }
  613   
  614      public void bind(Name name, Object obj)
  615         throws NamingException
  616      {
  617         Hashtable refEnv = getEnv(name);
  618         checkRef(refEnv);
  619         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  620         if (parsedName != null)
  621            name = parsedName;
  622   
  623         // Allow state factories to change the stored object
  624         obj = getStateToBind(obj, name, refEnv);
  625   
  626         try
  627         {
  628            String className = null;
  629            
  630            // Referenceable
  631            if (obj instanceof Referenceable)
  632               obj = ((Referenceable) obj).getReference();
  633   
  634            if (!(obj instanceof Reference))
  635            {
  636               if( obj != null )
  637                  className = obj.getClass().getName();
  638   
  639               // Normal object - serialize using a MarshalledValuePair
  640               obj = createMarshalledValuePair(obj);
  641            }
  642            else
  643            {
  644               className = ((Reference) obj).getClassName();
  645            }
  646            name = getAbsoluteName(name);
  647            
  648            try
  649            {
  650               naming.bind(name, obj, className);
  651            }
  652            catch (RemoteException re)
  653            {
  654               // Check for JBAS-4574.
  655               if (handleStaleNamingStub(re, refEnv))
  656               {
  657                  // try again with new naming stub                  
  658                  naming.bind(name, obj, className);
  659               }
  660               else
  661               {
  662                  // Not JBAS-4574. Throw exception and let outer logic handle it.
  663                  throw re;
  664               }            
  665            }
  666         }
  667         catch (CannotProceedException cpe)
  668         {
  669            cpe.setEnvironment(refEnv);
  670            Context cctx = NamingManager.getContinuationContext(cpe);
  671            cctx.bind(cpe.getRemainingName(), obj);
  672         }
  673         catch (IOException e)
  674         {
  675            naming = null;
  676            removeServer(refEnv);
  677            NamingException ex = new CommunicationException();
  678            ex.setRootCause(e);
  679            throw ex;
  680         }
  681      }
  682   
  683      public Object lookup(String name)
  684         throws NamingException
  685      {
  686         return lookup(getNameParser(name).parse(name));
  687      }
  688   
  689      public Object lookup(Name name)
  690         throws NamingException
  691      {
  692         Hashtable refEnv = getEnv(name);
  693         checkRef(refEnv);
  694         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  695         if (parsedName != null)
  696            name = parsedName;
  697   
  698         // Empty?
  699         if (name.isEmpty())
  700            return new NamingContext(refEnv, prefix, naming);
  701   
  702         try
  703         {
  704            int maxTries = 1;
  705            try
  706            {
  707               String n = (String) refEnv.get(JNP_MAX_RETRIES);
  708               if( n != null )
  709                  maxTries = Integer.parseInt(n);
  710               if( maxTries <= 0 )
  711                  maxTries = 1;
  712            }
  713            catch(Exception e)
  714            {
  715               log.debug("Failed to get JNP_MAX_RETRIES, using 1", e);
  716            }
  717            Name n = getAbsoluteName(name);
  718            Object res = null;
  719            boolean trace = log.isTraceEnabled();
  720            for (int i = 0; i < maxTries; i++)
  721            {
  722               try
  723               {
  724                  try
  725                  {
  726                     res = naming.lookup(n);
  727                  }
  728                  catch (RemoteException re)
  729                  {
  730                     // Check for JBAS-4574.
  731                     if (handleStaleNamingStub(re, refEnv))
  732                     {
  733                        // try again with new naming stub                  
  734                        res = naming.lookup(n);
  735                     }
  736                     else
  737                     {
  738                        // Not JBAS-4574. Throw exception and let outer logic handle it.
  739                        throw re;
  740                     }
  741                  }
  742                  // If we got here, we succeeded, so break the loop
  743                  break;
  744               }
  745               catch (ConnectException ce)
  746               {
  747                  int retries = maxTries - i - 1;
  748                  if( trace )
  749                     log.trace("Connect failed, retry count: "+retries, ce);
  750                  // We may overload server so sleep and retry
  751                  if (retries > 0)
  752                  {
  753                     try
  754                     {
  755                        Thread.sleep(1);
  756                     }
  757                     catch (InterruptedException ignored)
  758                     {
  759                     }
  760                     continue;
  761                  }
  762                  // Throw the exception to flush the bad server
  763                  throw ce;
  764               }
  765            }
  766            if (res instanceof MarshalledValuePair)
  767            {
  768               MarshalledValuePair mvp = (MarshalledValuePair) res;
  769               Object storedObj = mvp.get();
  770               return getObjectInstanceWrapFailure(storedObj, name, refEnv);
  771            }
  772            else if (res instanceof MarshalledObject)
  773            {
  774               MarshalledObject mo = (MarshalledObject) res;
  775               return mo.get();
  776            }
  777            else if (res instanceof Context)
  778            {
  779               // Add env
  780               Enumeration keys = refEnv.keys();
  781               while (keys.hasMoreElements())
  782               {
  783                  String key = (String) keys.nextElement();
  784                  ((Context) res).addToEnvironment(key, refEnv.get(key));
  785               }
  786               return res;
  787            }
  788            else if (res instanceof ResolveResult)
  789            {
  790               // Dereference partial result
  791               ResolveResult rr = (ResolveResult) res;
  792               Object resolveRes = rr.getResolvedObj();
  793               Object context;
  794               Object instanceID;
  795   
  796               if (resolveRes instanceof LinkRef)
  797               {
  798                  context = resolveLink(resolveRes, null);
  799                  instanceID = ((LinkRef) resolveRes).getLinkName();
  800               }
  801               else
  802               {
  803                  context = getObjectInstanceWrapFailure(resolveRes, name, refEnv);
  804                  instanceID = context;
  805               }
  806   
  807               if ((context instanceof Context) == false)
  808               {
  809                  throw new NotContextException(instanceID + " is not a Context");
  810               }
  811               Context ncontext = (Context) context;
  812               return ncontext.lookup(rr.getRemainingName());
  813            }
  814            else if (res instanceof LinkRef)
  815            {
  816               // Dereference link
  817               res = resolveLink(res, refEnv);
  818            }
  819            else if (res instanceof Reference)
  820            {
  821               // Dereference object
  822               res = getObjectInstanceWrapFailure(res, name, refEnv);
  823               if (res instanceof LinkRef)
  824                  res = resolveLink(res, refEnv);
  825            }
  826   
  827            return res;
  828         }
  829         catch (CannotProceedException cpe)
  830         {
  831            cpe.setEnvironment(refEnv);
  832            Context cctx = NamingManager.getContinuationContext(cpe);
  833            return cctx.lookup(cpe.getRemainingName());
  834         }
  835         catch (IOException e)
  836         {
  837            naming = null;
  838            removeServer(refEnv);
  839            NamingException ex = new CommunicationException();
  840            ex.setRootCause(e);
  841            throw ex;
  842         }
  843         catch (ClassNotFoundException e)
  844         {
  845            NamingException ex = new CommunicationException();
  846            ex.setRootCause(e);
  847            throw ex;
  848         }
  849      }
  850   
  851      public void unbind(String name)
  852         throws NamingException
  853      {
  854         unbind(getNameParser(name).parse(name));
  855      }
  856   
  857   
  858      public void unbind(Name name)
  859         throws NamingException
  860      {
  861         Hashtable refEnv = getEnv(name);
  862         checkRef(refEnv);
  863         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  864         if (parsedName != null)
  865            name = parsedName;
  866   
  867         try
  868         {
  869            try
  870            {
  871               naming.unbind(getAbsoluteName(name));
  872            }
  873            catch (RemoteException re)
  874            {
  875               // Check for JBAS-4574.
  876               if (handleStaleNamingStub(re, refEnv))
  877               {
  878                  // try again with new naming stub                  
  879                  naming.unbind(getAbsoluteName(name));
  880               }
  881               else
  882               {
  883                  // Not JBAS-4574. Throw exception and let outer logic handle it.
  884                  throw re;
  885               }             
  886            }
  887         }
  888         catch (CannotProceedException cpe)
  889         {
  890            cpe.setEnvironment(refEnv);
  891            Context cctx = NamingManager.getContinuationContext(cpe);
  892            cctx.unbind(cpe.getRemainingName());
  893         }
  894         catch (IOException e)
  895         {
  896            naming = null;
  897            removeServer(refEnv);
  898            NamingException ex = new CommunicationException();
  899            ex.setRootCause(e);
  900            throw ex;
  901         }
  902      }
  903   
  904      public void rename(String oldname, String newname)
  905         throws NamingException
  906      {
  907         rename(getNameParser(oldname).parse(oldname), getNameParser(newname).parse(newname));
  908      }
  909   
  910      public void rename(Name oldName, Name newName)
  911         throws NamingException
  912      {
  913         bind(newName, lookup(oldName));
  914         unbind(oldName);
  915      }
  916   
  917      public NamingEnumeration list(String name)
  918         throws NamingException
  919      {
  920         return list(getNameParser(name).parse(name));
  921      }
  922   
  923      public NamingEnumeration list(Name name)
  924         throws NamingException
  925      {
  926         Hashtable refEnv = getEnv(name);
  927         checkRef(refEnv);
  928         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  929         if (parsedName != null)
  930            name = parsedName;
  931   
  932         try
  933         {
  934            Collection c = null;
  935            try
  936            {
  937               c = naming.list(getAbsoluteName(name));
  938            }
  939            catch (RemoteException re)
  940            {
  941               // Check for JBAS-4574.
  942               if (handleStaleNamingStub(re, refEnv))
  943               {
  944                  // try again with new naming stub                  
  945                  c = naming.list(getAbsoluteName(name));
  946               }
  947               else
  948               {
  949                  // Not JBAS-4574. Throw exception and let outer logic handle it.
  950                  throw re;
  951               }            
  952            }
  953            return new NamingEnumerationImpl(c);
  954         }
  955         catch (CannotProceedException cpe)
  956         {
  957            cpe.setEnvironment(refEnv);
  958            Context cctx = NamingManager.getContinuationContext(cpe);
  959            return cctx.list(cpe.getRemainingName());
  960         }
  961         catch (IOException e)
  962         {
  963            naming = null;
  964            removeServer(refEnv);
  965            NamingException ex = new CommunicationException();
  966            ex.setRootCause(e);
  967            throw ex;
  968         }
  969      }
  970   
  971      public NamingEnumeration listBindings(String name)
  972         throws NamingException
  973      {
  974         return listBindings(getNameParser(name).parse(name));
  975      }
  976   
  977      public NamingEnumeration listBindings(Name name)
  978         throws NamingException
  979      {
  980         Hashtable refEnv = getEnv(name);
  981         checkRef(refEnv);
  982         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
  983         if (parsedName != null)
  984            name = parsedName;
  985   
  986         try
  987         {
  988            // Get list
  989            Collection bindings = null;
  990            try
  991            {
  992               // Get list
  993               bindings = naming.listBindings(getAbsoluteName(name));
  994            }
  995            catch (RemoteException re)
  996            {
  997               // Check for JBAS-4574.
  998               if (handleStaleNamingStub(re, refEnv))
  999               {
 1000                  // try again with new naming stub                  
 1001                  bindings = naming.listBindings(getAbsoluteName(name));
 1002               }
 1003               else
 1004               {
 1005                  // Not JBAS-4574. Throw exception and let outer logic handle it.
 1006                  throw re;
 1007               }            
 1008            }
 1009            Collection realBindings = new ArrayList(bindings.size());
 1010            
 1011            // Convert marshalled objects
 1012            Iterator i = bindings.iterator();
 1013            while (i.hasNext())
 1014            {
 1015               Binding binding = (Binding) i.next();
 1016               Object obj = binding.getObject();
 1017               if (obj instanceof MarshalledValuePair)
 1018               {
 1019                  try
 1020                  {
 1021                     obj = ((MarshalledValuePair) obj).get();
 1022                  }
 1023                  catch (ClassNotFoundException e)
 1024                  {
 1025                     NamingException ex = new CommunicationException();
 1026                     ex.setRootCause(e);
 1027                     throw ex;
 1028                  }
 1029               }
 1030               else if (obj instanceof MarshalledObject)
 1031               {
 1032                  try
 1033                  {
 1034                     obj = ((MarshalledObject) obj).get();
 1035                  }
 1036                  catch (ClassNotFoundException e)
 1037                  {
 1038                     NamingException ex = new CommunicationException();
 1039                     ex.setRootCause(e);
 1040                     throw ex;
 1041                  }
 1042               }
 1043               realBindings.add(new Binding(binding.getName(), binding.getClassName(), obj));
 1044            }
 1045            
 1046            // Return transformed list of bindings
 1047            return new NamingEnumerationImpl(realBindings);
 1048         }
 1049         catch (CannotProceedException cpe)
 1050         {
 1051            cpe.setEnvironment(refEnv);
 1052            Context cctx = NamingManager.getContinuationContext(cpe);
 1053            return cctx.listBindings(cpe.getRemainingName());
 1054         }
 1055         catch (IOException e)
 1056         {
 1057            naming = null;
 1058            removeServer(refEnv);
 1059            NamingException ex = new CommunicationException();
 1060            ex.setRootCause(e);
 1061            throw ex;
 1062         }
 1063      }
 1064   
 1065      public String composeName(String name, String prefix)
 1066         throws NamingException
 1067      {
 1068         Name result = composeName(parser.parse(name),
 1069            parser.parse(prefix));
 1070         return result.toString();
 1071      }
 1072   
 1073      public Name composeName(Name name, Name prefix)
 1074         throws NamingException
 1075      {
 1076         Name result = (Name) (prefix.clone());
 1077         result.addAll(name);
 1078         return result;
 1079      }
 1080   
 1081      public NameParser getNameParser(String name)
 1082         throws NamingException
 1083      {
 1084         return parser;
 1085      }
 1086   
 1087      public NameParser getNameParser(Name name)
 1088         throws NamingException
 1089      {
 1090         return getNameParser(name.toString());
 1091      }
 1092   
 1093      public Context createSubcontext(String name)
 1094         throws NamingException
 1095      {
 1096         return createSubcontext(getNameParser(name).parse(name));
 1097      }
 1098   
 1099      public Context createSubcontext(Name name)
 1100         throws NamingException
 1101      {
 1102         if (name.size() == 0)
 1103            throw new InvalidNameException("Cannot pass an empty name to createSubcontext");
 1104   
 1105         Hashtable refEnv = getEnv(name);
 1106         checkRef(refEnv);
 1107         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
 1108         if (parsedName != null)
 1109            name = parsedName;
 1110   
 1111         try
 1112         {
 1113            name = getAbsoluteName(name);
 1114            try
 1115            {
 1116               return naming.createSubcontext(name);
 1117            }
 1118            catch (RemoteException re)
 1119            {
 1120               // Check for JBAS-4574.
 1121               if (handleStaleNamingStub(re, refEnv))
 1122               {
 1123                  // try again with new naming stub                  
 1124                  return naming.createSubcontext(name);
 1125               }
 1126               else
 1127               {
 1128                  // Not JBAS-4574. Throw exception and let outer logic handle it.
 1129                  throw re;
 1130               }            
 1131            }
 1132         }
 1133         catch (CannotProceedException cpe)
 1134         {
 1135            cpe.setEnvironment(refEnv);
 1136            Context cctx = NamingManager.getContinuationContext(cpe);
 1137            return cctx.createSubcontext(cpe.getRemainingName());
 1138         }
 1139         catch (IOException e)
 1140         {
 1141            naming = null;
 1142            removeServer(refEnv);
 1143            NamingException ex = new CommunicationException();
 1144            ex.setRootCause(e);
 1145            throw ex;
 1146         }
 1147      }
 1148   
 1149      public Object addToEnvironment(String propName, Object propVal)
 1150         throws NamingException
 1151      {
 1152         Object old = env.get(propName);
 1153         env.put(propName, propVal);
 1154         return old;
 1155      }
 1156   
 1157      public Object removeFromEnvironment(String propName)
 1158         throws NamingException
 1159      {
 1160         return env.remove(propName);
 1161      }
 1162   
 1163      public Hashtable getEnvironment()
 1164         throws NamingException
 1165      {
 1166         return env;
 1167      }
 1168   
 1169      public void close()
 1170         throws NamingException
 1171      {
 1172         env = null;
 1173         naming = null;
 1174      }
 1175   
 1176      public String getNameInNamespace()
 1177         throws NamingException
 1178      {
 1179         return prefix.toString();
 1180      }
 1181   
 1182      public void destroySubcontext(String name)
 1183         throws NamingException
 1184      {
 1185         destroySubcontext(getNameParser(name).parse(name));
 1186      }
 1187   
 1188      public void destroySubcontext(Name name)
 1189         throws NamingException
 1190      {
 1191         if (!list(name).hasMore())
 1192         {
 1193            unbind(name);
 1194         }
 1195         else
 1196            throw new ContextNotEmptyException();
 1197      }
 1198   
 1199      public Object lookupLink(String name)
 1200         throws NamingException
 1201      {
 1202         return lookupLink(getNameParser(name).parse(name));
 1203      }
 1204   
 1205      /**
 1206       * Lookup the object referred to by name but don't dereferrence the final
 1207       * component. This really just involves returning the raw value returned by
 1208       * the Naming.lookup() method.
 1209       * @return the raw object bound under name.
 1210       */
 1211      public Object lookupLink(Name name)
 1212         throws NamingException
 1213      {
 1214         Hashtable refEnv = getEnv(name);
 1215         checkRef(refEnv);
 1216         Name parsedName = (Name) refEnv.get(JNP_PARSED_NAME);
 1217         if (parsedName != null)
 1218            name = parsedName;
 1219   
 1220         if (name.isEmpty())
 1221            return lookup(name);
 1222   
 1223         Object link = null;
 1224         try
 1225         {
 1226            Name n = getAbsoluteName(name);
 1227            try
 1228            {
 1229               link = naming.lookup(n);
 1230            }
 1231            catch (RemoteException re)
 1232            {
 1233               // Check for JBAS-4574.
 1234               if (handleStaleNamingStub(re, refEnv))
 1235               {
 1236                  // try again with new naming stub                  
 1237                  link = naming.lookup(n);
 1238               }
 1239               else
 1240               {
 1241                  // Not JBAS-4574. Throw exception and let outer logic handle it.
 1242                  throw re;
 1243               }            
 1244            }
 1245            if (!(link instanceof LinkRef) && link instanceof Reference)
 1246               link = getObjectInstance(link, name, null);
 1247            ;
 1248         }
 1249         catch (IOException e)
 1250         {
 1251            naming = null;
 1252            removeServer(refEnv);
 1253            NamingException ex = new CommunicationException();
 1254            ex.setRootCause(e);
 1255            throw ex;
 1256         }
 1257         catch (Exception e)
 1258         {
 1259            NamingException ex = new NamingException("Could not lookup link");
 1260            ex.setRemainingName(name);
 1261            ex.setRootCause(e);
 1262            throw ex;
 1263         }
 1264         return link;
 1265      }
 1266   
 1267      // Begin EventContext methods
 1268      public void addNamingListener(Name target, int scope, NamingListener l)
 1269         throws NamingException
 1270      {
 1271         if((naming instanceof NamingEvents) == false)
 1272         {
 1273            throw new UnsupportedOperationException("Naming implementation does not support NamingExt");
 1274         }
 1275         NamingEvents next = (NamingEvents) naming;
 1276         try
 1277         {
 1278            next.addNamingListener(this, target, scope, l);
 1279         }
 1280         catch (RemoteException e)
 1281         {
 1282            CommunicationException ce = new CommunicationException("addNamingListener failed");
 1283            ce.initCause(e);
 1284         }
 1285      }
 1286   
 1287      public void addNamingListener(String target, int scope, NamingListener l)
 1288         throws NamingException
 1289      {
 1290         Name targetName = parser.parse(target);
 1291         addNamingListener(targetName, scope, l);
 1292      }
 1293   
 1294      public void removeNamingListener(NamingListener l)
 1295         throws NamingException
 1296      {
 1297         if((naming instanceof NamingEvents) == false)
 1298         {
 1299            throw new UnsupportedOperationException("Naming implementation does not support NamingExt");
 1300         }
 1301         NamingEvents next = (NamingEvents) naming;
 1302         try
 1303         {
 1304            next.removeNamingListener(l);
 1305         }
 1306         catch (RemoteException e)
 1307         {
 1308            CommunicationException ce = new CommunicationException("removeNamingListener failed");
 1309            ce.initCause(e);
 1310         }
 1311      }
 1312   
 1313      public boolean targetMustExist()
 1314         throws NamingException
 1315      {
 1316         if((naming instanceof NamingEvents) == false)
 1317         {
 1318            throw new UnsupportedOperationException("Naming implementation does not support NamingExt");
 1319         }
 1320         NamingEvents next = (NamingEvents) naming;
 1321         boolean targetMustExist = true;
 1322         try
 1323         {
 1324            targetMustExist = next.targetMustExist();
 1325         }
 1326         catch (RemoteException e)
 1327         {
 1328            CommunicationException ce = new CommunicationException("removeNamingListener failed");
 1329            ce.initCause(e);
 1330         }
 1331         return targetMustExist;
 1332      }
 1333      // End EventContext methods
 1334   
 1335      protected Object resolveLink(Object res, Hashtable refEnv)
 1336         throws NamingException
 1337      {
 1338         Object linkResult = null;
 1339         try
 1340         {
 1341            LinkRef link = (LinkRef) res;
 1342            String ref = link.getLinkName();
 1343            if (ref.startsWith("./"))
 1344               linkResult = lookup(ref.substring(2));
 1345            else if (refEnv != null)
 1346               linkResult = new InitialContext(refEnv).lookup(ref);
 1347            else
 1348               linkResult = new InitialContext().lookup(ref);
 1349         }
 1350         catch (Exception e)
 1351         {
 1352            NamingException ex = new NamingException("Could not dereference object");
 1353            ex.setRootCause(e);
 1354            throw ex;
 1355         }
 1356         return linkResult;
 1357      }
 1358      
 1359      protected boolean shouldDiscoveryHappen(boolean globalDisableDiscovery, String perCtxDisableDiscovery)
 1360      {
 1361         boolean trace = log.isTraceEnabled();
 1362         if (!globalDisableDiscovery)
 1363         {
 1364            // No global disable, so act as before.
 1365            if (Boolean.valueOf(perCtxDisableDiscovery) == Boolean.TRUE)
 1366            {
 1367               if (trace)
 1368                  log.trace("Skipping discovery due to disable flag in context");
 1369               return false;
 1370            }         
 1371         }
 1372         else
 1373         {
 1374            // Global disable on but double check whether there's a per context override.
 1375            // If disableDiscovery in context is explicitly set to false, do discovery.
 1376            if (perCtxDisableDiscovery == null || Boolean.valueOf(perCtxDisableDiscovery) == Boolean.TRUE)
 1377            {
 1378               if (trace)
 1379                  log.trace("Skipping discovery due to disable flag in context, or disable flag globally (and no override in context)");
 1380               return false;            
 1381            }
 1382         }
 1383         
 1384         return true;
 1385      }
 1386   
 1387      // Private -------------------------------------------------------
 1388   
 1389      /**
 1390       * Isolate the creation of the MarshalledValuePair in a privileged block
 1391       * when running under a security manager so the following permissions can
 1392       * be isolated from the caller:
 1393       * RuntimePermission("createClassLoader")
 1394         ReflectPermission("suppressAccessChecks")
 1395         SerializablePermission("enableSubstitution")
 1396         @return the MarshalledValuePair wrapping obj
 1397       */
 1398      private Object createMarshalledValuePair(final Object obj)
 1399         throws IOException
 1400      {
 1401         MarshalledValuePair mvp = null;
 1402         SecurityManager sm = System.getSecurityManager();
 1403         if(sm != null)
 1404         {
 1405            try
 1406            {
 1407               mvp = AccessController.doPrivileged(new PrivilegedExceptionAction<MarshalledValuePair>()
 1408               {
 1409                  public MarshalledValuePair run() throws Exception
 1410                  {
 1411                     return new MarshalledValuePair(obj);
 1412                  }
 1413               }
 1414               );
 1415            }
 1416            catch(PrivilegedActionException e)
 1417            {
 1418               IOException ioe = new IOException();
 1419               ioe.initCause(e.getException());
 1420               throw ioe;
 1421            }
 1422         }
 1423         else
 1424         {
 1425            mvp = new MarshalledValuePair(obj);
 1426         }
 1427         return mvp;
 1428      }
 1429   
 1430      /**
 1431       * Determine the form of the name to pass to the NamingManager operations.
 1432       * This is supposed to be a context relative name according to the javaodcs
 1433       * for NamingManager, but historically the absolute name of the target
 1434       * context has been passed in. 
 1435       * 
 1436       * @param env - the env of NamingContext that op was called on
 1437       * @return true if the legacy and technically incorrect absolute name should
 1438       * be used, false if the context relative name should be used.
 1439       */ 
 1440      private boolean useAbsoluteName(Hashtable env)
 1441      {
 1442         if (env == null)
 1443            return true;
 1444         String useRelativeName = (String) env.get(JNP_USE_RELATIVE_NAME);
 1445         return Boolean.valueOf(useRelativeName) == Boolean.FALSE;
 1446      }
 1447   
 1448      /**
 1449       * Use the NamingManager.getStateToBind to obtain the actual object to bind
 1450       * into jndi.
 1451       * @param obj - the value passed to bind/rebind
 1452       * @param name - the name passed to bind/rebind
 1453       * @param env - the env of NamingContext that bind/rebind was called on
 1454       * @return the object to bind to the naming server
 1455       * @throws NamingException
 1456       */
 1457      private Object getStateToBind(Object obj, Name name, Hashtable env)
 1458         throws NamingException
 1459      {
 1460         if (useAbsoluteName(env))
 1461            name = getAbsoluteName(name);
 1462         return NamingManager.getStateToBind(obj, name, this, env);
 1463      }
 1464   
 1465      /**
 1466       * Use the NamingManager.getObjectInstance to resolve the raw object obtained
 1467       * from the naming server.
 1468       * @param obj - raw value obtained from the naming server
 1469       * @param name - the name passed to the lookup op
 1470       * @param env - the env of NamingContext that the op was called on
 1471       * @return the fully resolved object
 1472       * @throws Exception
 1473       */
 1474      private Object getObjectInstance(Object obj, Name name, Hashtable env)
 1475         throws Exception
 1476      {
 1477         if (useAbsoluteName(env))
 1478            name = getAbsoluteName(name);
 1479         return NamingManager.getObjectInstance(obj, name, this, env);
 1480      }
 1481   
 1482      /**
 1483       * Resolve the final object and wrap any non-NamingException errors in a
 1484       * NamingException with the cause passed as the root cause.
 1485       * @param obj - raw value obtained from the naming server
 1486       * @param name - the name passed to the lookup op
 1487       * @param env - the env of NamingContext that the op was called on
 1488       * @return the fully resolved object
 1489       * @throws NamingException
 1490       */
 1491      private Object getObjectInstanceWrapFailure(Object obj, Name name, Hashtable env)
 1492         throws NamingException
 1493      {
 1494         try
 1495         {
 1496            return getObjectInstance(obj, name, env);
 1497         }
 1498         catch (NamingException e)
 1499         {
 1500            throw e;
 1501         }
 1502         catch (Exception e)
 1503         {
 1504            NamingException ex = new NamingException("Could not dereference object");
 1505            ex.setRootCause(e);
 1506            throw ex;
 1507         }
 1508      }
 1509   
 1510      /**
 1511       * This methods sends a broadcast message on the network and asks and HA-JNDI
 1512       * server to sent it the HA-JNDI stub
 1513       */
 1514      private Naming discoverServer(Hashtable serverEnv) throws NamingException
 1515      {
 1516         boolean trace = log.isTraceEnabled();
 1517         // Check if discovery should be done
 1518         String disableDiscovery = (String) serverEnv.get(JNP_DISABLE_DISCOVERY);
 1519         
 1520         if (!shouldDiscoveryHappen(GLOBAL_JNP_DISABLE_DISCOVERY, disableDiscovery))
 1521         {
 1522            return null;
 1523         }
 1524         
 1525         if (Boolean.valueOf(disableDiscovery) == Boolean.TRUE)
 1526         {
 1527            if (trace)
 1528               log.trace("Skipping discovery due to disable flag");
 1529            return null;
 1530         }
 1531         
 1532         // we first try to discover the server locally
 1533         //
 1534         String partitionName = (String) serverEnv.get(JNP_PARTITION_NAME);
 1535         Naming server = null;
 1536         if (partitionName != null)
 1537         {
 1538            server = getHANamingServerForPartition(partitionName);
 1539            if (server != null)
 1540               return server;
 1541         }
 1542         
 1543         // We next broadcast a HelloWorld datagram (multicast)
 1544         // Any listening server will answer with its IP address:port in another datagram
 1545         // we will then use this to make a standard "lookup"
 1546         //
 1547         MulticastSocket s = null;
 1548         InetAddress iaGroup = null;
 1549         try
 1550         {
 1551            String group = DEFAULT_DISCOVERY_GROUP_ADDRESS;
 1552            int port = DEFAULT_DISCOVERY_GROUP_PORT;
 1553            int timeout = DEFAULT_DISCOVERY_TIMEOUT;
 1554            int ttl = 16;
 1555   
 1556            String discoveryGroup = (String) serverEnv.get(JNP_DISCOVERY_GROUP);
 1557            if (discoveryGroup != null)
 1558               group = discoveryGroup;
 1559   
 1560            String discoveryTTL = (String) serverEnv.get(JNP_DISCOVERY_TTL);
 1561            if(discoveryTTL != null)
 1562               ttl = Integer.parseInt(discoveryTTL);
 1563   
 1564            String discoveryTimeout = (String) serverEnv.get(JNP_DISCOVERY_TIMEOUT);
 1565            if (discoveryTimeout == null)
 1566            {
 1567               // Check the old property name
 1568               discoveryTimeout = (String) serverEnv.get("DISCOVERY_TIMEOUT");
 1569            }
 1570            if (discoveryTimeout != null && !discoveryTimeout.equals(""))
 1571               timeout = Integer.parseInt(discoveryTimeout);
 1572   
 1573            String discoveryGroupPort = (String) serverEnv.get(JNP_DISCOVERY_PORT);
 1574            if (discoveryGroupPort == null)
 1575            {
 1576               // Check the old property name
 1577               discoveryGroupPort = (String) serverEnv.get("DISCOVERY_GROUP");
 1578            }
 1579            if (discoveryGroupPort != null && !discoveryGroupPort.equals(""))
 1580            {
 1581               int colon = discoveryGroupPort.indexOf(':');
 1582               if (colon < 0)
 1583               {
 1584                  // No group given, just the port
 1585                  try
 1586                  {
 1587                     port = Integer.parseInt(discoveryGroupPort);
 1588                  }
 1589                  catch (Exception ex)
 1590                  {
 1591                     log.warn("Failed to parse port: " + discoveryGroupPort, ex);
 1592                  }
 1593               }
 1594               else
 1595               {
 1596                  // The old group:port syntax was given
 1597                  group = discoveryGroupPort.substring(0, colon);
 1598                  String portStr = discoveryGroupPort.substring(colon + 1);
 1599                  try
 1600                  {
 1601                     port = Integer.parseInt(portStr);
 1602                  }
 1603                  catch (Exception ex)
 1604                  {
 1605                     log.warn("Failed to parse port: " + portStr, ex);
 1606                  }
 1607               }
 1608            }
 1609   
 1610            iaGroup = InetAddress.getByName(group);
 1611            String localAddrStr = (String) serverEnv.get(JNP_LOCAL_ADDRESS);
 1612            String localPortStr = (String) serverEnv.get(JNP_LOCAL_PORT);
 1613            int localPort = 0;
 1614            if (localPortStr != null)
 1615               localPort = Integer.parseInt(localPortStr);
 1616            if (localAddrStr != null)
 1617            {
 1618               InetSocketAddress localAddr = new InetSocketAddress(localAddrStr, localPort);
 1619               s = new MulticastSocket(localAddr);
 1620            }
 1621            else
 1622            {
 1623               s = new MulticastSocket(localPort);
 1624            }
 1625            s.setSoTimeout(timeout);
 1626            s.setTimeToLive(ttl);
 1627            if(log.isTraceEnabled())
 1628               log.trace("TTL on multicast discovery socket is " + ttl);
 1629            s.joinGroup(iaGroup);
 1630            if (trace)
 1631               log.trace("MulticastSocket: " + s);
 1632            DatagramPacket packet;
 1633            // Send a request optionally restricted to a cluster partition
 1634            StringBuffer data = new StringBuffer("GET_ADDRESS");
 1635            if (partitionName != null)
 1636               data.append(":" + partitionName);
 1637            byte[] buf = data.toString().getBytes();
 1638            packet = new DatagramPacket(buf, buf.length, iaGroup, port);
 1639            if (trace)
 1640               log.trace("Sending discovery packet(" + data + ") to: " + iaGroup + ":" + port);
 1641            s.send(packet);
 1642            // Look for a reply
 1643            // IP address + port number = 128.128.128.128:65535 => (12+3) + 1 + (5) = 21
 1644   
 1645            buf = new byte[50];
 1646            packet = new DatagramPacket(buf, buf.length);
 1647            s.receive(packet);
 1648            String myServer = new String(packet.getData()).trim();
 1649            if (trace)
 1650               log.trace("Received answer packet: " + myServer);
 1651            while (myServer != null && myServer.startsWith("GET_ADDRESS"))
 1652            {
 1653               Arrays.fill(buf, (byte) 0);
 1654               packet.setLength(buf.length);
 1655               s.receive(packet);
 1656               byte[] reply = packet.getData();
 1657               myServer = new String(reply).trim();
 1658               if (trace)
 1659                  log.trace("Received answer packet: " + myServer);
 1660            }
 1661            String serverHost;
 1662            int serverPort;
 1663   
 1664            Object[] hostAndPort = {myServer, 0};
 1665            parseHostPort(myServer, hostAndPort, DEFAULT_DISCOVERY_GROUP_PORT);
 1666            serverHost = (String) hostAndPort[HOST_INDEX];
 1667            serverPort = (Integer) hostAndPort[PORT_INDEX];
 1668            if (serverHost != null)
 1669            {
 1670               server = getServer(serverHost, serverPort, serverEnv);
 1671            }
 1672            return server;
 1673         }
 1674         catch (IOException e)
 1675         {
 1676            if (trace)
 1677               log.trace("Discovery failed", e);
 1678            NamingException ex = new CommunicationException(e.getMessage());
 1679            ex.setRootCause(e);
 1680            throw ex;
 1681         }
 1682         finally
 1683         {
 1684            try
 1685            {
 1686               if (s != null)
 1687                  s.leaveGroup(iaGroup);
 1688            }
 1689            catch (Exception ignore)
 1690            {
 1691            }
 1692            try
 1693            {
 1694               if (s != null)
 1695                  s.close();
 1696            }
 1697            catch (Exception ignore)
 1698            {
 1699            }
 1700         }
 1701      }
 1702   
 1703      private void checkRef(Hashtable refEnv)
 1704         throws NamingException
 1705      {
 1706         if (naming == null)
 1707         {
 1708            String host = "localhost";
 1709            int port = 1099;
 1710            Exception serverEx = null;
 1711            
 1712            // Locate first available naming service
 1713            String urls = (String) refEnv.get(Context.PROVIDER_URL);
 1714            if (urls != null && urls.length() > 0)
 1715            {
 1716               StringTokenizer tokenizer = new StringTokenizer(urls, ",");
 1717   
 1718               while (naming == null && tokenizer.hasMoreElements())
 1719               {
 1720                  String url = tokenizer.nextToken();
 1721                  // Parse the url into a host:port form, stripping any protocol
 1722                  Name urlAsName = getNameParser("").parse(url);
 1723                  String server = parseNameForScheme(urlAsName, null);
 1724                  if (server != null)
 1725                     url = server;
 1726                  // 
 1727                  Object[] hostAndPort = {url, 0};
 1728                  parseHostPort(url, hostAndPort, 1099);
 1729                  host = (String) hostAndPort[HOST_INDEX];
 1730                  port = (Integer) hostAndPort[PORT_INDEX];
 1731                  try
 1732                  {
 1733                     // Get server from cache
 1734                     naming = getServer(host, port, refEnv);
 1735                  }
 1736                  catch (Exception e)
 1737                  {
 1738                     serverEx = e;
 1739                     log.debug("Failed to connect to " + host + ":" + port, e);
 1740                  }
 1741               }
 1742   
 1743               // If there is still no
 1744               Exception discoveryFailure = null;
 1745               if (naming == null)
 1746               {
 1747                  try
 1748                  {
 1749                     naming = discoverServer(refEnv);
 1750                  }
 1751                  catch (Exception e)
 1752                  {
 1753                     discoveryFailure = e;
 1754                     if (serverEx == null)
 1755                        serverEx = e;
 1756                  }
 1757                  if (naming == null)
 1758                  {
 1759                     StringBuffer buffer = new StringBuffer(50);
 1760                     buffer.append("Could not obtain connection to any of these urls: ").append(urls);
 1761                     if (discoveryFailure != null)
 1762                        buffer.append(" and discovery failed with error: ").append(discoveryFailure);
 1763                     CommunicationException ce = new CommunicationException(buffer.toString());
 1764                     ce.setRootCause(serverEx);
 1765                     throw ce;
 1766                  }
 1767               }
 1768            }
 1769            else
 1770            {
 1771               // If we are in a clustering scenario, the client code may request a context
 1772               // for a *specific* HA-JNDI service (i.e. linked to a *specific* partition)
 1773               // EVEN if the lookup is done inside a JBoss VM. For example, a JBoss service
 1774               // may do a lookup on a HA-JNDI service running on another host *without*
 1775               // explicitly providing a PROVIDER_URL but simply by providing a JNP_PARTITON_NAME
 1776               // parameter so that dynamic discovery can be used
 1777               //
 1778               String jnpPartitionName = (String) refEnv.get(JNP_PARTITION_NAME);
 1779               if (jnpPartitionName != null)
 1780               {
 1781                  // the client is requesting for a specific partition name
 1782                  // 
 1783                  naming = discoverServer(refEnv);
 1784                  if (naming == null)
 1785                     throw new ConfigurationException
 1786                        ("No valid context could be build for jnp.partitionName=" + jnpPartitionName);
 1787               }
 1788               else
 1789               {
 1790                  // Use server in same JVM
 1791                  naming = localServer;
 1792   
 1793                  if (naming == null)
 1794                  {
 1795                     naming = discoverServer(refEnv);
 1796                     if (naming == null)
 1797                     // Local, but no local JNDI provider found!
 1798                        throw new ConfigurationException("No valid Context.PROVIDER_URL was found");
 1799                  }
 1800               }
 1801            }
 1802         }
 1803      }
 1804   
 1805      /**
 1806       * Parse a naming provider url for the host/port information
 1807       * @param url - the naming provider url string to parse
 1808       * @param output, [0] = the host name/address, [1] = the parsed port as an Integer
 1809       * @param defaultPort - the default port to return in output[1] if no port
 1810       * was seen in the url string.
 1811       * @return the index of the port separator if found, -1 otherwise.
 1812       */
 1813      static private int parseHostPort(String url, Object[] output, int defaultPort)
 1814      {
 1815         // First look for a @ separating the host and port
 1816         int colon = url.indexOf('@');
 1817         if(colon < 0)
 1818         {
 1819            // If there are multiple ':' assume its an IPv6 address
 1820            colon = url.lastIndexOf(':');
 1821            int firstColon = url.indexOf(':');
 1822            if(colon > firstColon)
 1823               colon = -1;
 1824         }
 1825   
 1826         if(colon < 0)
 1827         {
 1828            output[HOST_INDEX] = url;
 1829            output[PORT_INDEX] = new Integer(defaultPort);
 1830         }
 1831         else
 1832         {
 1833            output[HOST_INDEX] = url.substring(0, colon);  
 1834            try
 1835            {
 1836               output[PORT_INDEX] = Integer.parseInt(url.substring(colon+1).trim());
 1837            }
 1838            catch (Exception ex)
 1839            {
 1840               // Use default port
 1841               output[PORT_INDEX] = new Integer(defaultPort);
 1842            }
 1843         }
 1844         return colon;
 1845      }
 1846   
 1847      private Name getAbsoluteName(Name n)
 1848         throws NamingException
 1849      {
 1850         if (n.isEmpty())
 1851            return composeName(n, prefix);
 1852         else if (n.get(0).toString().equals("")) // Absolute name
 1853            return n.getSuffix(1);
 1854         else // Add prefix
 1855            return composeName(n, prefix);
 1856      }
 1857   
 1858      private Hashtable getEnv(Name n)
 1859         throws InvalidNameException
 1860      {
 1861         Hashtable nameEnv = env;
 1862         env.remove(JNP_PARSED_NAME);
 1863         String serverInfo = parseNameForScheme(n, nameEnv);
 1864         if (serverInfo != null)
 1865         {
 1866            // Set hostname:port value for the naming server
 1867            nameEnv = (Hashtable) env.clone();
 1868            nameEnv.put(Context.PROVIDER_URL, serverInfo);
 1869         }
 1870         return nameEnv;
 1871      }
 1872      
 1873      /**
 1874       * JBAS-4574. Check if the given exception is because the server has 
 1875       * been restarted while the cached naming stub hasn't been dgc-ed yet. 
 1876       * If yes, we will flush out the naming stub from our cache and
 1877       * acquire a new stub. BW.
 1878       * 
 1879       * @param e  the exception that may be due to a stale stub
 1880       * @param refEnv the naming environment associated with the failed call
 1881       * 
 1882       * @return <code>true</code> if <code>e</code> indicates a stale
 1883       *         naming stub and we were able to succesfully flush the
 1884       *         cache and acquire a new stub; <code>false</code> otherwise.
 1885       */
 1886      private boolean handleStaleNamingStub(Exception e, Hashtable refEnv)
 1887      {
 1888         if (e instanceof NoSuchObjectException
 1889               || e.getCause() instanceof NoSuchObjectException)
 1890         {
 1891            try
 1892            {
 1893               if( log.isTraceEnabled() )
 1894               {
 1895                  log.trace("Call failed with NoSuchObjectException, " +
 1896                            "flushing server cache and retrying", e);
 1897               }
 1898               naming = null;
 1899               removeServer(refEnv);
 1900                 
 1901               checkRef(refEnv);
 1902               
 1903               return true;
 1904            }
 1905            catch (Exception e1)
 1906            {
 1907               // Just log and return false; let caller continue processing
 1908               // the original exception passed in to this method
 1909               log.error("Caught exception flushing server cache and " +
 1910                         "re-establish naming after exception " + 
 1911                         e.getLocalizedMessage(), e1);
 1912            }
 1913         }
 1914         return false;
 1915      }
 1916   
 1917      // Inner classes -------------------------------------------------
 1918   }

Save This Page
Home » jnpserver-sources » org.jnp.interfaces » [javadoc | source]