diff --git a/jsf/subsystem/pom.xml b/jsf/subsystem/pom.xml index bf8fce622b63..c5b75427ab82 100644 --- a/jsf/subsystem/pom.xml +++ b/jsf/subsystem/pom.xml @@ -67,6 +67,11 @@ jakarta.enterprise.cdi-api + + jakarta.servlet + jakarta.servlet-api + + jakarta.validation jakarta.validation-api diff --git a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java index 5c4d925a999a..6fd7a15d93be 100644 --- a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java +++ b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/JSFMetadataProcessor.java @@ -10,6 +10,7 @@ import jakarta.faces.application.ViewHandler; import org.jboss.as.jsf.logging.JSFLogger; +import org.jboss.as.jsf.subsystem.JSFResourceDefinition; import org.jboss.as.server.deployment.DeploymentPhaseContext; import org.jboss.as.server.deployment.DeploymentUnit; import org.jboss.as.server.deployment.DeploymentUnitProcessingException; @@ -18,8 +19,11 @@ import org.jboss.metadata.javaee.spec.ParamValueMetaData; import org.jboss.metadata.web.jboss.JBossServletMetaData; import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; import org.jboss.metadata.web.spec.MultipartConfigMetaData; +import com.sun.faces.config.ConfigureListener; + /** * @author Stuart Douglas */ @@ -66,11 +70,12 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro if(JsfVersionMarker.isJsfDisabled(deploymentUnit)) { return; } - if(metaData == null || metaData.getMergedJBossWebMetaData() == null || metaData.getMergedJBossWebMetaData().getServlets() == null) { + JBossWebMetaData webMetaData = (metaData != null) ? metaData.getMergedJBossWebMetaData() : null; + if (webMetaData == null || webMetaData.getServlets() == null) { return; } JBossServletMetaData jsf = null; - for(JBossServletMetaData servlet : metaData.getMergedJBossWebMetaData().getServlets()) { + for(JBossServletMetaData servlet : webMetaData.getServlets()) { if(JAVAX_FACES_WEBAPP_FACES_SERVLET.equals(servlet.getServletClass())) { jsf = servlet; } @@ -81,22 +86,34 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro } if (disallowDoctypeDecl != null) { // Add the disallowDoctypeDecl context param if it's not already present - setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), DISALLOW_DOCTYPE_DECL, disallowDoctypeDecl.toString()); + setContextParameterIfAbsent(webMetaData, DISALLOW_DOCTYPE_DECL, disallowDoctypeDecl.toString()); } - // Auto-disable lazy bean validation for distributable web application. - // This can otherwise cause missing @PreDestroy events. - if (metaData.getMergedJBossWebMetaData().getDistributable() != null) { + if (webMetaData.getDistributable() != null) { + // Auto-disable lazy bean validation for distributable web application. + // This can otherwise cause missing @PreDestroy events. String disabled = Boolean.toString(false); - if (!setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), LAZY_BEAN_VALIDATION_PARAM, disabled).equals(disabled)) { + if (!setContextParameterIfAbsent(webMetaData, LAZY_BEAN_VALIDATION_PARAM, disabled).equals(disabled)) { JSFLogger.ROOT_LOGGER.lazyBeanValidationEnabled(); } + + String version = JsfVersionMarker.getVersion(deploymentUnit); + // Disable counter-productive "distributable" logic in Mojarra implementation + if (version.equals(JsfVersionMarker.JSF_4_0) && JSFModuleIdFactory.getInstance().getImplModId(version).getSlot().equals(JSFResourceDefinition.DEFAULT_SLOT)) { + ListenerMetaData mojarraListenerMetaData = new ListenerMetaData(); + mojarraListenerMetaData.setListenerClass(ConfigureListener.class.getName()); + ListenerMetaData workaroundListenerMetaData = new ListenerMetaData(); + workaroundListenerMetaData.setListenerClass(NonDistributableServletContextListener.class.getName()); + + webMetaData.getListeners().add(mojarraListenerMetaData); + // Ensure workaround listener runs after Mojarra's bootstrap listener + webMetaData.getListeners().add(workaroundListenerMetaData); + } } // Set a default buffer size as 1024 is too small - final JBossWebMetaData webMetaData = metaData.getMergedJBossWebMetaData(); // First check the legacy facelets.BUFFER_SIZE property which is required for backwards compatibility if (!hasContextParam(webMetaData, "facelets.BUFFER_SIZE")) { // The legacy parameter has not been set, set a default buffer if the current parameter name has not been set. - setContextParameterIfAbsent(metaData.getMergedJBossWebMetaData(), ViewHandler.FACELETS_BUFFER_SIZE_PARAM_NAME, Integer.toString(defaultBufferSize)); + setContextParameterIfAbsent(webMetaData, ViewHandler.FACELETS_BUFFER_SIZE_PARAM_NAME, Integer.toString(defaultBufferSize)); } } diff --git a/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java new file mode 100644 index 000000000000..cb83372e17d2 --- /dev/null +++ b/jsf/subsystem/src/main/java/org/jboss/as/jsf/deployment/NonDistributableServletContextListener.java @@ -0,0 +1,32 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.as.jsf.deployment; + +import jakarta.faces.context.FacesContext; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; + +import com.sun.faces.config.InitFacesContext; +import com.sun.faces.config.WebConfiguration; + +/** + * Workaround for counter-productive "distributable" logic in Mojarra. + * This setting is used to trigger redundant calls to HttpSession.setAttribute(...) for mutated attributes. + */ +public class NonDistributableServletContextListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent event) { + ServletContext context = event.getServletContext(); + FacesContext facesContext = new InitFacesContext(context); + try { + WebConfiguration.getInstance(context).setOptionEnabled(WebConfiguration.BooleanWebContextInitParameter.EnableDistributable, false); + context.setAttribute(WebConfiguration.BooleanWebContextInitParameter.EnableDistributable.getQualifiedName(), Boolean.FALSE); + } finally { + facesContext.release(); + } + } +}