Skip to content

Commit 9119c06

Browse files
committed
W-17340911: Resolve loader constraint violation when policy isolation is enabled
1 parent 70b90f1 commit 9119c06

File tree

6 files changed

+166
-5
lines changed

6 files changed

+166
-5
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023 Salesforce, Inc. All rights reserved.
3+
* The software in this package is published under the terms of the CPAL v1.0
4+
* license, a copy of which has been included with this distribution in the
5+
* LICENSE.txt file.
6+
*/
7+
package org.mule.runtime.container.internal;
8+
9+
import static org.mule.runtime.api.util.Preconditions.checkArgument;
10+
11+
import org.mule.runtime.module.artifact.api.classloader.MuleDeployableArtifactClassLoader;
12+
import org.mule.runtime.module.artifact.api.classloader.RegionClassLoader;
13+
import org.mule.runtime.module.artifact.api.descriptor.DeployableArtifactDescriptor;
14+
15+
import java.net.URL;
16+
17+
public class IsolatedPolicyClassLoader extends MuleDeployableArtifactClassLoader {
18+
19+
private static IsolatedPolicyClassLoader instance;
20+
21+
private IsolatedPolicyClassLoader(String artifactId,
22+
DeployableArtifactDescriptor artifactDescriptor,
23+
RegionClassLoader regionClassLoader) {
24+
super(artifactId, artifactDescriptor, new URL[0], regionClassLoader, regionClassLoader.getClassLoaderLookupPolicy());
25+
}
26+
27+
public static synchronized IsolatedPolicyClassLoader getInstance(RegionClassLoader regionClassLoader) {
28+
checkArgument(regionClassLoader != null, "regionClassLoader cannot be null");
29+
if (instance == null) {
30+
instance = new IsolatedPolicyClassLoader(
31+
"isolated-policy-classloader",
32+
new DeployableArtifactDescriptor("isolated-policy-descriptor"),
33+
regionClassLoader);
34+
}
35+
return instance;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2023 Salesforce, Inc. All rights reserved.
3+
* The software in this package is published under the terms of the CPAL v1.0
4+
* license, a copy of which has been included with this distribution in the
5+
* LICENSE.txt file.
6+
*/
7+
package org.mule.runtime.container.internal;
8+
9+
import static org.hamcrest.CoreMatchers.is;
10+
import static org.hamcrest.MatcherAssert.assertThat;
11+
import static org.mockito.Mockito.mock;
12+
import static org.mockito.Mockito.when;
13+
14+
import org.mule.runtime.module.artifact.api.classloader.ClassLoaderLookupPolicy;
15+
import org.mule.runtime.module.artifact.api.classloader.RegionClassLoader;
16+
import org.mule.runtime.module.artifact.api.descriptor.ArtifactDescriptor;
17+
18+
import org.junit.Test;
19+
20+
public class IsolatedPolicyClassLoaderTestCase {
21+
22+
protected static final String PACKAGE_NAME = "java.lang";
23+
protected static final String CLASS_NAME = PACKAGE_NAME + ".Object";
24+
private static final Class PARENT_LOADED_CLASS = Object.class;
25+
protected static final String ARTIFACT_ID = "testAppId";
26+
public static final String APP_NAME = "testApp";
27+
28+
protected final ArtifactDescriptor artifactDescriptor;
29+
protected final ClassLoaderLookupPolicy lookupPolicy = mock(ClassLoaderLookupPolicy.class);
30+
31+
public IsolatedPolicyClassLoaderTestCase() {
32+
artifactDescriptor = new ArtifactDescriptor(APP_NAME);
33+
}
34+
35+
@Test
36+
public void getIsolatedPolicyClassLoaderInstance() throws ClassNotFoundException {
37+
final ClassLoader parentClassLoader = mock(ClassLoader.class);
38+
when(parentClassLoader.loadClass(CLASS_NAME)).thenReturn(PARENT_LOADED_CLASS);
39+
40+
RegionClassLoader regionClassLoader = new RegionClassLoader(ARTIFACT_ID, artifactDescriptor, parentClassLoader, lookupPolicy);
41+
42+
IsolatedPolicyClassLoader instance1 = IsolatedPolicyClassLoader.getInstance(regionClassLoader);
43+
IsolatedPolicyClassLoader instance2 = IsolatedPolicyClassLoader.getInstance(regionClassLoader);
44+
assertThat(instance1, is(instance2));
45+
}
46+
47+
@Test(expected = IllegalArgumentException.class)
48+
public void getIsolatedPolicyClassLoaderInstanceWithNullRegionClassLoader() {
49+
IsolatedPolicyClassLoader.getInstance(null);
50+
}
51+
}

modules/deployment-model-impl/src/main/java/org/mule/runtime/module/deployment/impl/internal/MuleArtifactResourcesRegistry.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.mule.runtime.api.scheduler.SchedulerService;
3838
import org.mule.runtime.api.util.LazyValue;
3939
import org.mule.runtime.container.api.ModuleRepository;
40+
import org.mule.runtime.container.internal.FilteringContainerClassLoader;
4041
import org.mule.runtime.core.api.config.FeatureContext;
4142
import org.mule.runtime.core.api.config.FeatureFlaggingRegistry;
4243
import org.mule.runtime.core.api.context.notification.ServerNotificationManager;
@@ -338,7 +339,8 @@ private MuleArtifactResourcesRegistry(ArtifactClassLoader containerClassLoader,
338339
DeployableArtifactClassLoaderFactory<PolicyTemplateDescriptor> policyClassLoaderFactory =
339340
trackDeployableArtifactClassLoaderFactory(new PolicyTemplateClassLoaderFactory());
340341
PolicyTemplateClassLoaderBuilderFactory policyTemplateClassLoaderBuilderFactory =
341-
new ApplicationPolicyTemplateClassLoaderBuilderFactory(policyClassLoaderFactory, pluginClassLoadersFactory);
342+
new ApplicationPolicyTemplateClassLoaderBuilderFactory(policyClassLoaderFactory, pluginClassLoadersFactory,
343+
(FilteringContainerClassLoader) containerClassLoader);
342344

343345
applicationFactory = new DefaultApplicationFactory(applicationClassLoaderBuilderFactory,
344346
deployableArtifactDescriptorFactory,

modules/deployment-model-impl/src/main/java/org/mule/runtime/module/deployment/impl/internal/policy/ApplicationPolicyTemplateClassLoaderBuilderFactory.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@
66
*/
77
package org.mule.runtime.module.deployment.impl.internal.policy;
88

9+
import org.mule.runtime.container.internal.FilteringContainerClassLoader;
910
import org.mule.runtime.deployment.model.api.builder.RegionPluginClassLoadersFactory;
11+
import org.mule.runtime.deployment.model.api.policy.PolicyTemplateDescriptor;
1012
import org.mule.runtime.deployment.model.internal.policy.PolicyTemplateClassLoaderBuilder;
1113
import org.mule.runtime.module.artifact.api.classloader.DeployableArtifactClassLoaderFactory;
1214

1315
/**
1416
* Creates {@link PolicyTemplateClassLoaderBuilder} for application artifacts.
1517
*/
18+
@SuppressWarnings("deprecation")
1619
public class ApplicationPolicyTemplateClassLoaderBuilderFactory implements PolicyTemplateClassLoaderBuilderFactory {
1720

18-
private final DeployableArtifactClassLoaderFactory artifactClassLoaderFactory;
21+
private final DeployableArtifactClassLoaderFactory<PolicyTemplateDescriptor> artifactClassLoaderFactory;
1922
private final RegionPluginClassLoadersFactory pluginClassLoadersFactory;
23+
private final FilteringContainerClassLoader containerClassLoader;
2024

2125
/**
2226
* Creates a new factory instance
@@ -25,15 +29,28 @@ public class ApplicationPolicyTemplateClassLoaderBuilderFactory implements Polic
2529
* null.
2630
* @param pluginClassLoadersFactory creates the class loaders for the plugins included in the application's region. Non null
2731
*/
28-
public ApplicationPolicyTemplateClassLoaderBuilderFactory(DeployableArtifactClassLoaderFactory artifactClassLoaderFactory,
32+
public ApplicationPolicyTemplateClassLoaderBuilderFactory(DeployableArtifactClassLoaderFactory<PolicyTemplateDescriptor> artifactClassLoaderFactory,
2933
RegionPluginClassLoadersFactory pluginClassLoadersFactory) {
3034

35+
this(artifactClassLoaderFactory, pluginClassLoadersFactory, null);
36+
}
37+
38+
public ApplicationPolicyTemplateClassLoaderBuilderFactory(DeployableArtifactClassLoaderFactory<PolicyTemplateDescriptor> artifactClassLoaderFactory,
39+
RegionPluginClassLoadersFactory pluginClassLoadersFactory,
40+
FilteringContainerClassLoader containerClassLoader) {
41+
3142
this.artifactClassLoaderFactory = artifactClassLoaderFactory;
3243
this.pluginClassLoadersFactory = pluginClassLoadersFactory;
44+
this.containerClassLoader = containerClassLoader;
3345
}
3446

3547
@Override
3648
public PolicyTemplateClassLoaderBuilder createArtifactClassLoaderBuilder() {
3749
return new PolicyTemplateClassLoaderBuilder(artifactClassLoaderFactory, pluginClassLoadersFactory);
3850
}
51+
52+
@Override
53+
public FilteringContainerClassLoader getFilteringContainerClassLoader() {
54+
return containerClassLoader;
55+
}
3956
}

modules/deployment-model-impl/src/main/java/org/mule/runtime/module/deployment/impl/internal/policy/DefaultPolicyTemplateFactory.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@
66
*/
77
package org.mule.runtime.module.deployment.impl.internal.policy;
88

9+
import static org.mule.runtime.api.config.MuleRuntimeFeature.ENABLE_POLICY_ISOLATION;
910
import static org.mule.runtime.api.util.Preconditions.checkArgument;
1011
import static org.mule.runtime.deployment.model.internal.DefaultRegionPluginClassLoadersFactory.getArtifactPluginId;
1112
import static org.mule.runtime.module.artifact.api.classloader.DefaultArtifactClassLoaderFilter.NULL_CLASSLOADER_FILTER;
13+
import static org.mule.runtime.module.artifact.internal.util.FeatureFlaggingUtils.isFeatureEnabled;
1214
import static org.mule.runtime.module.deployment.impl.internal.artifact.ArtifactFactoryUtils.validateArtifactLicense;
1315

1416
import static java.lang.String.format;
1517
import static java.util.Collections.emptySet;
1618
import static java.util.stream.Collectors.toList;
1719
import static java.util.stream.Collectors.toSet;
1820

21+
import org.mule.runtime.container.internal.IsolatedPolicyClassLoader;
22+
import org.mule.runtime.container.internal.FilteringContainerClassLoader;
1923
import org.mule.runtime.deployment.model.api.application.Application;
2024
import org.mule.runtime.deployment.model.api.plugin.ArtifactPlugin;
2125
import org.mule.runtime.deployment.model.api.plugin.resolver.PluginDependenciesResolver;
2226
import org.mule.runtime.deployment.model.api.policy.PolicyTemplate;
2327
import org.mule.runtime.deployment.model.api.policy.PolicyTemplateDescriptor;
2428
import org.mule.runtime.module.artifact.api.Artifact;
2529
import org.mule.runtime.module.artifact.api.classloader.MuleDeployableArtifactClassLoader;
30+
import org.mule.runtime.module.artifact.api.classloader.RegionClassLoader;
2631
import org.mule.runtime.module.artifact.api.descriptor.ArtifactPluginDescriptor;
2732
import org.mule.runtime.module.deployment.impl.internal.plugin.DefaultArtifactPlugin;
2833
import org.mule.runtime.module.license.api.LicenseValidator;
@@ -61,24 +66,47 @@ public DefaultPolicyTemplateFactory(PolicyTemplateClassLoaderBuilderFactory poli
6166
public PolicyTemplate createArtifact(Application application, PolicyTemplateDescriptor descriptor) {
6267
MuleDeployableArtifactClassLoader ownPolicyClassLoader;
6368
MuleDeployableArtifactClassLoader policyClassLoader;
69+
RegionClassLoader regionClassLoader;
70+
MuleDeployableArtifactClassLoader parentClassLoader;
71+
FilteringContainerClassLoader containerClassLoader =
72+
policyTemplateClassLoaderBuilderFactory.getFilteringContainerClassLoader();
73+
6474

6575
final List<ArtifactPluginDescriptor> resolvedPolicyPluginsDescriptors =
6676
resolvePolicyPluginDescriptors(application, descriptor);
6777
final List<ArtifactPluginDescriptor> ownResolvedPluginDescriptors =
6878
pluginDependenciesResolver.resolve(emptySet(), new ArrayList<>(descriptor.getPlugins()), false);
6979

7080
try {
81+
if (containerClassLoader != null && isPolicyIsolationEnabled(descriptor) && hasRequiredPlugin(descriptor)) {
82+
// When policy isolation is enabled, a new RegionClassLoader provides a separate
83+
// classloading environment for the policy, preventing potential classloader
84+
// conflicts (when using the same dependency in both policy and domain).
85+
// IsolatedPolicyClassLoader then enforces this isolation.
86+
regionClassLoader =
87+
new RegionClassLoader(containerClassLoader.getArtifactId(),
88+
containerClassLoader.getArtifactDescriptor(),
89+
containerClassLoader,
90+
containerClassLoader.getClassLoaderLookupPolicy());
91+
parentClassLoader = IsolatedPolicyClassLoader
92+
.getInstance(regionClassLoader);
93+
} else {
94+
parentClassLoader = application.getRegionClassLoader();
95+
}
96+
7197
ownPolicyClassLoader = policyTemplateClassLoaderBuilderFactory.createArtifactClassLoaderBuilder()
7298
.addArtifactPluginDescriptors(ownResolvedPluginDescriptors
7399
.toArray(new ArtifactPluginDescriptor[ownResolvedPluginDescriptors.size()]))
74-
.setParentClassLoader(application.getRegionClassLoader()).setArtifactDescriptor(descriptor).build();
100+
.setParentClassLoader(parentClassLoader)
101+
.setArtifactDescriptor(descriptor).build();
75102

76103
// This classloader needs to be created after ownPolicyClassLoader so its inner classloaders override the entries in the
77104
// ClassLoaderRepository for the application
78105
policyClassLoader = policyTemplateClassLoaderBuilderFactory.createArtifactClassLoaderBuilder()
79106
.addArtifactPluginDescriptors(resolvedPolicyPluginsDescriptors
80107
.toArray(new ArtifactPluginDescriptor[resolvedPolicyPluginsDescriptors.size()]))
81-
.setParentClassLoader(application.getRegionClassLoader()).setArtifactDescriptor(descriptor).build();
108+
.setParentClassLoader(parentClassLoader)
109+
.setArtifactDescriptor(descriptor).build();
82110
} catch (Exception e) {
83111
throw new PolicyTemplateCreationException(createPolicyTemplateCreationErrorMessage(descriptor.getName()), e);
84112
}
@@ -95,6 +123,24 @@ public PolicyTemplate createArtifact(Application application, PolicyTemplateDesc
95123
ownPolicyClassLoader));
96124
}
97125

126+
private boolean isPolicyIsolationEnabled(PolicyTemplateDescriptor descriptor) {
127+
return isFeatureEnabled(ENABLE_POLICY_ISOLATION, descriptor);
128+
}
129+
130+
//
131+
private boolean hasRequiredPlugin(PolicyTemplateDescriptor descriptor) {
132+
if (descriptor == null || descriptor.getPlugins() == null) {
133+
return false;
134+
}
135+
Set<ArtifactPluginDescriptor> plugins = descriptor.getPlugins();
136+
for (ArtifactPluginDescriptor plugin : plugins) {
137+
if (plugin.getName().equals("HTTP")) {
138+
return true;
139+
}
140+
}
141+
return false;
142+
}
143+
98144
// Need all the plugins that the policy itself depends on, while keeping a relationship with the appropriate classloader.
99145
private List<ArtifactPlugin> resolveOwnArtifactPlugins(List<ArtifactPlugin> artifactPlugins,
100146
List<ArtifactPluginDescriptor> ownResolvedPluginDescriptors,

modules/deployment-model-impl/src/main/java/org/mule/runtime/module/deployment/impl/internal/policy/PolicyTemplateClassLoaderBuilderFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package org.mule.runtime.module.deployment.impl.internal.policy;
88

9+
import org.mule.runtime.container.internal.FilteringContainerClassLoader;
910
import org.mule.runtime.deployment.model.internal.policy.PolicyTemplateClassLoaderBuilder;
1011

1112
/**
@@ -19,4 +20,11 @@ public interface PolicyTemplateClassLoaderBuilderFactory {
1920
* @return a new builder instance.
2021
*/
2122
PolicyTemplateClassLoaderBuilder createArtifactClassLoaderBuilder();
23+
24+
/**
25+
* Retrieves the filtering container class loader.
26+
*
27+
* @return The filtering container class loader.
28+
*/
29+
FilteringContainerClassLoader getFilteringContainerClassLoader();
2230
}

0 commit comments

Comments
 (0)