package org.codehaus.plexus.component.composition; import org.codehaus.plexus.PlexusTestCase; import static org.codehaus.plexus.PlexusConstants.PLEXUS_DEFAULT_HINT; import org.codehaus.plexus.classworlds.realm.ClassRealm; import java.io.File; import java.net.URL; import java.util.Map; import java.util.List; import java.util.TreeMap; /** @author Jason van Zyl */ public class ComponentRealmCompositionTest extends PlexusTestCase { // // Component archives // private static final String PLUGIN_0_JAR = "src/test/test-components/plugin0-1.0-SNAPSHOT.jar"; private static final String PLUGIN_1_JAR = "src/test/test-components/plugin1-1.0-SNAPSHOT.jar"; private static final String COMPONENT_A_JAR = "src/test/test-components/component-a-1.0-SNAPSHOT.jar"; private static final String COMPONENT_B_JAR = "src/test/test-components/component-b-1.0-SNAPSHOT.jar"; private static final String COMPONENT_C_JAR = "src/test/test-components/component-c-1.0-SNAPSHOT.jar"; private static final String ARCHIVER_JAR = "src/test/test-components/plexus-archiver-1.0-alpha-8.jar"; // // Component roles // private static final String PLUGIN_0_ROLE = "org.codehaus.plexus.plugins.Plugin0"; private static final String PLUGIN_1_ROLE = "org.codehaus.plexus.plugins.Plugin1"; // // Component realms // private static final String PLUGIN_0_REALM = "plugin0Realm"; private static final String PLUGIN_1_REALM = "plugin1Realm"; private ClassRealm classRealm0; private ClassRealm classRealm1; protected void setUp() throws Exception { super.setUp(); // Create ClassRealm plugin0 with plugin0 -> A, plugin0 -> B classRealm0 = createClassRealm( PLUGIN_0_REALM, PLUGIN_0_JAR, COMPONENT_A_JAR, COMPONENT_B_JAR, ARCHIVER_JAR ); // Create ClassRealm plugin1 with plugin1 -> A, plugin1 -> C classRealm1 = createClassRealm( PLUGIN_1_REALM, PLUGIN_1_JAR, COMPONENT_A_JAR, COMPONENT_C_JAR, ARCHIVER_JAR ); } /* * We are testing that when the same component implementation exists in more then one * realm and components depend on those implementations, that the right realm is used * to wire up the components. * * An example of this in practice are Maven plugins where each plugin is loaded into * a separate realm and the plugin may have dependencies on other components. We want * to make sure that a requirement, say a JarArchiver, for a given component, say the * maven-jar-plugin, is wired up with a JarArchiver taken from the same realm as the * maven-jar-plugin and not a different realm. */ public void testCompositionWhereTheSameImplementationExistsInDifferentRealms() throws Exception { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); try { // Plugin0 Thread.currentThread().setContextClassLoader( classRealm0 ); getContainer().lookup( PLUGIN_0_ROLE ); // Plugin1 Thread.currentThread().setContextClassLoader( classRealm1 ); getContainer().lookup( PLUGIN_1_ROLE ); // Plugin0(alt) Thread.currentThread().setContextClassLoader( classRealm0 ); getContainer().lookup( PLUGIN_0_ROLE, "alt" ); // Plugin1(alt) Thread.currentThread().setContextClassLoader( classRealm1 ); getContainer().lookup( PLUGIN_1_ROLE, "alt" ); } finally { Thread.currentThread().setContextClassLoader( oldClassLoader ); } } public void testThatASingletonComponentIntheCoreRealmWhenLookedUpInComponentRealmsYieldsTheSameInstance() throws Exception { } public void testMultiRealmLookupMap() throws Exception { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( classRealm0 ); Map<String,Object> plugin0Map = getContainer().lookupMap( PLUGIN_0_ROLE ); assertNotNull("plugin0Map is null", plugin0Map ); assertNotNull("plugin0Map does not contain a DefaultPlugin0", plugin0Map.get( PLEXUS_DEFAULT_HINT)); assertNotNull("plugin0Map does not contain a AltPlugin0", plugin0Map.get( "alt")); assertEquals("Expected only 2 components in plugin0Map", 2, plugin0Map.size()); Thread.currentThread().setContextClassLoader( classRealm1 ); Map<String,Object> plugin1Map = getContainer().lookupMap( PLUGIN_1_ROLE ); assertNotNull("plugin1Map is null", plugin1Map); assertNotNull("plugin1Map does not contain a DefaultPlugin1", plugin1Map.get( PLEXUS_DEFAULT_HINT)); assertNotNull("plugin1Map does not contain a AltPlugin1", plugin1Map.get( "alt")); assertEquals("Expected only 2 components in plugin1Map", 2, plugin1Map.size()); Thread.currentThread().setContextClassLoader( null ); } finally { Thread.currentThread().setContextClassLoader( oldClassLoader ); } } public void testMultiRealmLookupList() throws Exception { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( classRealm0 ); List<Object> plugin0List = getContainer().lookupList( PLUGIN_0_ROLE ); assertNotNull("plugin0List is null", plugin0List ); Map<String, Object> plugin0Map = mapByClassSimpleName( plugin0List ); assertNotNull("plugin0List does not contain a DefaultPlugin0", plugin0Map.get( "DefaultPlugin0")); assertNotNull("plugin0List does not contain a AltPlugin0", plugin0Map.get( "AltPlugin0")); assertEquals("Expected only 2 components in plugin0Map", 2, plugin0Map.size()); Thread.currentThread().setContextClassLoader( classRealm1 ); List<Object> plugin1List = getContainer().lookupList( PLUGIN_1_ROLE ); assertNotNull("plugin1List is null", plugin1List ); Map<String, Object> plugin1Map = mapByClassSimpleName( plugin1List ); assertNotNull("plugin1List does not contain a DefaultPlugin1", plugin1Map.get( "DefaultPlugin1")); assertNotNull("plugin1List does not contain a AltPlugin1", plugin1Map.get( "AltPlugin1")); assertEquals("Expected only 2 components in plugin0Map", 2, plugin1Map.size()); } finally { Thread.currentThread().setContextClassLoader( oldClassLoader ); } } private ClassRealm createClassRealm(String id, String... jars) throws Exception { // create the realm ClassRealm classRealm = getContainer().createChildRealm( id ); // populate the realm for ( String jar : jars ) { File file = new File(jar); assertTrue( jar + " is not a file", file.isFile() ); URL url = file.toURI().toURL(); classRealm.addURL( url ); } // descover all component definitions in the realm and register them with the repository getContainer().discoverComponents( classRealm ); return classRealm; } private Map<String, Object> mapByClassSimpleName(List<Object> objects) { Map<String, Object> map = new TreeMap<String, Object>(); for ( Object object : objects ) { map.put(object.getClass().getSimpleName(), object); } return map; } }