Implement new start level approach. (FELIX-2975)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1128399 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 3d7196b..17396fb 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -38,6 +38,7 @@
import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
+import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWire;
@@ -999,9 +1000,14 @@
getFramework().uninstallBundle(this);
}
- public <A> A adapt(Class<A> type)
+ public synchronized <A> A adapt(Class<A> type)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ if (type == BundleStartLevel.class)
+ {
+ return (A) getFramework().adapt(FrameworkStartLevelImpl.class)
+ .createBundleStartLevel(this);
+ }
+ return null;
}
public File getDataFile(String filename)
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 a6e009d..1cae819 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -70,6 +70,7 @@
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.hooks.service.FindHook;
import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
@@ -88,6 +89,7 @@
// Framework wiring object.
private final FrameworkWiringImpl m_fwkWiring;
+ private final FrameworkStartLevelImpl m_fwkStartLevel;
// Logging related member variables.
private final Logger m_logger;
@@ -391,6 +393,8 @@
// Create framework wiring object.
m_fwkWiring = new FrameworkWiringImpl(this);
+ // Create framework start level object.
+ m_fwkStartLevel = new FrameworkStartLevelImpl(this);
}
Logger getLogger()
@@ -460,10 +464,16 @@
@Override
public <A> A adapt(Class<A> type)
{
- if (type == FrameworkWiring.class)
+ if ((type == FrameworkWiring.class)
+ || (type == FrameworkWiringImpl.class))
{
return (A) m_fwkWiring;
}
+ else if ((type == FrameworkStartLevel.class)
+ || (type == FrameworkStartLevelImpl.class))
+ {
+ return (A) m_fwkStartLevel;
+ }
return super.adapt(type);
}
@@ -848,7 +858,7 @@
if (sl instanceof StartLevelImpl)
{
- ((StartLevelImpl) sl).setStartLevelAndWait(startLevel);
+ m_fwkStartLevel.setStartLevelAndWait(startLevel);
}
else
{
@@ -1078,7 +1088,7 @@
* directly.
* @param requestedLevel The new start level of the framework.
**/
- void setActiveStartLevel(int requestedLevel)
+ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners)
{
Bundle[] bundles = null;
@@ -1266,6 +1276,24 @@
if (getState() == Bundle.ACTIVE)
{
fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, this, null);
+
+ if (listeners != null)
+ {
+ FrameworkEvent event = new FrameworkEvent(
+ FrameworkEvent.STARTLEVEL_CHANGED, this, null);
+ for (FrameworkListener l : listeners)
+ {
+ try
+ {
+ l.frameworkEvent(event);
+ }
+ catch (Throwable th)
+ {
+ m_logger.log(Logger.LOG_ERROR,
+ "Framework listener delivery error.", th);
+ }
+ }
+ }
}
}
@@ -1801,7 +1829,7 @@
// Check to see if there is a start level change in progress and if so
// add this bundle to the bundles being processed by the start level
// thread and return.
- if (!Thread.currentThread().getName().equals(StartLevelImpl.THREAD_NAME))
+ if (!Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME))
{
synchronized (m_startLevelBundles)
{
@@ -4848,20 +4876,12 @@
// shutdown happens on its own thread, we can wait for the start
// level service to finish before proceeding by calling the
// non-spec setStartLevelAndWait() method.
- try
- {
- StartLevelImpl sl = (StartLevelImpl) getService(
- Felix.this,
- getServiceReferences(Felix.this, StartLevel.class.getName(), null, true)[0]);
- sl.setStartLevelAndWait(0);
- }
- catch (InvalidSyntaxException ex)
- {
- // Should never happen.
- }
+ m_fwkStartLevel.setStartLevelAndWait(0);
// Stop framework wiring thread.
m_fwkWiring.stop();
+ // Stop framework start level thread.
+ m_fwkStartLevel.stop();
// Shutdown event dispatching queue.
EventDispatcher.shutdown();
diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java
new file mode 100644
index 0000000..6ce7924
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java
@@ -0,0 +1,303 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
+
+class FrameworkStartLevelImpl implements FrameworkStartLevel, Runnable
+{
+ static final String THREAD_NAME = "FelixStartLevel";
+
+ private static final int BUNDLE_IDX = 0;
+ private static final int STARTLEVEL_IDX = 1;
+
+ private final Felix m_felix;
+ private final List m_requests = new ArrayList();
+ private final List<FrameworkListener[]> m_requestListeners
+ = new ArrayList<FrameworkListener[]>();
+ private Thread m_thread = null;
+
+ FrameworkStartLevelImpl(Felix felix)
+ {
+ m_felix = felix;
+ }
+
+ // Should only be called hold requestList lock.
+ private void startThread()
+ {
+ // Start a thread to perform asynchronous package refreshes.
+ if (m_thread == null)
+ {
+ m_thread = new Thread(this, THREAD_NAME);
+ m_thread.setDaemon(true);
+ m_thread.start();
+ }
+ }
+
+ /**
+ * Stops the FelixStartLevel thread on system shutdown. Shutting down the
+ * thread explicitly is required in the embedded case, where Felix may be
+ * stopped without the Java VM being stopped. In this case the
+ * FelixStartLevel thread must be stopped explicitly.
+ * <p>
+ * This method is called by the
+ * {@link StartLevelActivator#stop(BundleContext)} method.
+ */
+ void stop()
+ {
+ synchronized (m_requests)
+ {
+ if (m_thread != null)
+ {
+ // Null thread variable to signal to the thread that
+ // we want it to exit.
+ m_thread = null;
+
+ // Wake up the thread, if it is currently in the wait() state
+ // for more work.
+ m_requests.notifyAll();
+ }
+ }
+ }
+
+ public Bundle getBundle()
+ {
+ return m_felix;
+ }
+
+ public int getStartLevel()
+ {
+ return m_felix.getActiveStartLevel();
+ }
+
+ public void setStartLevel(int startlevel, FrameworkListener... listeners)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(m_felix, AdminPermission.STARTLEVEL));
+ }
+
+ if (startlevel <= 0)
+ {
+ throw new IllegalArgumentException(
+ "Start level must be greater than zero.");
+ }
+
+ synchronized (m_requests)
+ {
+ // Start thread if necessary.
+ startThread();
+ // Queue request.
+ m_requestListeners.add(listeners);
+ m_requests.add(new Integer(startlevel));
+ m_requests.notifyAll();
+ }
+ }
+
+ /**
+ * This method is currently only called by the by the thread that calls
+ * the Felix.start() method and the shutdown thread when the
+ * framework is shutting down.
+ * @param startlevel
+ **/
+ /* package */ void setStartLevelAndWait(int startlevel)
+ {
+ Object request = new Integer(startlevel);
+ synchronized (request)
+ {
+ synchronized (m_requests)
+ {
+ // Start thread if necessary.
+ startThread();
+ // Queue request.
+ m_requestListeners.add(null);
+ m_requests.add(request);
+ m_requests.notifyAll();
+ }
+
+ try
+ {
+ request.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ // Log it and ignore since it won't cause much of an issue.
+ m_felix.getLogger().log(
+ Logger.LOG_WARNING,
+ "Wait for start level change during shutdown interrupted.",
+ ex);
+ }
+ }
+ }
+
+ public int getInitialBundleStartLevel()
+ {
+ return m_felix.getInitialBundleStartLevel();
+ }
+
+ public void setInitialBundleStartLevel(int startlevel)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(m_felix, AdminPermission.STARTLEVEL));
+ }
+ m_felix.setInitialBundleStartLevel(startlevel);
+ }
+
+ BundleStartLevel createBundleStartLevel(BundleImpl bundle)
+ {
+ return new BundleStartLevelImpl(bundle);
+ }
+
+ class BundleStartLevelImpl implements BundleStartLevel
+ {
+ private BundleImpl m_bundle;
+
+ private BundleStartLevelImpl(BundleImpl bundle)
+ {
+ m_bundle = bundle;
+ }
+
+ public Bundle getBundle()
+ {
+ return m_bundle;
+ }
+
+ public int getStartLevel()
+ {
+ return m_felix.getBundleStartLevel(m_bundle);
+ }
+
+ public void setStartLevel(int startlevel)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(m_bundle, AdminPermission.EXECUTE));
+ }
+
+ if (m_bundle.getBundleId() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Cannot change system bundle start level.");
+ }
+ else if (startlevel <= 0)
+ {
+ throw new IllegalArgumentException(
+ "Start level must be greater than zero.");
+ }
+ synchronized (m_requests)
+ {
+ // Start thread if necessary.
+ startThread();
+ // Synchronously persists the start level.
+ ((BundleImpl) m_bundle).setStartLevel(startlevel);
+ // Queue request.
+ m_requestListeners.add(null);
+ m_requests.add(new Object[] { m_bundle, new Integer(startlevel) });
+ m_requests.notifyAll();
+ }
+ }
+
+ public boolean isPersistentlyStarted()
+ {
+ return m_felix.isBundlePersistentlyStarted(m_bundle);
+ }
+
+ public boolean isActivationPolicyUsed()
+ {
+ return m_felix.isBundleActivationPolicyUsed(m_bundle);
+ }
+ }
+
+ public void run()
+ {
+ // This thread loops forever, thus it should
+ // be a daemon thread.
+ while (true)
+ {
+ Object request = null;
+ FrameworkListener[] listeners = null;
+ synchronized (m_requests)
+ {
+ // Wait for a request.
+ while (m_requests.isEmpty())
+ {
+ // Terminate the thread if requested to do so (see stop()).
+ if (m_thread == null)
+ {
+ return;
+ }
+
+ try
+ {
+ m_requests.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ // Ignore.
+ }
+ }
+
+ // Get the requested start level.
+ request = m_requests.remove(0);
+ listeners = m_requestListeners.remove(0);
+ }
+
+ // If the request object is an Integer, then the request
+ // is to set the framework start level. If the request is
+ // an Object array, then the request is to set the start
+ // level for a bundle.
+ // NOTE: We don't catch any exceptions here, because
+ // the invoked methods shield us from exceptions by
+ // catching Throwables when they invoke callbacks.
+ if (request instanceof Integer)
+ {
+ // Set the new framework start level.
+ m_felix.setActiveStartLevel(((Integer) request).intValue(), listeners);
+ }
+ else
+ {
+ Bundle bundle = (Bundle) ((Object[]) request)[BUNDLE_IDX];
+ int startlevel = ((Integer) ((Object[]) request)[STARTLEVEL_IDX]).intValue();
+ m_felix.setBundleStartLevel(bundle, startlevel);
+ }
+
+ // Notify any waiting thread that this request is done.
+ synchronized (request)
+ {
+ request.notifyAll();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java b/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
index fcabcba..2888675 100644
--- a/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -44,6 +44,5 @@
public void stop(BundleContext context) throws Exception
{
m_reg.unregister();
- m_startLevel.stop();
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
index 2b3e112..74fed6f 100644
--- a/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -18,69 +18,32 @@
*/
package org.apache.felix.framework;
-import java.util.ArrayList;
-import java.util.List;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.osgi.service.startlevel.StartLevel;
/**
* StartLevel service implementation.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
**/
-public class StartLevelImpl implements StartLevel, Runnable
+public class StartLevelImpl implements StartLevel
{
- static final String THREAD_NAME = "FelixStartLevel";
-
- private static final int BUNDLE_IDX = 0;
- private static final int STARTLEVEL_IDX = 1;
-
private final Felix m_felix;
- private final List m_requestList = new ArrayList();
- private Thread m_thread = null;
public StartLevelImpl(Felix felix)
{
m_felix = felix;
- // Start a thread to perform asynchronous package refreshes.
- m_thread = new Thread(this, "FelixStartLevel");
- m_thread.setDaemon(true);
- m_thread.start();
}
-
- /**
- * Stops the FelixStartLevel thread on system shutdown. Shutting down the
- * thread explicitly is required in the embedded case, where Felix may be
- * stopped without the Java VM being stopped. In this case the
- * FelixStartLevel thread must be stopped explicitly.
- * <p>
- * This method is called by the
- * {@link StartLevelActivator#stop(BundleContext)} method.
- */
- void stop()
- {
- synchronized (m_requestList)
- {
- if (m_thread != null)
- {
- // Null thread variable to signal to the thread that
- // we want it to exit.
- m_thread = null;
-
- // Wake up the thread, if it is currently in the wait() state
- // for more work.
- m_requestList.notifyAll();
- }
- }
- }
-
+
/* (non-Javadoc)
* @see org.osgi.service.startlevel.StartLevel#getStartLevel()
**/
public int getStartLevel()
{
- return m_felix.getActiveStartLevel();
+ return m_felix.adapt(FrameworkStartLevel.class).getStartLevel();
}
/* (non-Javadoc)
@@ -88,57 +51,7 @@
**/
public void setStartLevel(int startlevel)
{
- Object sm = System.getSecurityManager();
-
- if (sm != null)
- {
- ((SecurityManager) sm).checkPermission(
- new AdminPermission(m_felix, AdminPermission.STARTLEVEL));
- }
-
- if (startlevel <= 0)
- {
- throw new IllegalArgumentException(
- "Start level must be greater than zero.");
- }
-
- synchronized (m_requestList)
- {
- m_requestList.add(new Integer(startlevel));
- m_requestList.notifyAll();
- }
- }
-
- /**
- * This method is currently only called by the by the thread that calls
- * the Felix.start() method and the shutdown thread when the
- * framework is shutting down.
- * @param startlevel
- **/
- /* package */ void setStartLevelAndWait(int startlevel)
- {
- Object request = new Integer(startlevel);
- synchronized (request)
- {
- synchronized (m_requestList)
- {
- m_requestList.add(request);
- m_requestList.notifyAll();
- }
-
- try
- {
- request.wait();
- }
- catch (InterruptedException ex)
- {
- // Log it and ignore since it won't cause much of an issue.
- m_felix.getLogger().log(
- Logger.LOG_WARNING,
- "Wait for start level change during shutdown interrupted.",
- ex);
- }
- }
+ m_felix.adapt(FrameworkStartLevel.class).setStartLevel(startlevel);
}
/* (non-Javadoc)
@@ -146,7 +59,7 @@
**/
public int getBundleStartLevel(Bundle bundle)
{
- return m_felix.getBundleStartLevel(bundle);
+ return bundle.adapt(BundleStartLevel.class).getStartLevel();
}
/* (non-Javadoc)
@@ -154,32 +67,7 @@
**/
public void setBundleStartLevel(Bundle bundle, int startlevel)
{
- Object sm = System.getSecurityManager();
-
- if (sm != null)
- {
- ((SecurityManager) sm).checkPermission(
- new AdminPermission(bundle, AdminPermission.EXECUTE));
- }
-
- if (bundle.getBundleId() == 0)
- {
- throw new IllegalArgumentException(
- "Cannot change system bundle start level.");
- }
- else if (startlevel <= 0)
- {
- throw new IllegalArgumentException(
- "Start level must be greater than zero.");
- }
- synchronized (m_requestList)
- {
- // Synchronously persists the start level.
- ((BundleImpl) bundle).setStartLevel(startlevel);
- // Asynchronously process the start level change.
- m_requestList.add(new Object[] { bundle, new Integer(startlevel) });
- m_requestList.notifyAll();
- }
+ bundle.adapt(BundleStartLevel.class).setStartLevel(startlevel);
}
/* (non-Javadoc)
@@ -187,7 +75,7 @@
**/
public int getInitialBundleStartLevel()
{
- return m_felix.getInitialBundleStartLevel();
+ return m_felix.adapt(FrameworkStartLevel.class).getInitialBundleStartLevel();
}
/* (non-Javadoc)
@@ -195,14 +83,7 @@
**/
public void setInitialBundleStartLevel(int startlevel)
{
- Object sm = System.getSecurityManager();
-
- if (sm != null)
- {
- ((SecurityManager) sm).checkPermission(
- new AdminPermission(m_felix, AdminPermission.STARTLEVEL));
- }
- m_felix.setInitialBundleStartLevel(startlevel);
+ m_felix.adapt(FrameworkStartLevel.class).setInitialBundleStartLevel(startlevel);
}
/* (non-Javadoc)
@@ -210,7 +91,7 @@
**/
public boolean isBundlePersistentlyStarted(Bundle bundle)
{
- return m_felix.isBundlePersistentlyStarted(bundle);
+ return bundle.adapt(BundleStartLevel.class).isPersistentlyStarted();
}
/* (non-Javadoc)
@@ -218,65 +99,6 @@
**/
public boolean isBundleActivationPolicyUsed(Bundle bundle)
{
- return m_felix.isBundleActivationPolicyUsed(bundle);
+ return bundle.adapt(BundleStartLevel.class).isActivationPolicyUsed();
}
-
- public void run()
- {
- // This thread loops forever, thus it should
- // be a daemon thread.
- while (true)
- {
- Object request = null;
- synchronized (m_requestList)
- {
- // Wait for a request.
- while (m_requestList.size() == 0)
- {
- // Terminate the thread if requested to do so (see stop()).
- if (m_thread == null)
- {
- return;
- }
-
- try
- {
- m_requestList.wait();
- }
- catch (InterruptedException ex)
- {
- // Ignore.
- }
- }
-
- // Get the requested start level.
- request = m_requestList.remove(0);
- }
-
- // If the request object is an Integer, then the request
- // is to set the framework start level. If the request is
- // an Object array, then the request is to set the start
- // level for a bundle.
- // NOTE: We don't catch any exceptions here, because
- // the invoked methods shield us from exceptions by
- // catching Throwables when they invoke callbacks.
- if (request instanceof Integer)
- {
- // Set the new framework start level.
- m_felix.setActiveStartLevel(((Integer) request).intValue());
- }
- else
- {
- Bundle bundle = (Bundle) ((Object[]) request)[BUNDLE_IDX];
- int startlevel = ((Integer) ((Object[]) request)[STARTLEVEL_IDX]).intValue();
- m_felix.setBundleStartLevel(bundle, startlevel);
- }
-
- // Notify any waiting thread that this request is done.
- synchronized (request)
- {
- request.notifyAll();
- }
- }
- }
-}
+}
\ No newline at end of file