TAP5-2657: blacklist for manifest autoloaded modules
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/IOCUtilities.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/IOCUtilities.java
index d45b1b9..c14e5a5 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/IOCUtilities.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/IOCUtilities.java
@@ -16,7 +16,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
import java.util.jar.Manifest;
import org.apache.tapestry5.commons.util.ExceptionUtils;
@@ -57,6 +60,8 @@
* Scans the classpath for JAR Manifests that contain the Tapestry-Module-Classes attribute and adds each
* corresponding class to the RegistryBuilder. In addition, looks for a system property named "tapestry.modules" and
* adds all of those modules as well. The tapestry.modules approach is intended for development.
+ * To prevent auto-loading of Manifest-defined modules the system property named "tapestry.manifest-modules-blacklist"
+ * can be used.
*
* @param builder
* the builder to which modules will be added
@@ -65,6 +70,19 @@
*/
public static void addDefaultModules(RegistryBuilder builder)
{
+ Set<String> blacklistedManifestModules = new HashSet<>();
+ String modulesBlacklist = System.getProperty("tapestry.manifest-modules-blacklist");
+ if (modulesBlacklist != null)
+ {
+ String[] blacklistedClassnames = modulesBlacklist.split(",");
+
+
+ for (String classname : blacklistedClassnames)
+ {
+ blacklistedManifestModules.add(classname.trim());
+ }
+ }
+
try
{
Enumeration<URL> urls = builder.getClassLoader().getResources("META-INF/MANIFEST.MF");
@@ -73,7 +91,7 @@
{
URL url = urls.nextElement();
- addModulesInManifest(builder, url);
+ addModulesInManifest(builder, url, blacklistedManifestModules);
}
addModulesInList(builder, System.getProperty("tapestry.modules"));
@@ -84,7 +102,7 @@
}
}
- private static void addModulesInManifest(RegistryBuilder builder, URL url)
+ private static void addModulesInManifest(RegistryBuilder builder, URL url, Set<String> blacklist)
{
InputStream in = null;
@@ -102,7 +120,7 @@
String list = mf.getMainAttributes().getValue(MODULE_BUILDER_MANIFEST_ENTRY_NAME);
- addModulesInList(builder, list);
+ addModulesInList(builder, list, blacklist);
} catch (RuntimeException ex)
{
fail = ex;
@@ -123,13 +141,24 @@
static void addModulesInList(RegistryBuilder builder, String list)
{
+ addModulesInList(builder, list, Collections.emptySet());
+ }
+
+ static void addModulesInList(RegistryBuilder builder, String list, Set<String> blacklist)
+ {
if (list == null) return;
String[] classnames = list.split(",");
for (String classname : classnames)
{
- builder.add(classname.trim());
+ String trimmedClassname = classname.trim();
+ if (blacklist != null && blacklist.contains(trimmedClassname))
+ {
+ continue;
+ }
+
+ builder.add(trimmedClassname);
}
}
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ManifestProcessingSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ManifestProcessingSpec.groovy
index 8c13398..ac76bc5 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ManifestProcessingSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ManifestProcessingSpec.groovy
@@ -1,7 +1,10 @@
package ioc.specs
+import com.example.ManifestModule
+
import org.apache.tapestry5.ioc.IOCUtilities
import org.apache.tapestry5.ioc.RegistryBuilder
+
import spock.lang.Specification
class ManifestProcessingSpec extends Specification {
@@ -31,7 +34,119 @@
e.message.contains "Exception loading module(s) from manifest"
e.message.contains "Failure loading Tapestry IoC module class does.not.exist.Module"
-
-
}
+
+ def "valid class in manifest"() {
+
+ given:
+
+ File jar = new File("src/test/realjar")
+
+ expect:
+
+ // This is more to verify the module execution environment
+ jar.exists()
+ jar.isDirectory()
+
+ when:
+
+ URL url = jar.toURL()
+ URLClassLoader loader = new URLClassLoader([url] as URL[], Thread.currentThread().contextClassLoader)
+
+ RegistryBuilder builder = new RegistryBuilder(loader)
+
+ IOCUtilities.addDefaultModules(builder)
+
+ def reg = builder.build()
+ reg.performRegistryStartup()
+
+ then:
+
+ noExceptionThrown()
+
+ ManifestModule.startupCalled == true
+
+ cleanup:
+
+ ManifestModule.startupCalled = false
+ }
+
+ def "blacklisted manifest module not loaded"() {
+
+ given:
+
+ File jar = new File("src/test/realjar")
+
+ def props = System.getProperties()
+ props.setProperty("tapestry.manifest-modules-blacklist", "does.not.ExistModule,com.example.ManifestModule")
+
+ expect:
+
+ // This is more to verify the module execution environment
+ jar.exists()
+ jar.isDirectory()
+
+ when:
+
+ URL url = jar.toURL()
+ URLClassLoader loader = new URLClassLoader([url] as URL[], Thread.currentThread().contextClassLoader)
+
+ RegistryBuilder builder = new RegistryBuilder(loader)
+
+ IOCUtilities.addDefaultModules(builder)
+
+ def reg = builder.build()
+ reg.performRegistryStartup()
+
+ then:
+
+ noExceptionThrown()
+
+ ManifestModule.startupCalled == false
+
+ cleanup:
+
+ props.remove("tapestry.manifest-modules-blacklist")
+ ManifestModule.startupCalled = false
+ }
+
+ def "blacklisted manifest module empty"() {
+
+ given:
+
+ File jar = new File("src/test/realjar")
+
+ def props = System.getProperties()
+ props.setProperty("tapestry.manifest-modules-blacklist", "")
+
+ expect:
+
+ // This is more to verify the module execution environment
+ jar.exists()
+ jar.isDirectory()
+
+ when:
+
+ URL url = jar.toURL()
+ URLClassLoader loader = new URLClassLoader([url] as URL[], Thread.currentThread().contextClassLoader)
+
+ RegistryBuilder builder = new RegistryBuilder(loader)
+
+ IOCUtilities.addDefaultModules(builder)
+
+ def reg = builder.build()
+ reg.performRegistryStartup()
+
+ then:
+
+ noExceptionThrown()
+
+ ManifestModule.startupCalled == true
+
+ cleanup:
+
+ props.remove("tapestry.manifest-modules-blacklist")
+ ManifestModule.startupCalled = false
+ }
+
}
diff --git a/tapestry-ioc/src/test/java/com/example/ManifestModule.java b/tapestry-ioc/src/test/java/com/example/ManifestModule.java
new file mode 100644
index 0000000..b09eec3
--- /dev/null
+++ b/tapestry-ioc/src/test/java/com/example/ManifestModule.java
@@ -0,0 +1,29 @@
+// Copyright 2021 The Apache Software Foundation
+//
+// Licensed 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 com.example;
+
+import org.apache.tapestry5.ioc.annotations.Startup;
+
+public class ManifestModule
+{
+ public static boolean startupCalled = false;
+
+ @Startup
+ public void doStartup()
+ {
+ ManifestModule.startupCalled = true;
+ }
+
+}
diff --git a/tapestry-ioc/src/test/realjar/META-INF/MANIFEST.MF b/tapestry-ioc/src/test/realjar/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..bfcd412
--- /dev/null
+++ b/tapestry-ioc/src/test/realjar/META-INF/MANIFEST.MF
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Archiver-Version: Plexus Archiver
+Created-By: Apache Maven
+Built-By: Ben
+Build-Jdk: 1.8.0_271
+Tapestry-Module-Classes: com.example.ManifestModule
+