/******************************************************************************* * Copyright (c) 2010-present Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stuart McCulloch (Sonatype, Inc.) - initial API and implementation *******************************************************************************/ package org.eclipse.sisu.space; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.jar.Manifest; import org.apache.felix.framework.FrameworkFactory; import org.eclipse.sisu.inject.DeferredClass; import org.junit.Ignore; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.launch.Framework; import junit.framework.TestCase; @Ignore( "Need to replace some test archives" ) public class BundleClassSpaceTest extends TestCase { private static final URL EMPTY_BUNDLE = ZipEntryIteratorTest.class.getResource( "empty.jar" ); private static final URL SIMPLE_BUNDLE = ZipEntryIteratorTest.class.getResource( "simple_bundle.jar" ); private static final URL LOGGING_BUNDLE = ZipEntryIteratorTest.class.getResource( "logging_bundle.jar" ); private Framework framework; @Override protected void setUp() throws Exception { super.setUp(); final Map<String, String> configuration = new HashMap<String, String>(); configuration.put( Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT ); configuration.put( Constants.FRAMEWORK_STORAGE, "target/bundlecache" ); final FrameworkFactory frameworkFactory = new FrameworkFactory(); framework = frameworkFactory.newFramework( configuration ); framework.start(); } @Override protected void tearDown() throws Exception { framework.stop(); framework.waitForStop( 0 ); super.tearDown(); } public void testHashCodeAndEquals() throws Exception { final Bundle testBundle = framework.getBundleContext().installBundle( LOGGING_BUNDLE.toString() ); final ClassSpace space = new BundleClassSpace( testBundle ); assertEquals( space, space ); assertEquals( space, new BundleClassSpace( testBundle ) ); assertFalse( space.equals( new ClassSpace() { public Class<?> loadClass( final String name ) { return space.loadClass( name ); } public DeferredClass<?> deferLoadClass( final String name ) { return space.deferLoadClass( name ); } public Enumeration<URL> getResources( final String name ) { return space.getResources( name ); } public URL getResource( final String name ) { return space.getResource( name ); } public Enumeration<URL> findEntries( final String path, final String glob, final boolean recurse ) { return space.findEntries( path, glob, recurse ); } } ) ); assertEquals( testBundle.hashCode(), space.hashCode() ); assertEquals( testBundle.toString(), space.toString() ); } public void testClassSpaceResources() throws Exception { final Bundle testBundle1 = framework.getBundleContext().installBundle( LOGGING_BUNDLE.toString() ); final ClassSpace space1 = new BundleClassSpace( testBundle1 ); final Bundle testBundle2 = framework.getBundleContext().installBundle( SIMPLE_BUNDLE.toString() ); final ClassSpace space2 = new BundleClassSpace( testBundle2 ); final Bundle testBundle3 = framework.getBundleContext().installBundle( EMPTY_BUNDLE.toString() ); final ClassSpace space3 = new BundleClassSpace( testBundle3 ); Enumeration<URL> e; // logging bundle class-path has repeated entries... e = space1.getResources( "META-INF/MANIFEST.MF" ); assertTrue( e.hasMoreElements() ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertFalse( e.hasMoreElements() ); // ...which we try to collapse when using find e = space1.findEntries( "META-INF", "*.MF", false ); assertTrue( e.hasMoreElements() ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertTrue( e.nextElement().toString().matches( "jar:bundle://.*!/META-INF/MANIFEST.MF" ) ); assertFalse( e.hasMoreElements() ); try { e.nextElement(); fail( "Expected NoSuchElementException" ); } catch ( final NoSuchElementException t ) { } e = space2.findEntries( "a/b", "*", true ); assertTrue( e.hasMoreElements() ); assertTrue( e.nextElement().toString().matches( "bundle://.*/a/b/2" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/a/b/c/" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/a/b/c/3" ) ); assertFalse( e.hasMoreElements() ); e = space3.findEntries( "", "*", true ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/" ) ); assertTrue( e.nextElement().toString().matches( "bundle://.*/META-INF/MANIFEST.MF" ) ); assertFalse( e.hasMoreElements() ); e = space1.findEntries( null, "missing", true ); assertFalse( e.hasMoreElements() ); e = space2.findEntries( null, "missing", true ); assertFalse( e.hasMoreElements() ); e = space3.findEntries( null, "missing", true ); assertFalse( e.hasMoreElements() ); final URL manifestURL = space1.getResource( "META-INF/MANIFEST.MF" ); assertNotNull( manifestURL ); new Manifest( manifestURL.openStream() ); } public void testDeferredClass() throws Exception { final Bundle testBundle = framework.getBundleContext().installBundle( LOGGING_BUNDLE.toString() ); final ClassSpace space = new BundleClassSpace( testBundle ); final String clazzName = "org.apache.commons.logging.Log"; final DeferredClass<?> clazz = space.deferLoadClass( clazzName ); assertEquals( clazzName, clazz.getName() ); assertSame( space.loadClass( clazzName ), clazz.load() ); final DeferredClass<?> missingClazz = space.deferLoadClass( "missing.class" ); try { missingClazz.load(); fail( "Expected TypeNotPresentException" ); } catch ( final TypeNotPresentException e ) { } } public void testBrokenResources() { final InvocationHandler handler = new InvocationHandler() { public Object invoke( final Object proxy, final Method method, final Object[] args ) throws Throwable { throw new IOException(); } }; final ClassSpace space = new BundleClassSpace( (Bundle) Proxy.newProxyInstance( Bundle.class.getClassLoader(), new Class<?>[] { Bundle.class }, handler ) ); assertFalse( space.getResources( "error" ).hasMoreElements() ); } }