You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ma...@apache.org on 2011/08/12 17:44:36 UTC
svn commit: r1157163 - in /aries/trunk/application:
application-itests/src/test/java/org/apache/aries/application/runtime/itests/
application-itests/src/test/java/org/apache/aries/isolated/sample/
application-itests/src/test/java/org/apache/aries/isola...
Author: mahrwald
Date: Fri Aug 12 15:44:36 2011
New Revision: 1157163
URL: http://svn.apache.org/viewvc?rev=1157163&view=rev
Log:
ARIES-726: Don't expose Equinox NPE
Added:
aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/sample/SharedImpl.java
aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/
aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/Shared.java
Modified:
aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java
aries/trunk/application/application-runtime-framework/src/main/java/org/apache/aries/application/runtime/framework/BundleFrameworkImpl.java
Modified: aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java?rev=1157163&r1=1157162&r2=1157163&view=diff
==============================================================================
--- aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java (original)
+++ aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java Fri Aug 12 15:44:36 2011
@@ -21,6 +21,7 @@ package org.apache.aries.application.run
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.equinox;
import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.repository;
@@ -28,6 +29,7 @@ import static org.apache.aries.itest.Ext
import java.io.File;
import java.io.FileOutputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.aries.application.management.AriesApplication;
import org.apache.aries.application.management.AriesApplicationContext;
@@ -49,6 +51,10 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.service.framework.CompositeBundle;
@RunWith(JUnit4TestRunner.class)
public class IsolatedRuntimeTest extends AbstractIntegrationTest {
@@ -67,14 +73,26 @@ public class IsolatedRuntimeTest extends
.jar("sample.jar")
.manifest().symbolicName("org.apache.aries.isolated.sample")
.attribute("Bundle-Version", "1.0.0")
- .attribute("Import-Package", "org.osgi.service.blueprint")
+ .attribute("Import-Package", "org.osgi.service.blueprint, org.apache.aries.isolated.shared")
+ // needed for testFrameworkResolvedBeforeInnerBundlesStart()
+ .attribute("Bundle-ActivationPolicy", "lazy")
.end()
.binary("org/apache/aries/isolated/sample/HelloWorld.class",
IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorld.class"))
.binary("org/apache/aries/isolated/sample/HelloWorldImpl.class",
IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorldImpl.class"))
+ .binary("org/apache/aries/isolated/sample/SharedImpl.class",
+ IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/SharedImpl.class"))
.binary("OSGI-INF/blueprint/sample-blueprint.xml",
IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("isolated/sample-blueprint.xml"))
+ .end()
+ .jar("shared.jar")
+ .manifest().symbolicName("org.apache.aries.isolated.shared")
+ .attribute("Bundle-Version", "1.0.0")
+ .attribute("Export-Package", "org.apache.aries.isolated.shared")
+ .end()
+ .binary("org/apache/aries/isolated/shared/Shared.class",
+ IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/shared/Shared.class"))
.end();
FileOutputStream fout = new FileOutputStream("test.eba");
@@ -227,7 +245,53 @@ public class IsolatedRuntimeTest extends
manager.uninstall(ctx);
}
-
+ @Test
+ public void testFrameworkResolvedBeforeInnerBundlesStart() throws Exception {
+ /*
+ * Lazy bundles have in the past triggered recursive bundle trackers to handle them before
+ * the composite bundle framework was even resolved. In such a case the below loadClass
+ * operation on a class that depends on a class imported from the outside of the composite
+ * will fail with an NPE.
+ */
+
+ final AtomicBoolean loadedClass = new AtomicBoolean(false);
+
+ context().addBundleListener(new SynchronousBundleListener() {
+ public void bundleChanged(BundleEvent event) {
+ Bundle b = event.getBundle();
+ if (event.getType() == BundleEvent.STARTING || event.getType() == BundleEvent.LAZY_ACTIVATION) {
+ if (b.getEntry("org/apache/aries/isolated/sample/SharedImpl.class") != null) {
+ try {
+ Class<?> cl = b.loadClass("org.apache.aries.isolated.sample.SharedImpl");
+ cl.newInstance();
+ loadedClass.set(true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ } else if (event.getType() == BundleEvent.INSTALLED && b instanceof CompositeBundle) {
+ ((CompositeBundle) b).getCompositeFramework().getBundleContext().addBundleListener(this);
+ }
+ }
+ });
+
+ AriesApplicationManager manager = context().getService(AriesApplicationManager.class);
+ AriesApplication app = manager.createApplication(FileSystem.getFSRoot(new File("test2.eba")));
+ AriesApplicationContext ctx = manager.install(app);
+
+ try {
+ ctx.start();
+
+ app = ctx.getApplication();
+ assertEquals(1, app.getDeploymentMetadata().getApplicationDeploymentContents().size());
+ assertEquals(1, app.getDeploymentMetadata().getApplicationProvisionBundles().size());
+ assertTrue(loadedClass.get());
+ } finally {
+ manager.uninstall(ctx);
+ }
+ }
+
private void assertHelloWorldService(String appName) throws Exception
{
assertHelloWorldService(appName, "hello world");
Added: aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/sample/SharedImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/sample/SharedImpl.java?rev=1157163&view=auto
==============================================================================
--- aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/sample/SharedImpl.java (added)
+++ aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/sample/SharedImpl.java Fri Aug 12 15:44:36 2011
@@ -0,0 +1,25 @@
+/* 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.aries.isolated.sample;
+
+import org.apache.aries.isolated.shared.Shared;
+
+public class SharedImpl implements Shared {
+
+ @Override
+ public void something() {}
+
+}
Added: aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/Shared.java
URL: http://svn.apache.org/viewvc/aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/Shared.java?rev=1157163&view=auto
==============================================================================
--- aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/Shared.java (added)
+++ aries/trunk/application/application-itests/src/test/java/org/apache/aries/isolated/shared/Shared.java Fri Aug 12 15:44:36 2011
@@ -0,0 +1,20 @@
+/* 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.aries.isolated.shared;
+
+public interface Shared {
+ public void something();
+}
Modified: aries/trunk/application/application-runtime-framework/src/main/java/org/apache/aries/application/runtime/framework/BundleFrameworkImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/application/application-runtime-framework/src/main/java/org/apache/aries/application/runtime/framework/BundleFrameworkImpl.java?rev=1157163&r1=1157162&r2=1157163&view=diff
==============================================================================
--- aries/trunk/application/application-runtime-framework/src/main/java/org/apache/aries/application/runtime/framework/BundleFrameworkImpl.java (original)
+++ aries/trunk/application/application-runtime-framework/src/main/java/org/apache/aries/application/runtime/framework/BundleFrameworkImpl.java Fri Aug 12 15:44:36 2011
@@ -24,18 +24,23 @@ import static org.apache.aries.applicati
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.aries.application.management.AriesApplication;
import org.apache.aries.application.management.spi.framework.BundleFramework;
import org.apache.aries.application.management.spi.repository.BundleRepository.BundleSuggestion;
-import org.eclipse.osgi.framework.internal.core.InternalSystemBundle;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.service.framework.CompositeBundle;
-import org.osgi.service.framework.SurrogateBundle;
import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +54,8 @@ public class BundleFrameworkImpl impleme
Framework _framework;
ServiceTracker _packageAdminTracker;
+
+ private final AtomicBoolean startLevelIncreased = new AtomicBoolean(false);
BundleFrameworkImpl(CompositeBundle cb)
{
@@ -68,6 +75,11 @@ public class BundleFrameworkImpl impleme
PackageAdmin.class.getName(), null);
_packageAdminTracker.open();
}
+
+ // make sure inner bundles are now startable
+ if (startLevelIncreased.compareAndSet(false, true)) {
+ increaseStartLevel(_compositeBundle.getCompositeFramework().getBundleContext());
+ }
}
@Override
@@ -80,9 +92,81 @@ public class BundleFrameworkImpl impleme
_packageAdminTracker = new ServiceTracker(_compositeBundle.getCompositeFramework().getBundleContext(),
PackageAdmin.class.getName(), null);
_packageAdminTracker.open();
+
+ setupStartLevelToPreventAutostart(_compositeBundle.getCompositeFramework().getBundleContext());
+ }
+ }
+
+ /**
+ * Name says it all if we don't make some adjustments bundles will be autostarted, which in the
+ * grand scheme of things causes extenders to act on the inner bundles before the outer composite is even
+ * resolved ...
+ */
+ private void setupStartLevelToPreventAutostart(BundleContext frameworkBundleContext)
+ {
+ ServiceReference ref = frameworkBundleContext.getServiceReference(StartLevel.class.getName());
+ if (ref != null) {
+ StartLevel sl = (StartLevel) frameworkBundleContext.getService(ref);
+ if (sl != null) {
+ // make sure new bundles are *not* automatically started (because that causes havoc)
+ sl.setInitialBundleStartLevel(sl.getStartLevel()+1);
+ frameworkBundleContext.ungetService(ref);
+ }
}
}
+ private void increaseStartLevel(BundleContext context) {
+ /*
+ * Algorithm for doing this
+ *
+ * 1. Set up a framework listener that will tell us when the start level has been set.
+ *
+ * 2. Change the start level. This is asynchronous so by the time the method returned the event
+ * could have been sent. This is why we set up the listener in step 1.
+ *
+ * 3. Wait until the start level has been set appropriately. At this stage all the bundles are startable
+ * and some have been started (most notably lazy activated bundles it appears). Other bundles are still
+ * in resolved state.
+ */
+
+ ServiceReference ref = context.getServiceReference(StartLevel.class.getName());
+ if (ref != null) {
+ StartLevel sl = (StartLevel) context.getService(ref);
+ if (sl != null) {
+
+ final Semaphore waitForStartLevelChangedEventToOccur = new Semaphore(0);
+
+ // step 1
+ FrameworkListener listener = new FrameworkListener() {
+ public void frameworkEvent(FrameworkEvent event)
+ {
+ if (event.getType() == FrameworkEvent.STARTLEVEL_CHANGED) {
+ waitForStartLevelChangedEventToOccur.release();
+ }
+ }
+ };
+
+ context.addFrameworkListener(listener);
+
+ // step 2
+ sl.setStartLevel(sl.getStartLevel()+1);
+
+ // step 3
+ try {
+ if (!!!waitForStartLevelChangedEventToOccur.tryAcquire(60, TimeUnit.SECONDS)) {
+ LOGGER.debug("Starting CBA child bundles took longer than 60 seconds");
+ }
+ } catch (InterruptedException e) {
+ // restore the interrupted status
+ Thread.currentThread().interrupt();
+ }
+
+ context.removeFrameworkListener(listener);
+ }
+ context.ungetService(ref);
+ }
+ }
+
public void close() throws BundleException
{
// close out packageadmin service tracker