Package org.jboss.ha.jndi.impl.jbc

Source Code of org.jboss.ha.jndi.impl.jbc.JBossCacheDistributedTreeManager

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, 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.impl.jbc;

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.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.ha.framework.server.HAPartitionCacheHandlerImpl;
import org.jboss.ha.jndi.spi.DistributedTreeManager;
import org.jboss.logging.Logger;
import org.jnp.interfaces.Naming;
import org.jnp.interfaces.NamingContext;
import org.jnp.interfaces.NamingParser;

/**
*  This class utilizes JBossCache to provide a DistributedTreeManager implementation.
*
@author <a href="mailto:jgauthier@novell.com">Jerry Gauthier</a>
@author Brian Stansberry
@version $Revision: 74736 $
*/
public class JBossCacheDistributedTreeManager
   implements org.jnp.interfaces.Naming, DistributedTreeManager
{
   static final long serialVersionUID = 6342802270002172451L;
  
   private static Logger log = Logger.getLogger(JBossCacheDistributedTreeManager.class);

   private static final NamingParser parser = new NamingParser();
 
   public static final String DEFAULT_ROOT = "__HA_JNDI__";
  
   // Attributes --------------------------------------------------------

   private Cache<String, Binding> m_cache;
   private Fqn<String> m_root;
   private Naming haStub;
   private boolean treeRootSet;
   protected HAPartitionCacheHandlerImpl cacheHandler;
   protected boolean acquiredCache = false;

   // Constructor --------------------------------------------------------
 
   public JBossCacheDistributedTreeManager()
   {     
      super();
   }
  
   // Properties --------------------------------------------------------
  
  
   public HAPartitionCacheHandlerImpl getCacheHandler()
   {
      return cacheHandler;
   }

   public void setCacheHandler(HAPartitionCacheHandlerImpl cacheHandler)
   {
      this.cacheHandler = cacheHandler;
   }  
  
   public Cache<String, Binding> getClusteredCache()
   {
      return m_cache;
   }

   public void setClusteredCache(Cache<String, Binding> cache)
   {
      if (treeRootSet)
      {
         throw new IllegalStateException("Cannot change clusteredCache after call to init()");
      }
      this.m_cache = cache;
   }
  
   public void setRootFqn(String rootFqn)
   {
      if (treeRootSet)
      {
         throw new IllegalStateException("Cannot change rootFqn after call to init()");
      }
     
      m_root = (rootFqn == null) ? null : Fqn.fromString(rootFqn);        
   }
  
   // JBossCacheDistributedTreeManagerMBean ----------------------------------
  
   public String getRootFqn()
   {
      return m_root == null ? DEFAULT_ROOT : m_root.toString();
   }
  
   // Public -----------------------------------------------------------------

   @SuppressWarnings("unchecked")
   public void init()
   {
      if (this.haStub == null)
      {
         throw new IllegalStateException("Must call setHAStub before starting");
      }
     
      if (this.m_cache == null)
      {
         if (cacheHandler == null)
         {
            throw new IllegalStateException("No clustered cache available");
         }
        
         try
         {
            Cache c = null;
            synchronized (cacheHandler)
            {
               c = cacheHandler.getCache();
               if (c == null)
               {
                  cacheHandler.acquireCache();
                  c = cacheHandler.getCache();
                  acquiredCache = true;
               }
            }
            cacheHandler.startCache();
            setClusteredCache(c);
         }
         catch (RuntimeException e)
         {
            throw e;
         }
         catch (Exception e)
         {
            throw new RuntimeException(e);
         }
      }
     
      log.debug("initializing HAJNDITreeCache root");
      this.putTreeRoot();
   }

   public void shutdown()
   {     
      if (acquiredCache)
      {
         try
         {
            cacheHandler.releaseCache();
         }
         catch (Exception e)
         {
            log.error("Caught exception releasing cache", e);
         }
      }
   }

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

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

   // Naming implementation -----------------------------------------
 
   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);
   }
  
   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);
   }

   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();
      }
     
      // is the name a context?
      try
      {
         Fqn<String> temp = new Fqn<String>(this.m_root, Fqn.fromString(name.toString()));
         // TODO why not jst call remove -- why hasChild first?
         if (this.m_cache.getRoot().hasChild(temp))
         {
            this.m_cache.removeNode(temp);
            return;
         }
      }
      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;
      }
     
      int size = name.size();
     
      // get the context and key
      Fqn<String> 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<String> fqn = Fqn.fromString(prefix);
         ctx = new Fqn<String>(this.m_root, fqn);
      }
      else
      {
         ctx = this.m_root;
      }
     
      try
      {
         Object removed = this.m_cache.remove(ctx, key);
         if (removed == null)
         {
            if (!this.m_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;
      }
   }
  
   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.m_cache.getRoot().getChild(new Fqn<String>(this.m_root, Fqn.fromString(name.toString())));
         if (n != null)
         {
            Name fullName = (Name) name.clone();
            return new NamingContext(null, fullName, this.getHAStub());
         }
      }
      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;
      }
  
      int size = name.size();
  
      // get the context and key
      Fqn<String> 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<String> fqn = Fqn.fromString(prefix);
         ctx = new Fqn<String>(this.m_root, fqn);
      }
      else
      {
         ctx = this.m_root;
      }
  
      try
      {
         Binding b = this.m_cache.get(ctx, key);
        
         // if key not in cache, return null
         return (b != null) ? b.getObject() : null;
      }
      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;
      }
   }
  
   public Collection<NameClassPair> list(Name name) throws NamingException
   {
      if (log.isTraceEnabled())
      {
         log.trace("list, name="+name);
      }
  
      // get the context
      Fqn<String> ctx;
      String ctxName = "";
      int size = name.size();
      if (size >= 1)
      {
         ctxName = name.toString();
         Fqn<String> fqn = Fqn.fromString(ctxName);
         ctx = new Fqn<String>(this.m_root, fqn);
      }
      else
      {
         ctx = this.m_root;
      }
     
      boolean exists = this.m_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.m_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)
      {
         // 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;
      }
   }

   public Collection<Binding> listBindings(Name name) throws NamingException
   {
      if (log.isTraceEnabled())
      {
         log.trace("listBindings, name="+name);
      }
     
      // get the context
      Fqn<String> ctx;
      String ctxName = "";
      int size = name.size();
      if (size >= 1)
      {
         ctxName = name.toString();
         Fqn<String> fqn = Fqn.fromString(ctxName);
         ctx = new Fqn<String>(this.m_root, fqn);
      }
      else
      {
         ctx = this.m_root;
      }
     
      boolean exists = this.m_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.m_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)
      {
         // 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;
      }
   }

   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("Cannot pass an empty name to createSubcontext");
      }

      // does the new context already exist?
      String str = name.toString();
      Fqn<String> fqn = Fqn.fromString(str);
      Fqn<String> ctx = new Fqn<String>(this.m_root, fqn);
      if (this.m_cache.getRoot().hasChild(ctx))
      {
         throw new NameAlreadyBoundException();
      }
     
      // does the prefix context already exist?
      Fqn<String> 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<String> fqn2 = Fqn.fromString(prefix);
         pctx = new Fqn<String>(this.m_root, fqn2);
      }
      else
      {
         pctx = this.m_root;
      }
     
      boolean exists = this.m_cache.getRoot().hasChild(pctx);
      if (!exists)
      {
         throw new NotContextException(name.getPrefix(size - 1).toString());
      }

      Fqn<String> newf = new Fqn<String>(pctx, Fqn.fromString(newctx));
      try
      {
         this.m_cache.put(newf, new HashMap<String, Binding>());
      }
      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;
      }
  
      Name fullName = parser.parse("");
      fullName.addAll(name);
     
      return new NamingContext(null, fullName, this.getHAStub());
   }
  
   private void putTreeRoot() throws CacheException
   {
      if (this.m_root == null)
      {
         setRootFqn(DEFAULT_ROOT);
      }
     
      if (!this.m_cache.getRoot().hasChild(this.m_root))
      {
         this.m_cache.put(this.m_root, null);
         this.treeRootSet = true;
      }
   }
 
   private void internalBind(Name name, Object obj, String className, boolean rebind) throws NamingException
   {
      if (name.isEmpty())
      {  // Empty names are not allowed
         throw new InvalidNameException();
      }

      int size = name.size();
     
      // get the context and key
      Fqn<String> ctx;
      String key = name.get(size - 1);
      if (size > 1) // find subcontext to which the key will be added
      {
         String prefix = name.getPrefix(size - 1).toString();
         Fqn<String> fqn = Fqn.fromString(prefix);
         ctx = new Fqn<String>(this.m_root, fqn);
      }
      else
      {
         ctx = this.m_root;
      }
  
      boolean exists = this.m_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.
      }
      if (!rebind)
      {
         Node<String, Binding> node = this.m_cache.getRoot().getChild(ctx);
         if ((node != null) && (node.get(key) != null))
         {
            throw new NameAlreadyBoundException(key);
         }
      }
     
      this.m_cache.put(ctx, key, new Binding(key, className, obj, true));
   }
}
TOP

Related Classes of org.jboss.ha.jndi.impl.jbc.JBossCacheDistributedTreeManager

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.