ContextualHttpServletRequest and class loading
7rond Oct 2, 2008 4:10 AMHello
I've gotten into a problem with the ContextualHttpServletRequest class, specifically when it comes to class loading.
My application structure is as follows;
- core.ear - the core of the app, with code shared amongst the webapps deployed as standalone wars. no loader repository configured in jboss-app.xml, and no seam jars are bundled, they are all located in server/default/lib
- app1.war - a webapp using code from core.ear
- app2.war - a webapp using code from core.ear, but which also have a component overriding a component in core.ear
The overridden component mentioned is a SiteContext class that contains context info about the current site (loaded from the database on seam initialization and stored in a APPLICATION-scoped component, as such;
@Name("siteContext") @Install(precedence = Install.FRAMEWORK) @Scope(ScopeType.APPLICATION) public class SiteContext implements Serializable { }
This class is placed inside the ear and loaded by the UnifiedClassLoader for the ear itself, which I've verified running heaps of tests around this to try to localize the problem.
Then I have a class overriding the SiteContext for that specific application, located in WEB-INF/classes in app2.war. This class is loaded by the URLClassLoader for the app2.war, as expected;
@Name("siteContext") @Install(precedence = Install.APPLICATION) @Scope(ScopeType.SESSION) public class AdminSiteContext extends SiteContext { }
Now, for the problem. Anything, anywhere, that requests a SiteContext as such;
@In private SiteContext siteContext
Will get the proper SiteContext instance. Everything residing in app1.war gets the SiteContext.class instance, everything residing in app2.war gets the AdminSiteContext.class instance.
The problem arises when I try to load the SiteContext component in a method wrapped by the ContextualHttpServletRequest class. What I'm trying to accomplish is a Seam Resource Servlet provider that checks for access rules and such against the resources it's going to provide before showing them to the client. The class is placed inside the ear, and I've implemented the provider as such;
public class MyCustomResource extends AbstractResource { @Override public void getResource(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { new ContextualHttpServletRequest(request) { @Override public void process() throws IOException { serveResource(request, response); } }.run(); } public void serveResource(HttpServletRequest request, HttpServletResponse response) { SiteContext siteContext = Component.getInstance("siteContext"); } }
This is where it starts to go haywire. Any webapp (both app1 and app2) get a instance of the AdminSiteContext.class here, and it's loaded by the URLClassLoader of app2.
How did this make it into my resource provider from both apps, and not just app2 which should be the only app ever to see this class? I've tested and reproduced the same result with a custom, basic servlet extending from HttpServlet instead of AbstractResource and I get exactly the same result. I have configured the context filter in my components.xml for both applications to cover both the test servlet and the seam resource servlet. Both webapps are loaded within their own loader repository, which I've also validated that's properly configured by going through debug log data from the JBoss logs.
Also, I started a thread yesterday about another issue which presumably was this issue all along. I started a new thread to get it more on track since I cannot comprehend this is a issue with anything but the ContextualHttpServletRequest class as it's working as intended in every other aspect of Seam. :)