From f60aa3db33cc2df868ee6602e4d589d5f91d9c43 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Fri, 26 Jul 2024 00:40:02 +0200 Subject: [PATCH] Move global EL resolvers from static variables to application variables (#5461) This avoids sharing resolvers between multiple applications on the classpath and also avoids memory leaks in application servers after an application and its classloaders are undeployed. --- .../application/ApplicationAssociate.java | 17 +++++-- .../faces/application/ApplicationImpl.java | 6 +++ .../faces/application/ResolversRegistry.java | 43 ++++++++++++++++++ .../main/java/com/sun/faces/el/ELUtils.java | 44 ++++++------------- 4 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 impl/src/main/java/com/sun/faces/application/ResolversRegistry.java diff --git a/impl/src/main/java/com/sun/faces/application/ApplicationAssociate.java b/impl/src/main/java/com/sun/faces/application/ApplicationAssociate.java index 36d61b5bcb..761b51a466 100644 --- a/impl/src/main/java/com/sun/faces/application/ApplicationAssociate.java +++ b/impl/src/main/java/com/sun/faces/application/ApplicationAssociate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Contributors to Eclipse Foundation. + * Copyright (c) 2021, 2024 Contributors to Eclipse Foundation. * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -79,8 +79,8 @@ import com.sun.faces.facelets.util.FunctionLibrary; import com.sun.faces.spi.InjectionProvider; import com.sun.faces.util.FacesLogger; - import jakarta.el.CompositeELResolver; + import jakarta.el.ELResolver; import jakarta.el.ExpressionFactory; import jakarta.faces.FacesException; @@ -181,7 +181,6 @@ protected ApplicationAssociate initialValue() { Map resourceBundles = new HashMap<>(); - public static void setCurrentInstance(ApplicationAssociate associate) { if (associate == null) { instance.remove(); @@ -473,6 +472,10 @@ public InjectionProvider getInjectionProvider() { return injectionProvider; } + public ResolversRegistry getGlobalResolversRegistry() { + return applicationImpl.getGlobalResolversRegistry(); + } + public void setContextName(String contextName) { this.contextName = contextName; } @@ -569,6 +572,14 @@ public ResourceBundle getResourceBundle(FacesContext context, String var) { return bundle.getResourceBundle(locale); } + /** + * Returns a container with EL resolvers global to this application associate + * @return global EL resolvers for the current application + */ + public ResolversRegistry getApplicationResolvers() { + return applicationImpl.getGlobalResolversRegistry(); + } + /** * keys: element from faces-config *

diff --git a/impl/src/main/java/com/sun/faces/application/ApplicationImpl.java b/impl/src/main/java/com/sun/faces/application/ApplicationImpl.java index 4d7af14f85..1d2ecae3a4 100644 --- a/impl/src/main/java/com/sun/faces/application/ApplicationImpl.java +++ b/impl/src/main/java/com/sun/faces/application/ApplicationImpl.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 Contributors to Eclipse Foundation. * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -81,6 +82,7 @@ public class ApplicationImpl extends Application { private final InstanceFactory instanceFactory; private final SearchExpression searchExpression; private final Stage stage; + private final ResolversRegistry globalResolversRegistry = new ResolversRegistry(); /** * Constructor @@ -212,6 +214,10 @@ public CompositeELResolver getApplicationELResolvers() { return expressionLanguage.getApplicationELResolvers(); } + public ResolversRegistry getGlobalResolversRegistry() { + return globalResolversRegistry; + } + public FacesCompositeELResolver getCompositeELResolver() { return expressionLanguage.getCompositeELResolver(); } diff --git a/impl/src/main/java/com/sun/faces/application/ResolversRegistry.java b/impl/src/main/java/com/sun/faces/application/ResolversRegistry.java new file mode 100644 index 0000000000..d50bfbe8c7 --- /dev/null +++ b/impl/src/main/java/com/sun/faces/application/ResolversRegistry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Contributors to Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package com.sun.faces.application; + +import com.sun.faces.context.flash.FlashELResolver; +import com.sun.faces.el.CompositeComponentAttributesELResolver; +import com.sun.faces.el.EmptyStringToNullELResolver; +import com.sun.faces.el.FacesResourceBundleELResolver; +import com.sun.faces.el.ResourceELResolver; +import com.sun.faces.el.ScopedAttributeELResolver; +import jakarta.el.ArrayELResolver; +import jakarta.el.BeanELResolver; +import jakarta.el.ListELResolver; +import jakarta.el.MapELResolver; +import jakarta.el.ResourceBundleELResolver; + +public class ResolversRegistry { + public final BeanELResolver BEAN_RESOLVER = new BeanELResolver(); + public final ArrayELResolver ARRAY_RESOLVER = new ArrayELResolver(); + public final FacesResourceBundleELResolver FACES_BUNDLE_RESOLVER = new FacesResourceBundleELResolver(); + public final FlashELResolver FLASH_RESOLVER = new FlashELResolver(); + public final ListELResolver LIST_RESOLVER = new ListELResolver(); + public final MapELResolver MAP_RESOLVER = new MapELResolver(); + public final ResourceBundleELResolver BUNDLE_RESOLVER = new ResourceBundleELResolver(); + public final ScopedAttributeELResolver SCOPED_RESOLVER = new ScopedAttributeELResolver(); + public final ResourceELResolver RESOURCE_RESOLVER = new ResourceELResolver(); + public final CompositeComponentAttributesELResolver COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER = new CompositeComponentAttributesELResolver(); + public final EmptyStringToNullELResolver EMPTY_STRING_TO_NULL_RESOLVER = new EmptyStringToNullELResolver(); + +} diff --git a/impl/src/main/java/com/sun/faces/el/ELUtils.java b/impl/src/main/java/com/sun/faces/el/ELUtils.java index dee44542e7..d48b905ceb 100644 --- a/impl/src/main/java/com/sun/faces/el/ELUtils.java +++ b/impl/src/main/java/com/sun/faces/el/ELUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2023, 2024 Contributors to Eclipse Foundation. * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -30,18 +31,12 @@ import java.util.regex.Pattern; import com.sun.faces.application.ApplicationAssociate; +import com.sun.faces.application.ResolversRegistry; import com.sun.faces.config.WebConfiguration; -import com.sun.faces.context.flash.FlashELResolver; - -import jakarta.el.ArrayELResolver; -import jakarta.el.BeanELResolver; import jakarta.el.CompositeELResolver; import jakarta.el.ELContext; import jakarta.el.ELResolver; import jakarta.el.ExpressionFactory; -import jakarta.el.ListELResolver; -import jakarta.el.MapELResolver; -import jakarta.el.ResourceBundleELResolver; import jakarta.el.ValueExpression; import jakarta.enterprise.inject.spi.BeanManager; import jakarta.faces.context.ExternalContext; @@ -103,18 +98,6 @@ public class ELUtils { */ private static final Pattern METHOD_EXPRESSION_LOOKUP = Pattern.compile(".[{]cc[.]attrs[.]\\w+[}]"); - public static final ArrayELResolver ARRAY_RESOLVER = new ArrayELResolver(); - public static final BeanELResolver BEAN_RESOLVER = new BeanELResolver(); - public static final FacesResourceBundleELResolver FACES_BUNDLE_RESOLVER = new FacesResourceBundleELResolver(); - public static final FlashELResolver FLASH_RESOLVER = new FlashELResolver(); - public static final ListELResolver LIST_RESOLVER = new ListELResolver(); - public static final MapELResolver MAP_RESOLVER = new MapELResolver(); - public static final ResourceBundleELResolver BUNDLE_RESOLVER = new ResourceBundleELResolver(); - public static final ScopedAttributeELResolver SCOPED_RESOLVER = new ScopedAttributeELResolver(); - public static final ResourceELResolver RESOURCE_RESOLVER = new ResourceELResolver(); - public static final CompositeComponentAttributesELResolver COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER = new CompositeComponentAttributesELResolver(); - public static final EmptyStringToNullELResolver EMPTY_STRING_TO_NULL_RESOLVER = new EmptyStringToNullELResolver(); - // ------------------------------------------------------------ Constructors private ELUtils() { @@ -164,24 +147,25 @@ public static boolean isCompositeComponentLookupWithArgs(String expression) { public static void buildFacesResolver(FacesCompositeELResolver composite, ApplicationAssociate associate) { checkNotNull(composite, associate); addCDIELResolver(composite); - composite.add(FLASH_RESOLVER); - composite.addPropertyELResolver(COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER); + ResolversRegistry elRegistry = associate.getGlobalResolversRegistry(); + composite.add(elRegistry.FLASH_RESOLVER); + composite.addPropertyELResolver(elRegistry.COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER); addELResolvers(composite, associate.getELResolversFromFacesConfig()); composite.add(associate.getApplicationELResolvers()); if (WebConfiguration.getInstance().isOptionEnabled(InterpretEmptyStringSubmittedValuesAsNull)) { - composite.addPropertyELResolver(EMPTY_STRING_TO_NULL_RESOLVER); + composite.addPropertyELResolver(elRegistry.EMPTY_STRING_TO_NULL_RESOLVER); } - composite.addPropertyELResolver(RESOURCE_RESOLVER); - composite.addPropertyELResolver(BUNDLE_RESOLVER); - composite.addRootELResolver(FACES_BUNDLE_RESOLVER); + composite.addPropertyELResolver(elRegistry.RESOURCE_RESOLVER); + composite.addPropertyELResolver(elRegistry.BUNDLE_RESOLVER); + composite.addRootELResolver(elRegistry.FACES_BUNDLE_RESOLVER); addEL3_0_Resolvers(composite, associate); - composite.addPropertyELResolver(MAP_RESOLVER); - composite.addPropertyELResolver(LIST_RESOLVER); - composite.addPropertyELResolver(ARRAY_RESOLVER); - composite.addPropertyELResolver(BEAN_RESOLVER); - composite.addRootELResolver(SCOPED_RESOLVER); + composite.addPropertyELResolver(elRegistry.MAP_RESOLVER); + composite.addPropertyELResolver(elRegistry.LIST_RESOLVER); + composite.addPropertyELResolver(elRegistry.ARRAY_RESOLVER); + composite.addPropertyELResolver(elRegistry.BEAN_RESOLVER); + composite.addRootELResolver(elRegistry.SCOPED_RESOLVER); } private static void checkNotNull(FacesCompositeELResolver composite, ApplicationAssociate associate) {