This is an automated email from the ASF dual-hosted git repository.
pauls pushed a commit to branch connect
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/connect by this push:
new 0f39641 Keep framework in a usable state when an exception happens
during init.
0f39641 is described below
commit 0f3964140bef0b2638814bf32346fe5403d75e18
Author: Karl Pauls <[email protected]>
AuthorDate: Wed Sep 23 17:58:27 2020 +0200
Keep framework in a usable state when an exception happens during init.
---
.../java/org/apache/felix/framework/Felix.java | 14 ++-
.../apache/felix/framework/StatefulResolver.java | 18 ++-
.../org/apache/felix/framework/LaunchTest.java | 138 +++++++++++++++++++++
3 files changed, 165 insertions(+), 5 deletions(-)
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java
b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 8df2c5d..81f5bcc 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -901,7 +901,6 @@ public class Felix extends BundleImpl implements Framework
}
catch (Throwable ex)
{
- m_dispatcher.stopDispatching();
m_logger.log(Logger.LOG_ERROR, "Unable to start system
bundle.", ex);
throw new RuntimeException("Unable to start system
bundle.");
}
@@ -965,6 +964,17 @@ public class Felix extends BundleImpl implements Framework
}
}
}
+ catch (Throwable t)
+ {
+ stopBundle(this, false);
+ if (m_cache != null)
+ {
+ m_cache.release();
+ m_cache = null;
+ }
+ __setState(Bundle.INSTALLED);
+ throw t;
+ }
finally
{
releaseBundleLock(this);
@@ -5195,6 +5205,8 @@ public class Felix extends BundleImpl implements Framework
// Stop framework start level thread.
m_fwkStartLevel.stop();
+ m_resolver.stop();
+
// Shutdown event dispatching queue.
m_dispatcher.stopDispatching();
diff --git
a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index 2d71eae..cca8544 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -31,7 +31,6 @@ import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
@@ -45,7 +44,6 @@ import org.apache.felix.framework.resolver.ResolveException;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.ShrinkableCollection;
import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.NativeLibrary;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.apache.felix.framework.wiring.BundleWireImpl;
import org.apache.felix.resolver.ResolverImpl;
@@ -57,6 +55,7 @@ import org.osgi.framework.CapabilityPermission;
import org.osgi.framework.Constants;
import org.osgi.framework.PackagePermission;
import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.hooks.resolver.ResolverHook;
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
import org.osgi.framework.wiring.BundleCapability;
@@ -91,6 +90,7 @@ class StatefulResolver
private final Map<String, List<BundleRevision>> m_singletons;
// Selected singleton bundle revisions.
private final Set<BundleRevision> m_selectedSingletons;
+ private volatile ServiceRegistration<?> m_serviceRegistration;
StatefulResolver(Felix felix, ServiceRegistry registry)
{
@@ -168,12 +168,22 @@ class StatefulResolver
void start()
{
- m_registry.registerService(m_felix,
- new String[] { Resolver.class.getName() },
+ m_serviceRegistration = m_registry.registerService(m_felix,
+ new String[]{Resolver.class.getName()},
new ResolverImpl(m_logger, 1),
null);
}
+ void stop()
+ {
+ ServiceRegistration reg = m_serviceRegistration;
+ if (reg != null)
+ {
+ reg.unregister();
+ m_serviceRegistration = null;
+ }
+ }
+
synchronized void addRevision(BundleRevision br)
{
// Always attempt to remove the revision, since
diff --git a/framework/src/test/java/org/apache/felix/framework/LaunchTest.java
b/framework/src/test/java/org/apache/felix/framework/LaunchTest.java
new file mode 100644
index 0000000..47f72e9
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/LaunchTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.felix.framework;
+
+import junit.framework.TestCase;
+import org.apache.felix.framework.util.FelixConstants;
+import org.osgi.framework.*;
+import org.osgi.framework.connect.ConnectModule;
+import org.osgi.framework.connect.ModuleConnector;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.resolver.Resolver;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class LaunchTest extends TestCase {
+ public void testInit() throws Exception{
+ Map params = new HashMap();
+ File cacheDir = File.createTempFile("felix-cache", ".dir");
+ cacheDir.delete();
+ cacheDir.mkdirs();
+ String cache = cacheDir.getPath();
+ params.put("felix.cache.profiledir", cache);
+ params.put("felix.cache.dir", cache);
+ params.put(FelixConstants.LOG_LOGGER_PROP, new Logger(){
+ @Override
+ protected void doLogOut(int level, String s, Throwable throwable) {
+
+ }
+ });
+ params.put(Constants.FRAMEWORK_STORAGE, cache);
+
+ try {
+ Framework f = new Felix(params, new ModuleConnector() {
+ boolean first = true;
+ @Override
+ public void initialize(File storage, Map<String, String>
configuration) {
+ if (first) {
+ first = false;
+ throw new IllegalStateException("Test");
+ }
+ }
+
+ @Override
+ public Optional<ConnectModule> connect(String location) throws
BundleException {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<BundleActivator> newBundleActivator() {
+ return Optional.empty();
+ }
+ }){
+ boolean first = true;
+ @Override
+ synchronized BundleActivator getActivator() {
+ BundleActivator activator = super.getActivator();
+ if (first) {
+ first = false;
+ return new BundleActivator() {
+ @Override
+ public void start(BundleContext context) throws
Exception {
+ activator.start(context);
+ throw new IllegalStateException("TEst");
+ }
+
+ @Override
+ public void stop(BundleContext context) throws
Exception {
+ activator.stop(context);
+ }
+ };
+ }
+ return super.getActivator();
+ }
+ };
+ try {
+ f.init();
+ fail("Excepted init to fail");
+ } catch (Exception ex) {
+
+ }
+ assertEquals(Bundle.INSTALLED, f.getState());
+ try {
+ f.init();
+ fail("Excepted init to fail");
+ } catch (Exception ex) {
+
+ }
+ assertEquals(Bundle.INSTALLED, f.getState());
+ f.init();
+ assertEquals(Bundle.STARTING, f.getState());
+ f.stop();
+ f.waitForStop(0);
+ assertEquals(Bundle.RESOLVED, f.getState());
+ f.init();
+
assertEquals(1,f.getBundleContext().getServiceReferences(Resolver.class,
null).size());
+ assertEquals(Bundle.STARTING, f.getState());
+ f.start();
+ assertEquals(Bundle.ACTIVE, f.getState());
+ f.stop();
+ f.waitForStop(0);
+ }
+ finally {
+ deleteDir(cacheDir);
+ }
+ }
+
+ private static void deleteDir(File root) throws IOException
+ {
+ if (root.isDirectory())
+ {
+ for (File file : root.listFiles())
+ {
+ deleteDir(file);
+ }
+ }
+ assertTrue(root.delete());
+ }
+}