Ales Justin [
http://community.jboss.org/people/alesj] created the discussion
"Wildcard support in Dynamic-imports"
To view the discussion, visit:
http://community.jboss.org/message/543069#543069
--------------------------------------------------------------
I've implemented an initial version of wildcard support.
e.g. Dynamic-import: com.acme.foo.*
When creating lazy delegate in Module (which we do for all dynamic requirements),
we differentiate between wildcards and plain dynamic import.
if (pr.isWildcard())
{
ClassLoaderPolicyFactory factory = new
WildcardClassLoaderPolicyFactory(domain, item);
return new WildcardDelegateLoader(factory, filter);
}
Our wildcard policy tracks potential matching modules via ModuleRegistry notion from
ClassLoading instance.
Hence wildcard factory registers the policy as a listener.
public ClassLoaderPolicy createClassLoaderPolicy()
{
WildcardClassLoaderPolicy policy = new WildcardClassLoaderPolicy(domain,
requirement, module);
ClassLoading classLoading = domain.getClassLoading();
classLoading.addModuleRegistry(policy); // so we know when to reset on module
change
return policy;
}
What our wildcard policy does is actually delegation to other existing matching modules.
public URL getResource(String path)
{
Module cached = resourceCache.get(path);
if (cached != null)
return cached.getResource(path);
ClassFilter filter = requirement.toClassFilter();
if (filter.matchesResourcePath(path))
{
for (Module m : modules)
{
URL url = m.getResource(path);
if (url != null)
{
resourceCache.put(path, m);
used.add(m);
return url;
}
}
}
return null;
}
"modules" list gets populated via tracking, where we only include potential
matching modules.
public void addModule(Module module)
{
Domain md = getDomain(module);
if (md != null && module.canResolve(requirement))
{
boolean isAncestor = (domain != md); // not the same domain, so it must be
ancestor
synchronized (this)
{
if (isAncestor)
{
if (domain.isParentFirst())
{
modules.add(0, module);
parentsBefore++;
}
else
modules.add(module);
}
else
modules.add(parentsBefore, module);
}
reset();
}
}
Same on removal, where we also try to bounce our module if we see that some module we used
went away.
We also remove ourselves from module listening when undeploying.
public void removeModule(Module module)
{
synchronized (this)
{
if (modules.remove(module))
{
Domain md = getDomain(module);
boolean isAncestor = (domain != md);
if (isAncestor && domain.isParentFirst())
parentsBefore--;
reset();
}
}
boolean sameModule = this.module == module;
// Unregister this policy as module listener
if (sameModule)
{
ClassLoading classLoading = domain.getClassLoading();
classLoading.removeModuleRegistry(this);
this.module = null;
}
// It's not us (we're already uninstalling) and we used this, let's
bounce.
if (used.remove(module) && sameModule == false)
{
LifeCycle lifeCycle = this.module.getLifeCycle();
if (lifeCycle != null && module.isCascadeShutdown() == false)
{
try
{
lifeCycle.bounce();
}
catch (Exception e)
{
throw new IllegalArgumentException("Error bouncing module: " +
this.module);
}
}
}
}
Then comes the tricky part. :-)
Since the policy is mostly just used to find the matching resource, where its underlying
classloader should do the real loading.
But in our case where we delegate all of the things, this needed some hacking into
existing code.
To find the right ClassLoader I hacked BaseDelegateLoader's getBaseClassLoader method
to protected (don't see why it should really be pckg protected), and then overriden it
in WildcardDelegateLoader.
protected BaseClassLoader getBaseClassLoader(String message, String context)
{
ClassLoaderPolicy policy = getPolicy();
if (policy instanceof WildcardClassLoaderPolicy == false)
throw new IllegalArgumentException("Can only handle wildcard policy: "
+ policy);
WildcardClassLoaderPolicy wclp = (WildcardClassLoaderPolicy) policy;
return wclp.getBaseClassLoader(context);
}
Which then delegates to the policy with additional context parameter -- which is really
the path of the requested resource.
BaseClassLoader getBaseClassLoader(String context)
{
Module m = findModule(context);
if (m != null)
{
ClassLoader cl = ClassLoading.getClassLoaderForModule(m);
if (cl instanceof BaseClassLoader)
return BaseClassLoader.class.cast(cl);
}
return null;
}
But the changes don't stop there, as the ClassLoadingManager/Task also asume there is
a single matching classloader.
So, I introduced a new protected method on BaseClassLoaderPolicy.
/**
* Get the classloader based on classloading task.
*
* Since ClassLoadingTask ctor is package protected
* this method cannot be easily abused, since the only
* code that can instantiate ClassLoadingTask is our ClassLoaderManager.
*
* @param task the classloading task info
* @return the classloader
*/
protected synchronized BaseClassLoader getClassLoader(ClassLoadingTask task)
{
return getClassLoader();
}
Which is then overriden in wildcard policy.
protected BaseClassLoader getClassLoader(ClassLoadingTask task)
{
if (task == null)
throw new IllegalArgumentException("Null task");
String path = ClassLoaderUtils.classNameToPath(task.getClassName());
return getBaseClassLoader(path);
}
--------------------------------------------------------------
Reply to this message by going to Community
[
http://community.jboss.org/message/543069#543069]
Start a new discussion in JBoss Microcontainer Development at Community
[
http://community.jboss.org/choose-container!input.jspa?contentType=1&...]