This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0f9309c23cba78169529a18144483f5acc8cfc0c Author: opencode <[email protected]> AuthorDate: Tue Oct 20 13:55:02 2026 +0200 Return null from ResourceLinkFactory when the global naming context is unavailable ResourceLinkFactory.getObjectInstance() threw a null pointer exception when a resource link had been registered while the static global naming context had not yet been set, which can happen with embedded start-up ordering because registerGlobalResourceAccess() accepts a null global context. Replace the NPE with the standard "cannot resolve" behaviour: log a warning naming the global resource and return null, which results in the usual namingContext.failResolvingReference NamingException at the lookup site. Add a regression test that reproduces the original NPE with the global context set to null. --- .../apache/naming/factory/LocalStrings.properties | 1 + .../apache/naming/factory/ResourceLinkFactory.java | 13 +++++- .../naming/factory/TestResourceLinkFactory.java | 54 ++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/java/org/apache/naming/factory/LocalStrings.properties b/java/org/apache/naming/factory/LocalStrings.properties index d7e7d9ef9f..78e6e0a0e4 100644 --- a/java/org/apache/naming/factory/LocalStrings.properties +++ b/java/org/apache/naming/factory/LocalStrings.properties @@ -35,6 +35,7 @@ lookupFactory.typeMismatch=The JNDI reference [{0}] was expected to be of type [ resourceFactory.factoryCreationError=Could not create resource factory instance resourceLinkFactory.invalidGlobalContext=Caller provided invalid global context +resourceLinkFactory.noGlobalContext=The global naming context is not available. The local resource link that refers to global resource [{0}] can not be resolved resourceLinkFactory.nullName=The local resource link [{0}] that refers to global resource [{1}] does not specify the required name or global attribute resourceLinkFactory.nullType=The local resource link [{0}] that refers to global resource [{1}] does not specify the required attribute type resourceLinkFactory.unknownType=The local resource link [{0}] that refers to global resource [{1}] specified the unknown type [{2}] diff --git a/java/org/apache/naming/factory/ResourceLinkFactory.java b/java/org/apache/naming/factory/ResourceLinkFactory.java index 725a062cf0..9dbfebde55 100644 --- a/java/org/apache/naming/factory/ResourceLinkFactory.java +++ b/java/org/apache/naming/factory/ResourceLinkFactory.java @@ -26,6 +26,8 @@ import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.spi.ObjectFactory; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; import org.apache.naming.ResourceLinkRef; import org.apache.naming.StringManager; @@ -48,6 +50,8 @@ public class ResourceLinkFactory implements ObjectFactory { */ protected static final StringManager sm = StringManager.getManager(ResourceLinkFactory.class); + private static final Log log = LogFactory.getLog(ResourceLinkFactory.class); + /** * Global naming context. */ @@ -144,7 +148,7 @@ public class ResourceLinkFactory implements ObjectFactory { * @param nameCtx unused * @param environment unused * - * @return the object instance + * @return the object instance or {@code null} if the reference cannot be resolved * * @throws IllegalArgumentException if the type of the reference is missing or does not match the type of the * global resource @@ -169,6 +173,13 @@ public class ResourceLinkFactory implements ObjectFactory { if (!validateGlobalResourceAccess(globalName)) { return null; } + // The global context may be missing if the web application was + // registered before the server created its naming context, which + // can happen with embedded start-up ordering + if (globalContext == null) { + log.warn(sm.getString("resourceLinkFactory.noGlobalContext", globalName)); + return null; + } Object result = globalContext.lookup(globalName); if (result == null) { return null; diff --git a/test/org/apache/naming/factory/TestResourceLinkFactory.java b/test/org/apache/naming/factory/TestResourceLinkFactory.java new file mode 100644 index 0000000000..8ef35d7ca7 --- /dev/null +++ b/test/org/apache/naming/factory/TestResourceLinkFactory.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.naming.factory; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import org.apache.naming.ResourceLinkRef; + +public class TestResourceLinkFactory { + + /* + * Regression test for the case where a resource link has been registered + * before the global context has been set, e.g. when an embedded Tomcat + * initialises the container before the naming context for the server is + * created. Prior to the fix, this resulted in a null pointer exception. + */ + @Test + public void testGetResourceLinkWithoutGlobalContext() throws Exception { + // Arrange: no global context is available and the link is registered + ResourceLinkFactory.setGlobalContext(null); + ResourceLinkFactory.registerGlobalResourceAccess(null, "link", "global"); + ResourceLinkRef ref = new ResourceLinkRef("type", "global", null, null); + ResourceLinkFactory factory = new ResourceLinkFactory(); + // Act + Object result = factory.getObjectInstance(ref, null, null, null); + // Assert + // Since the global context is not available, the link can not be + // resolved + Assert.assertNull(result); + } + + @After + public void tearDown() { + // Remove the registration made by the test so that other tests in the + // same JVM are not affected by it + ResourceLinkFactory.deregisterGlobalResourceAccess(null, "link"); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
