Index: nbproject/project.xml =================================================================== --- nbproject/project.xml (revision 8870) +++ nbproject/project.xml (working copy) @@ -18,6 +18,10 @@ UTF-8 + + /Users/edburns/Documents/chaff/netbeans-hack-links/jsf-api-test + + java jsf-ri/build/generate @@ -47,6 +51,22 @@ jsf-ri/test UTF-8 + + + java + /Users/edburns/Documents/chaff/netbeans-hack-links/jsf-api-test + UTF-8 + + + + java + /Users/edburns/Documents/JavaEE/workareas/mojarra-dependencies/trinidad-assembly-2.0.0-beta-1/src/trinidad-api-2.0.0-beta-1-sources + UTF-8 + + + + /Users/edburns/Documents/JavaEE/workareas/mojarra-dependencies/trinidad-assembly-2.0.0-beta-1/src/trinidad-api-2.0.0-beta-1-sources + @@ -88,6 +108,14 @@ jsf-ri/test + + + /Users/edburns/Documents/chaff/netbeans-hack-links/jsf-api-test + + + + /Users/edburns/Documents/JavaEE/workareas/mojarra-dependencies/trinidad-assembly-2.0.0-beta-1/src/trinidad-api-2.0.0-beta-1-sources + build.xml @@ -109,7 +137,9 @@ jsf-ri/test jsf-api/build/generate jsf-ri/build/generate - dependencies/jars/jsp-api-2.1.jar:dependencies/jars/jstl-1.2.jar:dependencies/jars/validation-api-1.0.0.GA.jar:dependencies/jars/servlet-api-3.0.20100224.jar:dependencies/jars/groovy-all-1.6.9.jar:dependencies/jars/junit-3.8.1.jar:lib/jsf-extensions-test-time.jar:lib/cactus-1.7.1-javaee5.jar:dependencies/jars/cdi-api-1.0-SP1.jar:dependencies/jars/javax.inject-1.0-PFD-1.jar:${container.home}/modules/el-impl.jar:${container.home}/modules/bean-validator.jar:${container.home}/modules/javax.servlet.jsp.jar:${container.home}/modules/javax.servlet.jar + /Users/edburns/Documents/chaff/netbeans-hack-links/jsf-api-test + /Users/edburns/Documents/JavaEE/workareas/mojarra-dependencies/trinidad-assembly-2.0.0-beta-1/src/trinidad-api-2.0.0-beta-1-sources + dependencies/jars/jsp-api-2.1.jar:dependencies/jars/jstl-1.2.jar:dependencies/jars/validation-api-1.0.0.GA.jar:dependencies/jars/servlet-api-3.0.20100224.jar:dependencies/jars/groovy-all-1.6.9.jar:dependencies/jars/junit-3.8.1.jar:lib/jsf-extensions-test-time.jar:lib/cactus-1.7.1-javaee5.jar:dependencies/jars/cdi-api-1.0-SP1.jar:dependencies/jars/javax.inject-1.0-PFD-1.jar:/Users/edburns/Documents/JavaEE/runtimes/glassfish-3.1-mojarra-shared/glassfish3/glassfish/modules/el-impl.jar:/Users/edburns/Documents/JavaEE/runtimes/glassfish-3.1-mojarra-shared/glassfish3/glassfish/modules/bean-validator.jar:/Users/edburns/Documents/JavaEE/runtimes/glassfish-3.1-mojarra-shared/glassfish3/glassfish/modules/javax.servlet.jsp.jar:/Users/edburns/Documents/JavaEE/runtimes/glassfish-3.1-mojarra-shared/glassfish3/glassfish/modules/javax.servlet.jar:jsf-api/build/classes 1.5 Index: jsf-api/src/test/java/javax/faces/component/NamingContainerTestCase.java =================================================================== --- jsf-api/src/test/java/javax/faces/component/NamingContainerTestCase.java (revision 8870) +++ jsf-api/src/test/java/javax/faces/component/NamingContainerTestCase.java (working copy) @@ -117,16 +117,16 @@ request.setAttribute("reqScopeName", "reqScopeValue"); response = new MockHttpServletResponse(); + externalContext = + new MockExternalContext(servletContext, request, response); + lifecycle = new MockLifecycle(); + facesContext = new MockFacesContext(externalContext, lifecycle); // Set up Faces API Objects FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, "com.sun.faces.mock.MockApplicationFactory"); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, "com.sun.faces.mock.MockRenderKitFactory"); - externalContext = - new MockExternalContext(servletContext, request, response); - lifecycle = new MockLifecycle(); - facesContext = new MockFacesContext(externalContext, lifecycle); ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); application = (MockApplication) applicationFactory.getApplication(); Index: jsf-api/src/test/java/javax/faces/component/UIComponentTestCase.java =================================================================== --- jsf-api/src/test/java/javax/faces/component/UIComponentTestCase.java (revision 8870) +++ jsf-api/src/test/java/javax/faces/component/UIComponentTestCase.java (working copy) @@ -164,18 +164,18 @@ request.setAttribute("reqScopeName", "reqScopeValue"); response = new MockHttpServletResponse(); + externalContext = + new MockExternalContext(servletContext, request, response); + Map map = new HashMap(); + externalContext.setRequestParameterMap(map); + lifecycle = new MockLifecycle(); + facesContext = new MockFacesContext(externalContext, lifecycle); // Set up Faces API Objects FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, "com.sun.faces.mock.MockApplicationFactory"); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, "com.sun.faces.mock.MockRenderKitFactory"); - externalContext = - new MockExternalContext(servletContext, request, response); - Map map = new HashMap(); - externalContext.setRequestParameterMap(map); - lifecycle = new MockLifecycle(); - facesContext = new MockFacesContext(externalContext, lifecycle); ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); application = (MockApplication) applicationFactory.getApplication(); Index: jsf-api/src/test/java/javax/faces/validator/ValidatorTestCase.java =================================================================== --- jsf-api/src/test/java/javax/faces/validator/ValidatorTestCase.java (revision 8870) +++ jsf-api/src/test/java/javax/faces/validator/ValidatorTestCase.java (working copy) @@ -124,16 +124,16 @@ request.setAttribute("reqScopeName", "reqScopeValue"); response = new MockHttpServletResponse(); + externalContext = + new MockExternalContext(servletContext, request, response); + lifecycle = new MockLifecycle(); + facesContext = new MockFacesContext(externalContext, lifecycle); // Set up Faces API Objects FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, "com.sun.faces.mock.MockApplicationFactory"); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, "com.sun.faces.mock.MockRenderKitFactory"); - externalContext = - new MockExternalContext(servletContext, request, response); - lifecycle = new MockLifecycle(); - facesContext = new MockFacesContext(externalContext, lifecycle); ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); application = (MockApplication) applicationFactory.getApplication(); Index: jsf-api/src/test/java/javax/faces/webapp/TagTestCaseBase.java =================================================================== --- jsf-api/src/test/java/javax/faces/webapp/TagTestCaseBase.java (revision 8870) +++ jsf-api/src/test/java/javax/faces/webapp/TagTestCaseBase.java (working copy) @@ -142,16 +142,16 @@ pageContext.initialize(servlet, request, response, null, true, 1024, true); + externalContext = + new MockExternalContext(servletContext, request, response); + externalContext.setRequestParameterMap(new HashMap()); + lifecycle = new MockLifecycle(); + facesContext = new MockFacesContext(externalContext, lifecycle); // Set up Faces API Objects FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, "com.sun.faces.mock.MockApplicationFactory"); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, "com.sun.faces.mock.MockRenderKitFactory"); - externalContext = - new MockExternalContext(servletContext, request, response); - externalContext.setRequestParameterMap(new HashMap()); - lifecycle = new MockLifecycle(); - facesContext = new MockFacesContext(externalContext, lifecycle); ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); application = (MockApplication) applicationFactory.getApplication(); Index: jsf-api/src/main/java/javax/faces/FactoryFinder.java =================================================================== --- jsf-api/src/main/java/javax/faces/FactoryFinder.java (revision 8870) +++ jsf-api/src/main/java/javax/faces/FactoryFinder.java (working copy) @@ -67,6 +67,8 @@ import java.lang.reflect.Constructor; import java.net.URL; import java.net.URLConnection; +import java.util.Set; +import javax.faces.context.FacesContext; /** @@ -680,8 +682,8 @@ */ private static final class FactoryManagerCache { - private ConcurrentMap> applicationMap = - new ConcurrentHashMap>(); + private ConcurrentMap> applicationMap = + new ConcurrentHashMap>(); // ------------------------------------------------------ Public Methods @@ -689,8 +691,10 @@ private FactoryManager getApplicationFactoryManager(ClassLoader cl) { + FactoryManagerCacheKey key = new FactoryManagerCacheKey(cl, applicationMap); + while (true) { - Future factories = applicationMap.get(cl); + Future factories = applicationMap.get(key); if (factories == null) { Callable callable = new Callable() { @@ -702,7 +706,7 @@ FutureTask ft = new FutureTask(callable); - factories = applicationMap.putIfAbsent(cl, ft); + factories = applicationMap.putIfAbsent(key, ft); if (factories == null) { factories = ft; ft.run(); @@ -717,14 +721,14 @@ ce.toString(), ce); } - applicationMap.remove(cl); + applicationMap.remove(key); } catch (InterruptedException ie) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, ie.toString(), ie); } - applicationMap.remove(cl); + applicationMap.remove(key); } catch (ExecutionException ee) { throw new FacesException(ee); } @@ -735,14 +739,89 @@ public void removeApplicationFactoryManager(ClassLoader cl) { + FactoryManagerCacheKey key = new FactoryManagerCacheKey(cl, applicationMap); - applicationMap.remove(cl); + applicationMap.remove(key); } } // END FactoryCache + private static final class FactoryManagerCacheKey { + private ClassLoader cl; + private Object context; + private static final String KEY = FactoryFinder.class.getName() + "." + + FactoryManagerCacheKey.class.getSimpleName(); + + public FactoryManagerCacheKey(ClassLoader cl, + Map> factoryMap) { + this.cl = cl; + FacesContext facesContext = FacesContext.getCurrentInstance(); + if (null != facesContext) { + Map appMap = facesContext.getExternalContext().getApplicationMap(); + Object val = appMap.get(KEY); + if (null == val) { + context = new Long(System.currentTimeMillis()); + appMap.put(KEY, context); + } else { + context = val; + } + } else { + // We don't have a FacesContext. + // Our only recourse is to inspect the keys of the + // factoryMap and see if any of them has a classloader + // equal to our argument cl. + Set keys = factoryMap.keySet(); + FactoryManagerCacheKey match = null; + for (FactoryManagerCacheKey cur : keys) { + if (this.cl.equals(cur.cl)) { + match = cur; + if (null != match) { + LOGGER.log(Level.WARNING, "Multiple JSF Applications found on same ClassLoader. Unable to safely determine which FactoryManager instance to use. Defaulting to first match."); + } + } + } + if (null != match) { + this.context = match.context; + } + } + } + + private FactoryManagerCacheKey() {} + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FactoryManagerCacheKey other = (FactoryManagerCacheKey) obj; + if (this.cl != other.cl && (this.cl == null || !this.cl.equals(other.cl))) { + return false; + } + if (this.context != other.context && (this.context == null || !this.context.equals(other.context))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.cl != null ? this.cl.hashCode() : 0); + hash = 97 * hash + (this.context != null ? this.context.hashCode() : 0); + return hash; + } + + + + + } + + /** * Maintains the factories for a single web application. */ Index: jsf-ri/test/com/sun/faces/config/TestFactoryInjection.java =================================================================== --- jsf-ri/test/com/sun/faces/config/TestFactoryInjection.java (revision 8870) +++ jsf-ri/test/com/sun/faces/config/TestFactoryInjection.java (working copy) @@ -235,7 +235,9 @@ // invoke the FactoryConfigProcessor FactoryConfigProcessor fcp = new FactoryConfigProcessor(false); + InitFacesContext initContext = new InitFacesContext(sc); fcp.process(sc, new DocumentInfo[]{new DocumentInfo(d, null)}); + initContext.release(); // now get an FacesContext instance from the Factory and ensure // no injection occured. @@ -264,7 +266,9 @@ // process the document. This should cause the the InjectionFacesContextFactory // to be put into play since there is more than one FacesContextFactory // being configured + initContext = new InitFacesContext(sc); fcp.process(sc, new DocumentInfo[]{new DocumentInfo(d, null)}); + initContext.release(); // get the FacesContextFactory instance. The top-level factory should // be the InjectionFacesContextFactory. Index: jsf-ri/src/main/java/com/sun/faces/config/ConfigureListener.java =================================================================== --- jsf-ri/src/main/java/com/sun/faces/config/ConfigureListener.java (revision 8870) +++ jsf-ri/src/main/java/com/sun/faces/config/ConfigureListener.java (working copy) @@ -348,6 +348,7 @@ ApplicationAssociate.setCurrentInstance(null); // Release the initialization mark on this web application ConfigManager.getInstance().destory(context); + FactoryFinder.releaseFactories(); if (initContext != null) { initContext.release(); } Index: jsf-ri/build.xml =================================================================== --- jsf-ri/build.xml (revision 8870) +++ jsf-ri/build.xml (working copy) @@ -700,7 +700,7 @@ - @@ -715,6 +715,14 @@ + + + + + + + Index: jsf-ri/build-tests.xml =================================================================== --- jsf-ri/build-tests.xml (revision 8870) +++ jsf-ri/build-tests.xml (working copy) @@ -552,8 +552,6 @@ - - + name="com.sun.faces.config.TestFactoryInjection"/> Index: jsf-ri/systest-per-webapp/build.xml =================================================================== --- jsf-ri/systest-per-webapp/build.xml (revision 8870) +++ jsf-ri/systest-per-webapp/build.xml (working copy) @@ -165,6 +165,7 @@ + Index: jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/SimplePhaseListener.java =================================================================== --- jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/SimplePhaseListener.java (revision 8870) +++ jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/SimplePhaseListener.java (working copy) @@ -43,6 +43,7 @@ import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; +import java.util.Map; public class SimplePhaseListener implements PhaseListener { @@ -57,8 +58,12 @@ public void beforePhase(PhaseEvent event) { - event.getFacesContext().getExternalContext().getRequestMap().put("beforePhase", - "beforePhase"); + Map requestMap = + event.getFacesContext().getExternalContext().getRequestMap(); + String message = requestMap.containsKey("beforePhase") ? + requestMap.get("beforePhase").toString() : ""; + requestMap.put("beforePhase", + message + " beforePhase"); event.getFacesContext().getExternalContext().getRequestMap().put("lifecycleImpl", event.getSource()); } Index: jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/ReplaceLifecycleTestCase.java =================================================================== --- jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/ReplaceLifecycleTestCase.java (revision 8870) +++ jsf-ri/systest-per-webapp/replace-lifecycle/src/java/com/sun/faces/systest/ReplaceLifecycleTestCase.java (working copy) @@ -128,7 +128,10 @@ public void testReplaceLifecycle() throws Exception { HtmlPage page = getPage("/faces/test.jsp"); - assertTrue(-1 != page.asText().indexOf("beforePhase")); + String pageText = page.asText(); + assertTrue(-1 != pageText.indexOf("beforePhase")); + // Ensure the phaseListener is only called once. + assertTrue(!pageText.matches("(?s).*beforePhase.*beforePhase.*")); } Index: lib/jsf-extensions-test-time.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream