0

I have the following problem.
A HashMap is used to set properties and the key is a ClassLoader.
The code that sets a property is the following (AxisProperties):

public static void setProperty(String propertyName, String value, boolean isDefault){  
      if(propertyName != null)  
            synchronized(propertiesCache)  
            {  
                ClassLoader classLoader = getThreadContextClassLoader();  
                HashMap properties = (HashMap)propertiesCache.get(classLoader);  
                if(value == null)  
                {  
                    if(properties != null)  
                        properties.remove(propertyName);  
                } else  
                {  
                    if(properties == null)  
                    {  
                        properties = new HashMap();  
                        propertiesCache.put(classLoader, properties);  
                    }  
                    properties.put(propertyName, new Value(value, isDefault));  
                }  
            }  
  }  

One of these values is cached somewhere and I need to reset this hashmap but the problem is I don't know how to do this.
I thought to load the class (delegating to axis using a URLClassLoader) but I see that the code does getThreadContextClassLoader(); which is:

public ClassLoader getThreadContextClassLoader()  
{  
   ClassLoader classLoader;  
        try  
        {  
            classLoader = Thread.currentThread().getContextClassLoader();  
        }  
        catch(SecurityException e)  
        {  
            classLoader = null;  
        }  
        return classLoader;  
}  

So I think it will use the classloader of my current thread not the one that I used to load the class to use (i.e. axis).
So is there a way around this?

Note: I already have loaded axis as part of my application. So the idea would be to reload it via a different classloader

WarrenFaith
  • 57,492
  • 25
  • 134
  • 150
Jim
  • 18,826
  • 34
  • 135
  • 254
  • What is the size of your propertiesCache? I would really expect it to be 1, is it? – Germann Arlington Nov 16 '12 at 11:53
  • @GermannArlington:I really don't know.I only set 1 property so unless `Axis` puts other things in the hashmap under the hood, I can only **assume** 1 entry. The one I set and the OP is about – Jim Nov 16 '12 at 12:28
  • If there is only one entry what is the point of having a HashMap here? P.S. You can always iterate over all entries in the map to find what you have. – Germann Arlington Nov 16 '12 at 12:39
  • @GermannArlington:This is not my code.This is from `axis` – Jim Nov 16 '12 at 14:03

1 Answers1

1

If you know the class loader in question, you can set the context class loader before making the call into axis:

ClassLoader key = ...;
ClassLoader oldCtx = Thread.currentThread().getContextClassLoader();
try {
  Thread.currentThread().setContextClassLoader(key);

  // your code here.
}
finally {
  Thread.currentThread().setContextClassLoader(oldCtx);
}

You often have to do this in cases when you are outside a servlet container, but the library assumes that you are in one. For instance, you have to do this with CXF in an OSGi container, where the semantics of context class loader are not defined. You can use a template like this to keep things clean:

public abstract class CCLTemplate<R>
{
  public R execute( ClassLoader context )
    throws Exception
 {
    ClassLoader oldCtx = Thread.currentThread().getContextClassLoader();
    try {
      Thread.currentThread().setContextClassLoader(context);

      return inContext();
    }
    finally {
      Thread.currentThread().setContextClassLoader(oldCtx);
    }
  }

  public abstract R inContext() throws Exception;
}

And then do this when interacting with Axis:

ClassLoader context = ...;
new CCLTemplate<Void>() {
  public Void inContext() {
    // your code here.
    return null;
  }
}.execute(context);
Christian Trimble
  • 2,126
  • 16
  • 27