User development,

A new message was posted in the thread "ScopedClassPoolRepositoryImpl and 
default ClassPool":

http://community.jboss.org/message/524465#524465

Author  : Flavia Rainone
Profile : http://community.jboss.org/people/flavia.rain...@jboss.com

Message:
--------------------------------------------------------------
While trying to fix the JBoss AOP + AS tests with the new jboss-classpool 
project, I bumped into a https://jira.jboss.org/jira/browse/JBREFLECT-94 
involving ScopedClassPoolRepositoryImpl and DefaultClassPool.
 
Our factories were using DefaultClassPool to represent null class loaders so 
that bootstrap classes could be loaded without duplicates. This turned out to 
be a problem because we were seeing duplicates of JBoss normal classes. Take a 
look at this example:
-> BaseClassLoader vfsfile:xxx/server/all/conf/jboss-service.xml belongs to 
DefaultDomain.
    When this ClassLoader is requested to load class 
org.jboss.jms.client.container.StateCreationAspect, it  will delegate to 
DefaultDomain, which will in turn find the original BaseClassLoader as a 
candidate to load that class. That BaseClassLoader loads the class and the 
result is returned.
 
When this example is ported to ClassPool-level, we get a CNFException. The 
reason for this is that the BaseClassPool 
vfsfile:xxx/server/all/conf/jboss-service.xml has a parent that can find the 
resource that contains the requested class:

public class TranslatableClassLoaderIsLocalResourcePlugin extends 
AbstractIsLocalResourcePlugin
{
   public boolean isMyResource(String resourceName)
   {
      ClassLoader loader = getPool().getClassLoader();
      if (loader instanceof Translatable == false)
      {
         throw new IllegalStateException("ClassLoader of pool " + getPool() +  
" is not instance of Translatable " + loader);
      }
      URL url = 
((Translatable)getPool().getClassLoader()).getResourceLocally(resourceName);
      if (url == null)
      {
         return false;
      }
 
RETURNS TRUE ----->      if (isSameInParent(resourceName, url))
      {
         return false;
      }
      return true;
   }
 
}

 
This is isSameInParent implementation:
 
protected boolean isSameInParent(String classResourceName, URL foundURL)
   {
      ClassPool  parent = pool.getParent(); 
      if (parent != null)
      {
         ClassLoader parentLoader = parent.getClassLoader();
         URL parentURL = parentLoader.getResource(classResourceName);
         if (parentURL == null)
         {
            return false;
         }
         URI parentURI = URI.create(parentURL.toString());
         URI foundURI = URI.create(foundURL.toString());
         if (parentURI.equals(foundURI))
         {
            return true;
         }
      }
      
      return false;
   }

 
And ClassPool.getClassLoader implementation:
 
public ClassLoader getClassLoader()
{
   return getContextClassLoader();
}
 


 
In the given example, getClassLoader will return the BaseClassLoader for AOP 
module, which can of course find the requested resource, even though it 
shouldn't.

 
Another problem I had is that ScopedClassPoolRepositoryImpl edits the classpath 
of the DefaultClassPool:
private ScopedClassPoolRepositoryImpl {
   classpool = ClassPool.getDefault();
   // FIXME This doesn't look correct
   ClassLoader cl = Thread.currentThread().getContextClassLoader();
   classpool.insertClassPath(new LoaderClassPath(cl));
}

 
This is similar to the problem explained above, and makes this class pool 
capable of loading classes that other classpools should be responsible to load. 
As a result, we get duplicates of the same CtClass. Its FIXME tells me that 
this was already spotted before as a possible bug.

 
I worked around this issue by replacing the usage of the Default ClassPool by 
this Singleton class:
public class SystemClassPool extends ClassPool
{
   private SystemClassPool()
   {
      super(null);
      appendSystemPath();
   }
   
   @Override
   public ClassLoader getClassLoader()
   {
      return ClassLoader.getSystemClassLoader();
   }
}

 
Equally to DefaultClassPool, it has the SystemPath appended, but its 
getClassLoader method returns the SystemClassLoader, which is the closest I can 
get to Bootstrap class loader (take a look at the 
http://java.sun.com/javase/7/docs/api/java/lang/ClassLoader.html#getResource%28java.lang.String%29
 for more on this).
 
That didn't solve my problem entirely, because ScopedClassPoolRepositoryImpl 
has its own “default” classpool field:
public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository 
{
  
    /** The default class pool */
    protected ClassPool classpool;
 
    /** The factory for creating class pools */
    protected ScopedClassPoolFactory factory = new ScopedClassPoolFactoryImpl();
 
    /**
     * Get the instance.
     * 
     * @return the instance.
     */
    public static ScopedClassPoolRepository getInstance() {
        return instance;
    }
 
    /**
     * Singleton.
     */
    private ScopedClassPoolRepositoryImpl() {
        classpool = ClassPool.getDefault();
        // FIXME This doesn't look correct
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        classpool.insertClassPath(new LoaderClassPath(cl));
    }
    ...
}

 
Differently from what one may have thought, the ClassPoolRepository class (from 
jboss-classpool project) is not a subclass of ScopedClassPoolRepositoryImpl, 
given this class cannot be subclassed. This has been an issue for me before, 
because I always thought my code would be much cleaner if I could extend 
ScopedClassPoolRepositoryImpl instead of 
http://anonsvn.jboss.org/repos/jbossas/projects/jboss-classpool/trunk/classpool/src/main/java/org/jboss/classpool/spi/ClassPoolRepository.java.

So, what should be done in this regard? I'm opening this thread se we can find 
an elegant solution to my problem. Should ScopedClassPoolRepository be 
singleton? Should we use ScopedClassPoolFactory at all (the problem with not 
doing that is that we will have duplicate code in both classes)? I know that 
ScopedClassPool and auxiliary classes have been created to be used as the 
ClassPool solution to AS, but so many things have changed ever since that this 
solution is far from being complete, and that's why we need jboss-classpool 
now. So now, I'm not even sure what to do of that.


Regarding ClassPool.getClassLoader()'s implementation, I don't think it is a 
bug, even though we are not using this implementation at all (ScopedClassPool 
overwrites it, and so does the new SystemClassPool class). I just think that it 
is a way of doing things that works with simple standalone scenarios, but that 
doesnot fulfill our needs with AS.

--------------------------------------------------------------

To reply to this message visit the message page: 
http://community.jboss.org/message/524465#524465


_______________________________________________
jboss-user mailing list
jboss-user@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/jboss-user

Reply via email to