Package org.jboss.classloading.plugins

Source Code of org.jboss.classloading.plugins.AbstractClassLoadingDomain

/*
* 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.classloading.plugins;

import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.jboss.classloading.spi.ClassLoadingDomain;
import org.jboss.classloading.spi.DomainClassLoader;
import org.jboss.kernel.plugins.registry.AbstractKernelRegistryEntry;
import org.jboss.kernel.spi.registry.KernelRegistryEntry;
import org.jboss.kernel.spi.registry.KernelRegistryPlugin;
import org.jboss.util.ClassLoading;
import org.jboss.util.CollectionsFactory;
import org.jboss.util.JBossObject;
import org.jboss.util.JBossStringBuilder;

/**
* An abstract classloading domain.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 1.8 $
*/
public class AbstractClassLoadingDomain extends JBossObject implements ClassLoadingDomain, KernelRegistryPlugin
{
   // Constants -----------------------------------------------------

   // Attributes ----------------------------------------------------

   /** Whether java2 classloading compliance is supported */
   protected boolean java2ClassLoadingCompliance;

   /** The parent classloading domain */
   protected ClassLoadingDomain parent;
  
   /** The classloaders by package name */
   protected Map pkgToCLs = CollectionsFactory.createConcurrentReaderMap();
   /** The cached classes */
   protected Map cachedClasses = CollectionsFactory.createConcurrentReaderMap();
  
   /** The failed classloading attempts */
   protected Map failedClasses = CollectionsFactory.createConcurrentReaderMap();
  
   /** The cached resources */
   protected Map cachedResources = CollectionsFactory.createConcurrentReaderMap();
  
   /** The failed resource attempts */
   protected Set failedResources = CollectionsFactory.createCopyOnWriteSet();
  
   // Static --------------------------------------------------------

   protected static AbstractClassLoadingDomain root;
  
   static
   {
      root = new AbstractClassLoadingDomain(true, null);
      SystemDomainClassLoader sdcl = new SystemDomainClassLoader();
      root.addDomainClassLoader(sdcl);
   }
  
   // Constructors --------------------------------------------------

   /**
    * Create a new AbstractClassLoadingDomain.
    */
   public AbstractClassLoadingDomain()
   {
      this(true, root);
   }
  
   /**
    * Create a new AbstractClassLoadingDomain.
    *
    * @param java2ClassLoadingCompliance whether java2 classloading complaince is enabled
    */
   public AbstractClassLoadingDomain(boolean java2ClassLoadingCompliance)
   {
      this(java2ClassLoadingCompliance, root);
   }
  
   /**
    * Create a new AbstractClassLoadingDomain.
    *
    * @param parent the parent domain
    */
   public AbstractClassLoadingDomain(ClassLoadingDomain parent)
   {
      this(true, parent);
   }
  
   /**
    * Create a new AbstractClassLoadingDomain.
    *
    * @param java2ClassLoadingCompliance whether java2 classloading complaince is enabled
    * @param parent the parent domain
    */
   public AbstractClassLoadingDomain(boolean java2ClassLoadingCompliance, ClassLoadingDomain parent)
   {
      this.java2ClassLoadingCompliance = java2ClassLoadingCompliance;
      this.parent = parent;
   }
  
   // Public --------------------------------------------------------

   /**
    * Add a domain classloader
    *
    * @param cl the classloader to add
    */
   public synchronized void addDomainClassLoader(DomainClassLoader cl)
   {
      boolean trace = log.isTraceEnabled();
     
      cl.setDomain(this);
     
      Set packages = cl.getPackageNames();
      if (trace)
         log.trace(this.toShortString() + " adding classloader " + cl + " packages " + packages);
      if (packages.isEmpty() == false)
      {
         for (Iterator i = packages.iterator(); i.hasNext();)
         {
            String pkg = (String) i.next();
            String name = pkg.replace('.', '/');
            List cls = (List) pkgToCLs.get(name);
            if (cls == null)
            {
               cls = CollectionsFactory.createCopyOnWriteList();
               pkgToCLs.put(name, cls);
            }
            cls.add(cl);
         }
      }

      toString = null;
      flushFailures();

      if (trace)
         log.trace(this.toShortString() + " added classloader " + cl + " packageMap=" + pkgToCLs);
   }

   /**
    * Remove a domain classloader
    *
    * @param cl the classloader to remove
    */
   public synchronized void removeDomainClassLoader(DomainClassLoader cl)
   {
      boolean trace = log.isTraceEnabled();

      Set packages = cl.getPackageNames();
      if (trace)
         log.trace(this.toShortString() + " removing classloader " + cl + " packages " + packages);
      if (packages.isEmpty() == false)
      {
         for (Iterator i = packages.iterator(); i.hasNext();)
         {
            String pkg = (String) i.next();
            String name = pkg.replace('.', '/');
            List cls = (List) pkgToCLs.get(name);
            if (cls != null)
            {
               cls.remove(cl);
               if (cls.isEmpty())
                  pkgToCLs.remove(name);
            }
         }
      }

      cl.setDomain(null);

      toString = null;
      flushCache();

      if (trace)
         log.trace(this.toShortString() + " removed classloader " + cl + " packageMap=" + pkgToCLs);
   }

   /**
    * Flush the cache
    */
   public void flushCache()
   {
      if (log.isTraceEnabled())
         log.trace(this.toShortString() + " flushing the cache");
      cachedClasses.clear();
      cachedResources.clear();
   }

   /**
    * Flush the failures
    */
   public void flushFailures()
   {
      if (log.isTraceEnabled())
         log.trace(this.toShortString() + " flushing the failures cache");
      failedClasses.clear();
      failedResources.clear();
   }
  
   // KernrelRegistryFactory implementation -------------------------
  
   public KernelRegistryEntry getEntry(Object name)
   {
      if (name instanceof String == false)
         return null;

      String stringName = (String) name;
      String slashName = stringName.replace('.', '/');
      List pkgs = (List) pkgToCLs.get(slashName);
      if (pkgs != null)
      {
         DomainClassLoader cl = (DomainClassLoader) pkgs.get(0);
         return new AbstractKernelRegistryEntry(name, cl.getPackage(stringName));
      }
     
      if (parent != null && parent instanceof KernelRegistryPlugin)
      {
         KernelRegistryPlugin factory = (KernelRegistryPlugin) parent;
         return factory.getEntry(name);
      }
     
      return null;
   }
  
   // ClassLoadingDomain implementation -----------------------------

   public boolean getJava2ClassLoadingCompliance()
   {
      return java2ClassLoadingCompliance;
   }

   public ClassLoadingDomain getParent()
   {
      return parent;
   }

   public synchronized Class loadClass(String name, boolean resolve, DomainClassLoader classLoader) throws ClassNotFoundException
   {
      if (name == null)
         throw new IllegalArgumentException("Null name");
     
      boolean trace = log.isTraceEnabled();
      if (trace)
         log.trace(this.toShortString() + " loading class " + name + " resolve=" + resolve + " classLoader=" + classLoader);
     
      Class clazz = null;

      if (java2ClassLoadingCompliance && parent != null)
         clazz = loadClassFromParent(trace, name, resolve, classLoader);

      if (clazz == null)
         checkLoadClassFailed(trace, name, resolve, classLoader);
     
      if (clazz == null)
         clazz = loadClassFromCache(trace, name, resolve, classLoader);
     
      if (clazz == null)
         clazz = loadClassFromClassLoaders(trace, name, resolve, classLoader);

      if (clazz == null && java2ClassLoadingCompliance == false && parent != null)
         clazz = loadClassFromParent(trace, name, resolve, classLoader);
     
      if (clazz == null)
         loadClassFailed(trace, name, resolve, classLoader);

      return clazz;
   }

   public URL loadResource(String name, DomainClassLoader classLoader)
   {
      if (name == null)
         throw new IllegalArgumentException("Null name");
     
      boolean trace = log.isTraceEnabled();
      if (trace)
         log.trace(this.toShortString() + " loading resource " + name + " classLoader=" + classLoader);
     
      URL url = null;
     
      if (classLoader != null)
         loadResourceFromClassLoader(trace, name, classLoader);
     
      if (url == null && java2ClassLoadingCompliance && parent != null)
         url = loadResourceFromParent(trace, name, classLoader);

      if (url == null)
      {
         if (checkLoadResourceFailed(trace, name, classLoader))
            return null;
      }
     
      if (url == null)
         url = loadResourceFromCache(trace, name, classLoader);
     
      if (url == null)
         url = loadResourceFromClassLoaders(trace, name, classLoader);

      if (url == null && java2ClassLoadingCompliance == false && parent != null)
         url = loadResourceFromParent(trace, name, classLoader);
     
      if (url == null)
         loadResourceFailed(trace, name, classLoader);

      return url;
   }

   // JBossObject overrides -----------------------------------------
  
   protected void toString(JBossStringBuilder buffer)
   {
      buffer.append("packages=").append(pkgToCLs.keySet());
      if (parent != null)
         buffer.append(" parent=").append(parent.toShortString());
   }

   public void toShortString(JBossStringBuilder buffer)
   {
      buffer.append(getClassShortName()).append('@');
      buffer.append(Integer.toHexString(System.identityHashCode(this)));
   }
  
   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------

   /**
    * Load a class from the parent
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param resolve whether the class should be resolved
    * @param classLoader the classloader initiating the request
    * @return the class or null if not found
    */
   protected Class loadClassFromParent(boolean trace, String name, boolean resolve, DomainClassLoader classLoader)
   {
      try
      {
         if (trace)
            log.trace(this.toShortString() + " loading class " + name + " from parent " + parent.toShortString());
         Class clazz = parent.loadClass(name, resolve, null);
         if (trace)
            log.trace(this.toShortString() + " loaded " + clazz + " from parent " + parent.toShortString());
         return clazz;
      }
      catch (ClassNotFoundException e)
      {
         if (trace)
            log.trace(this.toShortString() + " loading class " + name + " failed for parent " + parent.toShortString());
         return null;
      }
   }

   /**
    * Load a class from the classloaders
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param resolve whether the class should be resolved
    * @param classLoader the classloader initiating the request
    * @return the class or null if not found
    */
   protected Class loadClassFromClassLoaders(boolean trace, String name, boolean resolve, DomainClassLoader classLoader)
   {
      String dotName = name.replace('.', '/');
      List classLoaders = (List) pkgToCLs.get(ClassLoading.getPackageName(dotName));
      if (trace)
         log.trace(this.toShortString() + " loading class " + name + " from classloaders " + classLoaders);
      if (classLoaders == null)
         return null;
     
      for (ListIterator i = classLoaders.listIterator(); i.hasNext();)
      {
         DomainClassLoader cl = (DomainClassLoader) i.next();
         try
         {
            Class clazz = cl.loadClassLocally(name, resolve);
            if (trace)
               log.trace(this.toShortString() + " loaded " + clazz + " from classloader " + cl);
            cachedClasses.put(name, clazz);
            return clazz;
         }
         catch (ClassNotFoundException ignored)
         {
            if (trace)
               log.trace(this.toShortString() + " loading class " + name + " failed for classloader " + cl, ignored);
         }
      }
      return null;
   }

   /**
    * Load a class from the cache
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param resolve whether the class should be resolved
    * @param classLoader the classloader initiating the request
    * @return the class or null if not found
    */
   protected Class loadClassFromCache(boolean trace, String name, boolean resolve, DomainClassLoader classLoader)
   {
      Class clazz = (Class) cachedClasses.get(name);
      if (trace && clazz != null)
         log.trace(this.toShortString() + " loaded from cache " + clazz);
      return clazz;
   }

   /**
    * Check whether the request has already failed
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param resolve whether the class should be resolved
    * @param classLoader the classloader initiating the request
    * @throws ClassNotFoundException when already failed
    */
   protected void checkLoadClassFailed(boolean trace, String name, boolean resolve, DomainClassLoader classLoader) throws ClassNotFoundException
   {
      ClassNotFoundException cnfe = (ClassNotFoundException) failedClasses.get(name);
      if (cnfe != null)
      {
         if (trace)
            log.trace(this.toShortString() + " loading class " + name + " already failed");
         throw new ClassNotFoundException("Class " + name + " not found", cnfe);
      }
   }

   /**
    * Fail this classloading attempt
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param resolve whether the class should be resolved
    * @param classLoader the classloader initiating the request
    * @throws ClassNotFoundException always
    */
   protected void loadClassFailed(boolean trace, String name, boolean resolve, DomainClassLoader classLoader) throws ClassNotFoundException
   {
      if (trace)
         log.trace(this.toShortString() + " loading class " + name + " failed");
      ClassNotFoundException cnfe = new ClassNotFoundException("Class " + name + " not found ");
      failedClasses.put(name, cnfe);
      throw cnfe;
   }

   /**
    * Load a resource from the parent
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    * @return the resource or null if not found
    */
   protected URL loadResourceFromParent(boolean trace, String name, DomainClassLoader classLoader)
   {
      if (trace)
         log.trace(this.toShortString() + " loading resource " + name + " from parent " + parent.toShortString());
      URL url = parent.loadResource(name, null);
      if (trace)
      {
         if (url != null)
            log.trace(this.toShortString() + " loaded resource " + url + " from parent " + parent.toShortString());
         else
            log.trace(this.toShortString() + " loading resource " + name + " failed from parent " + parent.toShortString());
      }
      return url;
   }

   /**
    * Load a resource from the specified classloader
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    * @return the resource or null if not found
    */
   protected URL loadResourceFromClassLoader(boolean trace, String name, DomainClassLoader classLoader)
   {
      if (trace)
         log.trace(this.toShortString() + " loading resource " + name + " from classloader " + classLoader);
      URL url = classLoader.loadResourceLocally(name);
      if (url != null)
      {
         if (trace)
            log.trace(this.toShortString() + " loaded resource " + url + " from classloader " + classLoader);
         return url;
      }
      return null;
   }

   /**
    * Load a resource from the classloaders
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    * @return the resource or null if not found
    */
   protected URL loadResourceFromClassLoaders(boolean trace, String name, DomainClassLoader classLoader)
   {
      List classLoaders = (List) pkgToCLs.get(ClassLoading.getPackageName(name));
      if (trace)
         log.trace(this.toShortString() + " loading resource " + name + " from classloaders " + classLoaders);
      if (classLoaders == null)
         return null;
     
      for (ListIterator i = classLoaders.listIterator(); i.hasNext();)
      {
         DomainClassLoader cl = (DomainClassLoader) i.next();
         URL url = cl.loadResourceLocally(name);
         if (url != null)
         {
            if (trace)
               log.trace(this.toShortString() + " loaded resource " + url + " from classloader " + cl);
            cachedResources.put(name, url);
            return url;
         }
         if (trace)
            log.trace(this.toShortString() + " loading resource " + name + " failed from classloader " + cl);
      }
      return null;
   }

   /**
    * Load a resource from the cache
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    * @return the resource or null if not found
    */
   protected URL loadResourceFromCache(boolean trace, String name, DomainClassLoader classLoader)
   {
      URL url = (URL) cachedResources.get(name);
      if (trace && url != null)
         log.trace(this.toShortString() + " loaded resource "+ url + " from cache ");
      return url;
   }

   /**
    * Check whether the request has already failed
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    * @return the true when it has already failed
    */
   protected boolean checkLoadResourceFailed(boolean trace, String name, DomainClassLoader classLoader)
   {
      if (failedResources.contains(name))
      {
         if (trace)
            log.trace(this.toShortString() + " loading resource " + name + " already failed");
         return true;
      }
     
      return false;
   }

   /**
    * Fail this resource attempt
    *
    * @param trace whether trace is enabled
    * @param name the name of the class
    * @param classLoader the classloader initiating the request
    */
   protected void loadResourceFailed(boolean trace, String name, DomainClassLoader classLoader)
   {
      failedResources.add(name);
      if (trace)
         log.trace(this.toShortString() + " loading resource " + name + " failed");
   }
  
   // Private -------------------------------------------------------

   // Inner classes -------------------------------------------------
}
TOP

Related Classes of org.jboss.classloading.plugins.AbstractClassLoadingDomain

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.