/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.test.platform.plugin.pluginmgr; import org.junit.Before; import org.junit.Test; import org.pentaho.platform.plugin.services.pluginmgr.PluginClassLoader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import static org.junit.Assert.*; @SuppressWarnings( "nls" ) public class PluginClassLoaderIT { private PluginClassLoader pluginLoader; @Before public void init() { // now load a class pluginLoader = new PluginClassLoader( new File( "./src/test/resources/PluginClassLoaderTest/" ), getClass().getClassLoader() ); } @SuppressWarnings( "unchecked" ) @Test public void testOverrideLoad() throws ClassNotFoundException, SecurityException, InstantiationException, IllegalAccessException { pluginLoader.setOverrideLoad( true ); String className = "org.pentaho.test.platform.plugin.pluginmgr.ClassToOverride"; Class clazz = Class.forName( className, true, getClass().getClassLoader() ); Object o = clazz.newInstance(); assertEquals( "I am the original class from the parent class loader", o.toString() ); Class overridenClazz = Class.forName( className, true, pluginLoader ); Object o2 = overridenClazz.newInstance(); assertEquals( "I am the overridden class from the plugin class loader", o2.toString() ); } private Object getContainerFromPrivateClassLoader() throws ClassNotFoundException, InstantiationException, IllegalAccessException { String className = "org.pentaho.test.platform.plugin.pluginmgr.ClassToOverrideContainer"; Class<?> t = Class.forName( className, true, pluginLoader ); return t.newInstance(); } @Test public void testImplicitLoad() throws ClassNotFoundException, InstantiationException, IllegalAccessException { pluginLoader.setOverrideLoad( true ); // // 1. Implicitly create an instance of ClassToOverride and check that it was loaded by the default loader. // ClassToOverride cto = new ClassToOverride(); assertNotSame( PluginClassLoader.class.getName(), cto.getClass().getClassLoader().getClass().getName() ); assertEquals( "failed to load original class", "I am the original class from the parent class loader", cto .toString() ); // NOTE: implicit loading of a class (i.e. "new" or static method access) is always performed by the // classloader of the enclosing class (the "current" classloader), so if we set // Thread.currentThread().setContextClassLoader(pluginLoader) and then did a new ClassToOverride(), // the pluginLoader would *not* be asked to load ClassToOverride, rather the current classloader // will be asked to load it. // // 2. Ask a class that we are certain was loaded by the private loader to implicitly create an instance // of ClassToOverride and check that the class was loaded by the private loader // Object explicitlyLoadedContainer = getContainerFromPrivateClassLoader(); assertEquals( PluginClassLoader.class.getName(), explicitlyLoadedContainer.getClass().getClassLoader().getClass() .getName() ); assertEquals( "failed to load override class", "I am the overridden class from the plugin class loader", explicitlyLoadedContainer.toString() ); } @Test public void testLoadClass() throws IOException, ClassNotFoundException { // now try getting it as a class Class<?> testClass = pluginLoader.loadClass( "org.pentaho.test.platform.engine.services.TestClassForClassloader" ); assertNotNull( "class is null", testClass ); assertEquals( "wrong class", "org.pentaho.test.platform.engine.services.TestClassForClassloader", testClass .getName() ); } @Test public void testLoadClassAsResource() throws IOException, ClassNotFoundException { // test the byte array first InputStream in = pluginLoader.getResourceAsStream( "org/pentaho/test/platform/engine/services/TestClassForClassloader.class" ); assertNotNull( "Could not find class TestClassForClassloader in jar file", in ); byte[] b = toBytes( in ); String classBytes = new String( b ); assertTrue( "method is missing", classBytes .contains( "org/pentaho/test/platform/engine/services/TestClassForClassloader" ) ); } private byte[] toBytes( InputStream in ) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] b = new byte[2048]; int n = in.read( b ); while ( n != -1 ) { out.write( b, 0, n ); n = in.read( b ); } return out.toByteArray(); } @Test public void testLoadXml() throws IOException { InputStream in = pluginLoader.getResourceAsStream( "test1.xml" ); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String xml = new String( b ); assertTrue( "xml is wrong", xml.contains( "<test1>" ) ); } @Test public void testLoadBadResource() throws IOException { InputStream in = pluginLoader.getResourceAsStream( "bogus.xml" ); assertNull( "input stream should be null", in ); } @Test public void testLoadBadClass() throws IOException { // now try getting it as a class try { pluginLoader.loadClass( "bogus" ); assertFalse( "Exception expected", true ); } catch ( ClassNotFoundException e ) { assertTrue( "Exception expected", true ); } } @Test public void testLoadProperties_fromJar() throws IOException { InputStream in = pluginLoader.getResourceAsStream( "org/pentaho/test/platform/engine/services/test.properties" ); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String classBytes = new String( b ); assertTrue( "property is missing", classBytes.contains( "test_setting=test" ) ); } @Test public void testLoadProperties_fromDir() throws IOException { InputStream in = pluginLoader.getResourceAsStream( "resources/plugin-classloader-test-inresourcesdir.properties" ); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String classBytes = new String( b ); assertTrue( "property is missing", classBytes.contains( "name=" ) ); } @Test public void testFindXmlResource() throws IOException { URL url = pluginLoader.getResource( "test1.xml" ); assertNotNull( "URL is null", url ); InputStream in = url.openStream(); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String xml = new String( b ); assertTrue( "xml is wrong", xml.contains( "<test1>" ) ); } @Test public void testFindClassResource() throws IOException { InputStream in = pluginLoader.getResourceAsStream( "org/pentaho/test/platform/engine/services/TestClassForClassloader.class" ); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String xml = new String( b ); assertTrue( "xml is wrong", xml.contains( "TestClassForClassloader" ) ); } @Test public void testFindBadResource() throws IOException { URL url = pluginLoader.getResource( "bogus.xml" ); assertNull( "URL should be null", url ); } @Test public void testFindResources() throws IOException { Enumeration<URL> urls = pluginLoader.getResources( "test1.xml" ); assertNotNull( "URLS is null", urls ); int count = 0; while ( urls.hasMoreElements() ) { URL url = urls.nextElement(); InputStream in = url.openStream(); assertNotNull( "input stream is null", in ); byte[] b = toBytes( in ); String xml = new String( b ); assertTrue( "xml is wrong", xml.contains( "<test1>" ) ); count++; } assertEquals( "Wrong number of URLS", 1, count ); } @Test public void testFindBadResources() throws IOException { Enumeration<URL> urls = pluginLoader.getResources( "bogus.xml" ); assertNotNull( "URLS is null", urls ); int count = 0; while ( urls.hasMoreElements() ) { count++; } assertEquals( "Wrong number of URLS", 0, count ); } @Test public void testJarListedInClassLoader() throws ClassNotFoundException { boolean jarFound = false; for ( URL url : pluginLoader.getURLs() ) { if ( url.toString().contains( "test-jar.jar" ) ) { jarFound = true; } } assertTrue( "test-jar.jar not found in classloader", jarFound ); // now load a class from the jar pluginLoader.loadClass( "org.pentaho.test.platform.engine.services.TestClassForClassloader" ); } // @Test // public void testIsPluginClass() throws ClassNotFoundException { // Class testClass = loader.loadClass("org/pentaho/test/platform/engine/services/TestClassForClassloader"); // assertTrue("Class should have been identified as a plugin class", loader.isPluginClass(testClass)); // // assertFalse("Class should NOT have been identified as a plugin class", loader.isPluginClass(String.class)); // } }