You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2008/05/09 00:27:17 UTC

svn commit: r654647 - in /felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender: BundleTracker.java ExtenderManager.java ExtenderModelHandler.java

Author: clement
Date: Thu May  8 15:27:16 2008
New Revision: 654647

URL: http://svn.apache.org/viewvc?rev=654647&view=rev
Log:
Add a bundle tracker to externalize the tracking code from the extension manager.

Added:
    felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java
Modified:
    felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java
    felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java

Added: felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java?rev=654647&view=auto
==============================================================================
--- felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java (added)
+++ felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java Thu May  8 15:27:16 2008
@@ -0,0 +1,154 @@
+/* 
+ * 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.ipojo.handler.extender;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ * This is a very simple bundle tracker utility class that tracks active
+ * bundles. The tracker must be given a bundle context upon creation,
+ * which it uses to listen for bundle events. The bundle tracker must be
+ * opened to track objects and closed when it is no longer needed. This
+ * class is abstract, which means in order to use it you must create a
+ * subclass of it. Subclasses must implement the <tt>addedBundle()</tt>
+ * and <tt>removedBundle()</tt> methods, which can be used to perform some
+ * custom action upon the activation or deactivation of bundles. Since this
+ * tracker is quite simple, its concurrency control approach is also
+ * simplistic. This means that subclasses should take great care to ensure
+ * that their <tt>addedBundle()</tt> and <tt>removedBundle()</tt> methods
+ * are very simple and do not do anything to change the state of any bundles.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ **/
+public abstract class BundleTracker {
+    /**
+     * Set of tracked bundles.
+     */
+    final Set m_bundleSet = new HashSet();
+
+    /**
+     * Bundle context.
+     */
+    final BundleContext m_context;
+
+    /**
+     * Synchronous bundle listener.
+     */
+    final SynchronousBundleListener m_listener;
+
+    /**
+     * Flag indicating if the tracking is open.
+     */
+    boolean m_open;
+
+    /**
+     * Constructs a bundle tracker object that will use the specified
+     * bundle context.
+     * @param context The bundle context to use to track bundles.
+     **/
+    public BundleTracker(BundleContext context) {
+        m_context = context;
+        m_listener = new SynchronousBundleListener() {
+            public void bundleChanged(BundleEvent evt) {
+                synchronized (BundleTracker.this) {
+                    if (!m_open) { return; }
+
+                    if (evt.getType() == BundleEvent.STARTED) {
+                        if (!m_bundleSet.contains(evt.getBundle())) {
+                            m_bundleSet.add(evt.getBundle());
+                            addedBundle(evt.getBundle());
+                        }
+                    } else if (evt.getType() == BundleEvent.STOPPED) {
+                        if (m_bundleSet.contains(evt.getBundle())) {
+                            m_bundleSet.remove(evt.getBundle());
+                            removedBundle(evt.getBundle());
+                        }
+                    }
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns the current set of active bundles.
+     * @return The current set of active bundles.
+     **/
+    public synchronized Bundle[] getBundles() {
+        return (Bundle[]) m_bundleSet.toArray(new Bundle[m_bundleSet.size()]);
+    }
+
+    /**
+     * Call this method to start the tracking of active bundles.
+     **/
+    public synchronized void open() {
+        if (!m_open) {
+            m_open = true;
+
+            m_context.addBundleListener(m_listener);
+
+            Bundle[] bundles = m_context.getBundles();
+            for (int i = 0; i < bundles.length; i++) {
+                if (bundles[i].getState() == Bundle.ACTIVE) {
+                    m_bundleSet.add(bundles[i]);
+                    addedBundle(bundles[i]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Call this method to stop the tracking of active bundles.
+     **/
+    public synchronized void close() {
+        if (m_open) {
+            m_open = false;
+
+            m_context.removeBundleListener(m_listener);
+
+            Bundle[] bundles = (Bundle[]) m_bundleSet.toArray(new Bundle[m_bundleSet.size()]);
+            for (int i = 0; i < bundles.length; i++) {
+                if (m_bundleSet.remove(bundles[i])) {
+                    removedBundle(bundles[i]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Subclasses must implement this method; it can be used to perform
+     * actions upon the activation of a bundle. Subclasses should keep
+     * this method implementation as simple as possible and should not
+     * cause the change in any bundle state to avoid concurrency issues.
+     * @param bundle The bundle being added to the active set.
+     **/
+    protected abstract void addedBundle(Bundle bundle);
+
+    /**
+     * Subclasses must implement this method; it can be used to perform
+     * actions upon the deactivation of a bundle. Subclasses should keep
+     * this method implementation as simple as possible and should not
+     * cause the change in any bundle state to avoid concurrency issues.
+     * @param bundle The bundle being removed from the active set.
+     **/
+    protected abstract void removedBundle(Bundle bundle);
+}

Modified: felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java?rev=654647&r1=654646&r2=654647&view=diff
==============================================================================
--- felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java (original)
+++ felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java Thu May  8 15:27:16 2008
@@ -19,22 +19,19 @@
 package org.apache.felix.ipojo.handler.extender;
 
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
 import java.util.Dictionary;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.apache.felix.ipojo.PrimitiveHandler;
 import org.apache.felix.ipojo.util.Callback;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.SynchronousBundleListener;
 
 /**
  * Track and manage extensions.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class ExtenderManager implements SynchronousBundleListener {
+public class ExtenderManager extends BundleTracker {
     
     /**
      * Looked extension.
@@ -57,14 +54,9 @@
     private PrimitiveHandler m_handler;
     
     /**
-     * Bundle context. 
+     * Set of managed bundles.
      */
-    private BundleContext m_context;
-    
-    /**
-     * List of managed bundles. 
-     */
-    private List m_bundles = new ArrayList();
+    private Set m_bundles = new HashSet();
     
     /**
      * Constructor.
@@ -74,40 +66,27 @@
      * @param unbind : onDeparture method.
      */
     public ExtenderManager(ExtenderModelHandler handler, String extension, String bind, String unbind) {
+        super(handler.getInstanceManager().getContext());
         m_handler = handler;
         m_onArrival = new Callback(bind, new Class[] {Bundle.class, String.class}, false, m_handler.getInstanceManager());
         m_onDeparture = new Callback(unbind, new Class[] {Bundle.class}, false, m_handler.getInstanceManager());
         m_extension = extension;
-        m_context = handler.getInstanceManager().getContext();
     }
-    
-    /**
-     * Start method.
-     * Look for already presents bundle and register a (synchronous) bundle listener.
-     */
-    public void start() {
-        synchronized (this) {
-            // listen to any changes in bundles.
-            m_context.addBundleListener(this);
-            // compute already started bundles.
-            for (int i = 0; i < m_context.getBundles().length; i++) {
-                if (m_context.getBundles()[i].getState() == Bundle.ACTIVE) {
-                    onArrival(m_context.getBundles()[i]);
-                }
-            }
-        }
-    }
-    
+
+
     /**
-     * Manage a bundle arrival:
-     * Check the extension and manage it if present.
-     * @param bundle : bundle.
+     * A bundle arrives.
+     * Checks if the bundle match with the looked extension, if so call the arrival callback.
+     * @param bundle : arriving bundle.
+     * @see org.apache.felix.ipojo.handler.extender.BundleTracker#addedBundle(org.osgi.framework.Bundle)
      */
-    private void onArrival(Bundle bundle) {
+    protected void addedBundle(Bundle bundle) {
         Dictionary headers = bundle.getHeaders();
         String header = (String) headers.get(m_extension);
         if (header != null) {
-            m_bundles.add(bundle);
+            synchronized (this) {
+                m_bundleSet.add(bundle);
+            }
             try {
                 m_onArrival.call(new Object[] {bundle, header});
             } catch (NoSuchMethodException e) {
@@ -124,40 +103,18 @@
     }
 
     /**
-     * Stop method.
-     * Remove the bundle listener. 
+     * A bundle is stopping.
+     * Check if the bundle was managed, if so call the remove departure callback.
+     * @param bundle : leaving bundle.
+     * @see org.apache.felix.ipojo.handler.extender.BundleTracker#removedBundle(org.osgi.framework.Bundle)
      */
-    public void stop() {
-        m_context.removeBundleListener(this);
-        m_bundles.clear();
-    }
-
-    /**
-     * Bundle listener.
-     * @param event : event.
-     * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
-     */
-    public void bundleChanged(BundleEvent event) {
-        switch (event.getType()) {
-            case BundleEvent.STARTED:
-                onArrival(event.getBundle());
-                break;
-            case BundleEvent.STOPPING:
-                onDeparture(event.getBundle());
-                break;
-            default: 
-                break;
+    protected void removedBundle(Bundle bundle) {
+        boolean contained;
+        synchronized (this) {
+            contained = m_bundles.remove(bundle); // Stack confinement
         }
         
-    }
-
-    /**
-     * Manage a bundle departure.
-     * If the bundle was managed, invoke the OnDeparture callback, and remove the bundle from the list.
-     * @param bundle : bundle.
-     */
-    private void onDeparture(Bundle bundle) {
-        if (m_bundles.contains(bundle)) {
+        if (contained) {
             try {
                 m_onDeparture.call(new Object[] {bundle});
             } catch (NoSuchMethodException e) {

Modified: felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java?rev=654647&r1=654646&r2=654647&view=diff
==============================================================================
--- felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java (original)
+++ felix/trunk/ipojo/extender.pattern.handler/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java Thu May  8 15:27:16 2008
@@ -41,6 +41,7 @@
     
     /**
      * Extension manager list.
+     * Immutable once set.
      */
     private List m_managers = new ArrayList(1);
 
@@ -77,7 +78,7 @@
      */
     public void start() {
         for (int i = 0; i < m_managers.size(); i++) {
-            ((ExtenderManager) m_managers.get(i)).start();
+            ((ExtenderManager) m_managers.get(i)).open();
         }
     }
 
@@ -87,7 +88,7 @@
      */
     public void stop() {
         for (int i = 0; i < m_managers.size(); i++) {
-            ((ExtenderManager) m_managers.get(i)).stop();
+            ((ExtenderManager) m_managers.get(i)).close();
         } 
     }