You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2012/08/17 14:45:08 UTC

svn commit: r1374227 - in /sling/trunk/launchpad/base: ./ src/main/java/org/apache/sling/launchpad/base/impl/ src/test/java/org/apache/sling/launchpad/base/impl/ src/test/java/org/apache/sling/launchpad/base/impl/t1/ src/test/resources/

Author: fmeschbe
Date: Fri Aug 17 12:45:08 2012
New Revision: 1374227

URL: http://svn.apache.org/viewvc?rev=1374227&view=rev
Log:
SLING-2554 Add SlingFelix.getBundle(Class) method and test case

Added:
    sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/SlingFelixTest.java
    sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/
    sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/T1Activator.java
    sling/trunk/launchpad/base/src/test/resources/test1.bnd
Modified:
    sling/trunk/launchpad/base/pom.xml
    sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java

Modified: sling/trunk/launchpad/base/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/pom.xml?rev=1374227&r1=1374226&r2=1374227&view=diff
==============================================================================
--- sling/trunk/launchpad/base/pom.xml (original)
+++ sling/trunk/launchpad/base/pom.xml Fri Aug 17 12:45:08 2012
@@ -50,6 +50,36 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>testbundles</id>
+                        <phase>process-test-classes</phase>
+                        <configuration>
+                            <target name="build">
+                                <taskdef resource="aQute/bnd/ant/taskdef.properties"
+                                    classpathref="maven.plugin.classpath" />
+                                <bnd classpath="${build.testOutputDirectory}" failok="false"
+                                    exceptions="true" files="src/test/resources/test1.bnd"
+                                    output="${build.testOutputDirectory}" />
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>biz.aQute</groupId>
+                        <artifactId>bnd</artifactId>
+                        <version>0.0.384</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>

Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java?rev=1374227&r1=1374226&r2=1374227&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java Fri Aug 17 12:45:08 2012
@@ -21,11 +21,14 @@ package org.apache.sling.launchpad.base.
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Map;
 
 import org.apache.felix.framework.Felix;
 import org.apache.sling.launchpad.base.shared.Loader;
 import org.apache.sling.launchpad.base.shared.Notifiable;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 
 
@@ -35,6 +38,9 @@ public class SlingFelix extends Felix {
 
     private Thread notifierThread;
 
+    // see getBundle(Class) below
+    private Method getBundleMethod;
+
     public SlingFelix(final Notifiable notifiable, final Map<?, ?> props) throws Exception {
         super(props);
         this.notifiable = notifiable;
@@ -87,6 +93,49 @@ public class SlingFelix extends Felix {
         }
     }
 
+    /**
+     * Returns the bundle from which the given class has been loaded or
+     * <code>null</code> if the class has not been loaded through any
+     * of the bundles in this framework.
+     * <p>
+     * This method delegates to Felix.getBundle(Class) to support the
+     * URLHandlers service implementation. See SLING-2554 for details.
+     *
+     * @param clazz The class to check
+     *
+     * @return The Bundle or <code>null</code> if the class has not been
+     *      loaded through any of the bundles in this framework.
+     */
+    public Bundle getBundle(Class<?> clazz) {
+        Method getBundleMethod = this.getBundleMethod;
+        if (getBundleMethod == null) {
+            Class<?> provider = Felix.class; // super class actually
+            try {
+                getBundleMethod = provider.getDeclaredMethod("getBundle", Class.class);
+                getBundleMethod.setAccessible(true);
+                this.getBundleMethod = getBundleMethod;
+            } catch (Exception e) {
+                throw new NoSuchMethodError("getBundle");
+            }
+        }
+
+        try {
+            return (Bundle) getBundleMethod.invoke(this, clazz);
+        } catch (IllegalArgumentException e) {
+            // we don't expect this, we checked everything
+        } catch (IllegalAccessException e) {
+            // we don't expect this, because we set the method accessible
+        } catch (InvocationTargetException e) {
+            // unpack and rethrow
+            Throwable t = e.getCause();
+            if (t instanceof RuntimeException) {
+                throw (RuntimeException) t;
+            }
+        }
+
+        return null;
+    }
+
     private class Notifier implements Runnable {
 
         private final boolean restart;

Added: sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/SlingFelixTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/SlingFelixTest.java?rev=1374227&view=auto
==============================================================================
--- sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/SlingFelixTest.java (added)
+++ sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/SlingFelixTest.java Fri Aug 17 12:45:08 2012
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.launchpad.base.impl;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.sling.launchpad.base.shared.Notifiable;
+import org.junit.After;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class SlingFelixTest {
+
+    private final TestNotifiable notifiable = new TestNotifiable();
+
+    private SlingFelix framework;
+
+    @After
+    public void tearDown() {
+        stopSling();
+    }
+
+    @Test
+    public void test_start_stop() {
+        SlingFelix sf = startSling();
+        TestCase.assertNotNull(sf);
+        TestCase.assertEquals(Bundle.ACTIVE, sf.getState());
+
+        stopSling();
+        TestCase.assertNull("Expect the framework field to be cleared", this.framework);
+
+        TestCase.assertTrue("Expect Notifiable.stopped to be called", this.notifiable.stoppedCalled);
+        TestCase.assertFalse("Expect Notifiable.updated to not be called", this.notifiable.updatedCalled);
+        TestCase.assertNull("Expect Notifiable.updated to not be called", this.notifiable.updatedCalledFile);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void test_Felix_getBundle_Class_from_PackageAdmin() {
+
+        /*
+         * Tests whether the Felix.getBundle(Class) call from PackageAdmin
+         * is possible. This test should always succeed regardless of the
+         * SLING-2554 implementation because it uses regular Java call
+         * methodology.
+         */
+
+        SlingFelix sf = startSling();
+
+        PackageAdmin pa = getService(sf, PackageAdmin.class);
+        TestCase.assertNotNull(pa);
+
+        TestCase.assertNull("Integer class provided by the VM not from a bundle", pa.getBundle(Integer.class));
+        TestCase.assertEquals("BundleContext class must come from the framework", sf.getBundle(),
+            pa.getBundle(BundleContext.class));
+    }
+
+    @Test
+    public void test_Felix_getBundle_Class_from_UrlStreamHandler() {
+
+        /*
+         * Tests whether the Felix.getBundle(Class) method can be called
+         * from the URLHandlers class. This call may fail if SLING-2554
+         * does not work because it uses reflection on the class of the
+         * framework instance, which happens to be SlingFelix instead of
+         * Felix
+         */
+
+        SlingFelix sf = startSling();
+        SlingFelix sf2 = doStartSling(new TestNotifiable());
+
+        try {
+            InputStream ins = getClass().getResourceAsStream("/test1.jar");
+            sf.getBundleContext().installBundle("test1", ins).start();
+
+            Runnable r = getService(sf, Runnable.class);
+            r.run();
+
+        } catch (Exception e) {
+            throw (AssertionFailedError) new AssertionFailedError(e.toString()).initCause(e);
+        } finally {
+            doStopSling(sf2);
+        }
+    }
+
+    private SlingFelix startSling() {
+        if (this.framework == null) {
+            this.framework = doStartSling(this.notifiable);
+        }
+
+        return this.framework;
+    }
+
+    private static SlingFelix doStartSling(final Notifiable notifiable) {
+        final String baseDir = System.getProperty("basedir");
+        if (baseDir == null) {
+            TestCase.fail("Need the basedir system property to locate the framework folder");
+        }
+        File fwDir = new File(baseDir + "/target/felix." + System.nanoTime());
+        fwDir.mkdirs();
+
+        HashMap<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.FRAMEWORK_STORAGE, fwDir.getAbsolutePath());
+        props.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
+        props.put(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, "30");
+
+        try {
+            SlingFelix fw = new SlingFelix(notifiable, props);
+            fw.start();
+            return fw;
+        } catch (Exception e) {
+            TestCase.fail("Failed to start OSGi Framework: " + e);
+            return null; // to keep the compiler cool
+        }
+    }
+
+    private void stopSling() {
+        if (this.framework != null) {
+            try {
+                doStopSling(this.framework);
+            } finally {
+                this.framework = null;
+            }
+        }
+    }
+
+    private static void doStopSling(final SlingFelix framework) {
+        try {
+            framework.stop();
+            if (framework.waitForStop(10L).getType() == FrameworkEvent.WAIT_TIMEDOUT) {
+                TestCase.fail("Timed out waiting for framework to stop");
+            }
+        } catch (Exception e) {
+            TestCase.fail("Cannot stop OSGi Framework: " + e);
+        }
+    }
+
+    private <T> T getService(final Framework framework, Class<T> type) {
+        ServiceReference<T> ref = framework.getBundleContext().getServiceReference(type);
+        if (ref != null) {
+            return framework.getBundleContext().getService(ref);
+        }
+        return null;
+    }
+
+    private static class TestNotifiable implements Notifiable {
+
+        boolean stoppedCalled = false;
+
+        boolean updatedCalled = false;
+
+        File updatedCalledFile = null;
+
+        public void stopped() {
+            this.stoppedCalled = true;
+        }
+
+        public void updated(File tmpFile) {
+            this.updatedCalled = true;
+            this.updatedCalledFile = tmpFile;
+        }
+
+    }
+}

Added: sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/T1Activator.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/T1Activator.java?rev=1374227&view=auto
==============================================================================
--- sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/T1Activator.java (added)
+++ sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/base/impl/t1/T1Activator.java Fri Aug 17 12:45:08 2012
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.launchpad.base.impl.t1;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The <code>T1Activator</code> uses the framework to connect to an URL
+ * which causes the Felix.getBundle(Class) method to be called to resolve
+ * the framework from the calling class.
+ *
+ * If SlingFelix does not overwrite the Felix.getBundle(Class) method
+ * the URLHandlers class cannot find the method and thus the
+ * {@link #run()} method throws an exception.
+ */
+public class T1Activator implements BundleActivator, Runnable {
+
+    private String url;
+
+    public void start(BundleContext context) throws Exception {
+        this.url = context.getBundle().getEntry("META-INF/MANIFEST.MF").toString();
+        context.registerService(Runnable.class.getName(), this, null);
+    }
+
+    public void stop(BundleContext context) throws Exception {
+    }
+
+    public void run() {
+        try {
+            new URL(url).openConnection();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

Added: sling/trunk/launchpad/base/src/test/resources/test1.bnd
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/test/resources/test1.bnd?rev=1374227&view=auto
==============================================================================
--- sling/trunk/launchpad/base/src/test/resources/test1.bnd (added)
+++ sling/trunk/launchpad/base/src/test/resources/test1.bnd Fri Aug 17 12:45:08 2012
@@ -0,0 +1,24 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+
+# Descriptor for a test bundle for SlingFelixTest to ensure
+# SLING-2554
+
+Bundle-SymbolicName: test1
+Bundle-Version: 0.0.1
+Bundle-Activator: org.apache.sling.launchpad.base.impl.t1.T1Activator
+Export-Package: org.apache.sling.launchpad.base.impl.t1;provide:=true;version=1.0
\ No newline at end of file