Package org.jboss.ha.jndi.ispn

Source Code of org.jboss.ha.jndi.ispn.DistributedTreeManager

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2010, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt 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.jboss.ha.jndi.ispn;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.NotContextException;

import org.infinispan.Cache;
import org.infinispan.CacheException;
import org.infinispan.manager.CacheContainer;
import org.infinispan.tree.Fqn;
import org.infinispan.tree.Node;
import org.infinispan.tree.TreeCache;
import org.jboss.ha.ispn.CacheContainerRegistry;
import org.jboss.ha.ispn.tree.DefaultTreeCacheFactory;
import org.jboss.ha.ispn.tree.TreeCacheFactory;
import org.jboss.logging.Logger;
import org.jnp.interfaces.Naming;
import org.jnp.interfaces.NamingContext;
import org.jnp.interfaces.NamingParser;

/**
*  This class utilizes Infinispan to provide a HA-JNDI implementation.
*
@author Jerry Gauthier
@author Brian Stansberry
@author Scott Marlow
@version $Revision: 108179 $
*/
public class DistributedTreeManager
   implements Naming, org.jboss.ha.jndi.spi.DistributedTreeManager
{
   private static final Logger LOG = Logger.getLogger(DistributedTreeManager.class);
   private static final NamingParser PARSER = new NamingParser();
   private static final Fqn FQN_ROOT = Fqn.root();

   private final CacheContainerRegistry registry;
   private final TreeCacheFactory treeCacheFactory;
  
   private volatile String containerName;
   private volatile String cacheName = "DistributedTreeManager";
   private volatile Naming haStub;
   private volatile TreeCache<String, Binding> cache;

   public DistributedTreeManager(CacheContainerRegistry registry)
   {
      this(registry, new DefaultTreeCacheFactory());
   }

   public DistributedTreeManager(CacheContainerRegistry registry, TreeCacheFactory factory)
   {
      this.registry = registry;
      this.treeCacheFactory = factory;
   }

   @Override
   public void init()
   {
      CacheContainer container = this.registry.getCacheContainer(this.containerName);
      Cache<String, Binding> cache = (this.cacheName == null) ? container.<String, Binding>getCache() : container.<String, Binding>getCache(this.cacheName);
      this.cache = this.treeCacheFactory.createTreeCache(cache);
     
      if (!cache.getStatus().allowInvocations())
      {
         this.cache.start();
      }
   }


   @Override
   public void shutdown()
   {
      this.cache.stop();
   }

   public void setCacheContainerName(String containerName)
   {
      this.containerName = containerName;
   }
  
   public void setCacheName(String cacheName)
   {
      this.cacheName = cacheName;
   }

   @Override
   public Naming getHAStub()
   {
      return this.haStub;
   }

   @Override
   public void setHAStub(Naming haStub)
   {
      this.haStub = haStub;
   }

   // Naming implementation -----------------------------------------

   @Override
   public void bind(Name name, Object obj, String className) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("bind, name="+name);
      }
     
      this.internalBind(name, obj, className, false);
   }

   @Override
   public void rebind(Name name, Object obj, String className) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("rebind, name="+name);
      }

      this.internalBind(name, obj, className, true);
   }

   @Override  
   public void unbind(Name name) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("unbind, name="+name);
      }
      if (name.isEmpty())
      {
         // Empty names are not allowed
         throw new InvalidNameException("Name is empty");
      }
     
      // is the name a context?
      try
      {
         Fqn temp = Fqn.fromRelativeFqn(FQN_ROOT, Fqn.fromString(name.toString()));
         // TODO why not jst call remove -- why hasChild first?
         if (this.cache.getRoot().hasChild(temp))
         {
            this.cache.removeNode(temp);
            return;
         }
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }

         // don't chain CacheException since Infinispan may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
     
      int size = name.size();
     
      // get the context and key
      Fqn ctx;
      String key = name.get(size - 1);
      boolean ctxIsRoot = false;
      if (size > 1) // find subcontext to which the key is bound
      {
         String prefix = name.getPrefix(size - 1).toString();
         Fqn fqn = Fqn.fromString(prefix);
         ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
      }
      else
      {
         ctx = FQN_ROOT;
         ctxIsRoot = true;
      }
     
      try
      {
         Object removed = this.cache.remove(ctx, key);
         if (removed == null)
         {
            if (! ctxIsRoot && !this.cache.getRoot().hasChild(ctx))
            {
                throw new NotContextException(name.getPrefix(size - 1).toString() + " not a context");
            }

            throw new NameNotFoundException(key + " not bound");
         }
      }
      catch (CacheException ce)
      {
         // don't chain CacheException since JBoss Cache may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.setStackTrace(ce.getStackTrace());
         throw ne;
      }
   }

   @Override
   public Object lookup(Name name) throws NamingException
   {
      boolean trace = LOG.isTraceEnabled();
      if (trace)
      {
         LOG.trace("lookup, name="+name);
      }
  
      if (name.isEmpty())
      {
         // Return this
         return new NamingContext(null, PARSER.parse(""), this.getHAStub());
      }

      // is the name a context?
      try
      {
         Node<String, Binding> n = this.cache.getRoot().getChild(Fqn.fromRelativeFqn(FQN_ROOT, Fqn.fromString(name.toString())));
         if (n != null)
         {
            Name fullName = (Name) name.clone();
            return new NamingContext(null, fullName, this.getHAStub());
         }
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }
         // don't chain CacheException since Infinispan may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
  
      int size = name.size();
  
      // get the context and key
      Fqn ctx;
      String key = name.get(size - 1);
      if (size > 1) // find subcontext to which the key is bound
      {
         String prefix = name.getPrefix(size - 1).toString();
         Fqn fqn = Fqn.fromString(prefix);
         ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
      }
      else
      {
         ctx = FQN_ROOT;
      }
  
      try
      {
         Binding b = this.cache.get(ctx, key);
        
         // if key not in cache, return null
         return (b != null) ? b.getObject() : null;
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }
         // don't chain CacheException since JBoss Cache may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
   }

   @Override
   public Collection<NameClassPair> list(Name name) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("list, name="+name);
      }
  
      // get the context
      Fqn ctx;
      String ctxName = "";
      int size = name.size();
      if (size >= 1)
      {
         ctxName = name.toString();
         Fqn fqn = Fqn.fromString(ctxName);
         ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
      }
      else
      {
         ctx = FQN_ROOT;
      }
     
      boolean exists = this.cache.getRoot().hasChild(ctx);
      if (!exists)
      {
         try
         {
            return Collections.list(new InitialContext().list(name));
         }
         catch (NamingException e)
         {
            throw new NotContextException(ctxName+ " not a context");
         }
      }
     
      try
      {
         List<NameClassPair> list = new LinkedList<NameClassPair>();

         Node<String, Binding> base = this.cache.getRoot().getChild(ctx);
         if (base != null)
         {
            for (Binding b: base.getData().values())
            {
               list.add(new NameClassPair(b.getName(),b.getClassName(),true));
            }
           
            // Why doesn't this return Set<String>?
            Set<Object> children = base.getChildrenNames();
            if (children != null && !children.isEmpty())
            {
               for (Object child: children)
               {
                  String node = (String) child;
                  Name fullName = (Name) name.clone();
                  fullName.add(node);
                  list.add(new NameClassPair(node, NamingContext.class.getName(),true));
               }
            }
         }
        
         return list;
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }

         // don't chain CacheException since JBoss Cache may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
   }

   @Override
   public Collection<Binding> listBindings(Name name) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("listBindings, name="+name);
      }
     
      // get the context
      Fqn ctx;
      String ctxName = "";
      int size = name.size();
      if (size >= 1)
      {
         ctxName = name.toString();
         Fqn fqn = Fqn.fromString(ctxName);
         ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
      }
      else
      {
         ctx = FQN_ROOT;
      }
     
      boolean exists = this.cache.getRoot().hasChild(ctx);
      if (!exists)
      {
         // not found in global jndi, look in local.
         try
         {
            return Collections.list(new InitialContext().listBindings(name));
         }
         catch (NamingException e)
         {
            throw new NotContextException(ctxName+ " not a context");
         }
      }
     
      try
      {
         List<Binding> list = new LinkedList<Binding>();
        
         Node<String, Binding> node = this.cache.getRoot().getChild(ctx);
         if (node != null)
         {
            Map<String, Binding> data = node.getData();
            if (data != null && !data.isEmpty())
            {
               list.addAll(data.values());
            }
           
            // Why doesn't this return Set<String>?
            Set<Object> children = node.getChildrenNames();
            if (children != null && !children.isEmpty())
            {
               for (Object obj: children)
               {
                  String child = (String) obj;
                  Name fullName = (Name) name.clone();
                  fullName.add(child);
                  NamingContext subCtx = new NamingContext(null, fullName, this.getHAStub());
                  list.add(new Binding(child, NamingContext.class.getName(), subCtx, true));
               }
            }
         }
        
         return list;
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }

         // don't chain CacheException since Infinispan may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
   }

   @Override
   public Context createSubcontext(Name name) throws NamingException
   {
      if (LOG.isTraceEnabled())
      {
         LOG.trace("createSubcontext, name="+name);
      }
     
      int size = name.size();
     
      if (size == 0)
      {
         throw new InvalidNameException("Name is empty");
      }

      // does the new context already exist?
      String str = name.toString();
      Fqn fqn = Fqn.fromString(str);
      Fqn ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
      if (this.cache.getRoot().hasChild(ctx))
      {
         throw new NameAlreadyBoundException(str);
      }
     
      // does the prefix context already exist?
      Fqn pctx;
      String newctx = name.get(size - 1);
      if (size > 1) // find subcontext to which the context will be added
      {
         String prefix = name.getPrefix(size - 1).toString();
         Fqn fqn2 = Fqn.fromString(prefix);
         pctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn2);
         boolean exists = this.cache.getRoot().hasChild(pctx);
         if (!exists)
         {
            throw new NotContextException(name.getPrefix(size - 1).toString());
         }
      }
      else
      {
         pctx = FQN_ROOT;
      }

      Fqn newf = Fqn.fromRelativeFqn(pctx, Fqn.fromString(newctx));
      try
      {
         this.cache.put(newf, new HashMap<String, Binding>());
      }
      catch (CacheException ce)
      {
         if (LOG.isTraceEnabled())
         {
            LOG.trace(ce.getMessage(), ce);
         }
         // don't chain CacheException since JBoss Cache may not be on remote client's classpath
         NamingException ne = new NamingException(ce.getClass().getName() + ": " + ce.getMessage());
         ne.fillInStackTrace();
         throw ne;
      }
  
      Name fullName = PARSER.parse("");
      fullName.addAll(name);
     
      return new NamingContext(null, fullName, this.getHAStub());
   }


   private void internalBind(Name name, Object obj, String className, boolean rebind) throws NamingException
   {
      if (name.isEmpty())
      {  // Empty names are not allowed
         throw new InvalidNameException("Name is empty");
      }

      int size = name.size();
     
      // get the context and key
      Fqn ctx;
      String key = name.get(size - 1);
      boolean isRootCtx = false;

      if (size > 1) // find subcontext to which the key will be added
      {
         String prefix = name.getPrefix(size - 1).toString();
         Fqn fqn = Fqn.fromString(prefix);
         ctx = Fqn.fromRelativeFqn(FQN_ROOT, fqn);
         boolean exists = this.cache.getRoot().hasChild(ctx);
         if (!exists)
         {
            throw new NotContextException(name.getPrefix(size - 1).toString() + " not a context");
            // note - NamingServer throws a CannotProceedException if the client attempts to bind
            //        to a Reference object having an "nns" address.  This implementation simply
            //        throws the NotContextException that's used when "nns" isn't present.
         }

      }
      else
      {
         ctx = FQN_ROOT;
         isRootCtx = true;
      }


      if (LOG.isTraceEnabled())
      {
         LOG.trace("internalBind, name=" + name + ", class=" + className + ", ctx=" + ctx);
      }

      if (!rebind)
      {
         Node<String, Binding> node = this.cache.getRoot();
         if(!isRootCtx// search from context node otherwise search from root
         {
            node = node.getChild(ctx);
         }
         if ((node != null) && (node.get(key) != null))
         {
            throw new NameAlreadyBoundException(key);
         }
      }
     
      this.cache.put(ctx, key, new Binding(key, className, obj, true));
   }
}
TOP

Related Classes of org.jboss.ha.jndi.ispn.DistributedTreeManager

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.