blob: a25750f52e28a1f7a595a441ef56157ed75e8f4e [file] [log] [blame]
Richard S. Hall46754b52007-07-16 18:36:11 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.example.extenderbased.host;
20
21import java.util.HashSet;
Richard S. Hall0db88872012-03-07 16:24:47 +000022import java.util.Iterator;
Richard S. Hall46754b52007-07-16 18:36:11 +000023import java.util.Set;
24import org.osgi.framework.Bundle;
25import org.osgi.framework.BundleContext;
26import org.osgi.framework.BundleEvent;
27import org.osgi.framework.SynchronousBundleListener;
28
29/**
Richard S. Hall88287352007-07-16 19:22:36 +000030 * This is a very simple bundle tracker utility class that tracks active
31 * bundles. The tracker must be given a bundle context upon creation,
32 * which it uses to listen for bundle events. The bundle tracker must be
33 * opened to track objects and closed when it is no longer needed. This
34 * class is abstract, which means in order to use it you must create a
35 * subclass of it. Subclasses must implement the <tt>addedBundle()</tt>
36 * and <tt>removedBundle()</tt> methods, which can be used to perform some
37 * custom action upon the activation or deactivation of bundles. Since this
38 * tracker is quite simple, its concurrency control approach is also
39 * simplistic. This means that subclasses should take great care to ensure
40 * that their <tt>addedBundle()</tt> and <tt>removedBundle()</tt> methods
41 * are very simple and do not do anything to change the state of any bundles.
Richard S. Hall46754b52007-07-16 18:36:11 +000042**/
Richard S. Hall88287352007-07-16 19:22:36 +000043public abstract class BundleTracker
Richard S. Hall46754b52007-07-16 18:36:11 +000044{
Richard S. Hall0db88872012-03-07 16:24:47 +000045 final Set<Bundle> m_bundles = new HashSet<Bundle>();
46 protected final BundleContext m_context;
Richard S. Hall88287352007-07-16 19:22:36 +000047 final SynchronousBundleListener m_listener;
48 boolean m_open;
Richard S. Hall46754b52007-07-16 18:36:11 +000049
50 /**
51 * Constructs a bundle tracker object that will use the specified
Richard S. Hall88287352007-07-16 19:22:36 +000052 * bundle context.
Richard S. Hall46754b52007-07-16 18:36:11 +000053 * @param context The bundle context to use to track bundles.
Richard S. Hall46754b52007-07-16 18:36:11 +000054 **/
Richard S. Hall88287352007-07-16 19:22:36 +000055 public BundleTracker(BundleContext context)
Richard S. Hall46754b52007-07-16 18:36:11 +000056 {
57 m_context = context;
Richard S. Hall46754b52007-07-16 18:36:11 +000058 m_listener = new SynchronousBundleListener() {
59 public void bundleChanged(BundleEvent evt)
60 {
61 synchronized (BundleTracker.this)
62 {
63 if (!m_open)
64 {
65 return;
66 }
67
68 if (evt.getType() == BundleEvent.STARTED)
69 {
Richard S. Hall0db88872012-03-07 16:24:47 +000070 if (!m_bundles.contains(evt.getBundle()))
Richard S. Hall46754b52007-07-16 18:36:11 +000071 {
Richard S. Hall0db88872012-03-07 16:24:47 +000072 m_bundles.add(evt.getBundle());
Richard S. Hall88287352007-07-16 19:22:36 +000073 addedBundle(evt.getBundle());
Richard S. Hall46754b52007-07-16 18:36:11 +000074 }
75 }
76 else if (evt.getType() == BundleEvent.STOPPED)
77 {
Richard S. Hall0db88872012-03-07 16:24:47 +000078 if (m_bundles.contains(evt.getBundle()))
Richard S. Hall46754b52007-07-16 18:36:11 +000079 {
Richard S. Hall0db88872012-03-07 16:24:47 +000080 m_bundles.remove(evt.getBundle());
Richard S. Hall88287352007-07-16 19:22:36 +000081 removedBundle(evt.getBundle());
Richard S. Hall46754b52007-07-16 18:36:11 +000082 }
83 }
84 }
85 }
86 };
87 }
88
89 /**
90 * Returns the current set of active bundles.
91 * @return The current set of active bundles.
92 **/
93 public synchronized Bundle[] getBundles()
94 {
Richard S. Hall0db88872012-03-07 16:24:47 +000095 return m_bundles.toArray(new Bundle[m_bundles.size()]);
Richard S. Hall46754b52007-07-16 18:36:11 +000096 }
97
98 /**
99 * Call this method to start the tracking of active bundles.
100 **/
101 public synchronized void open()
102 {
103 if (!m_open)
104 {
105 m_open = true;
106
107 m_context.addBundleListener(m_listener);
108
109 Bundle[] bundles = m_context.getBundles();
Richard S. Hall0db88872012-03-07 16:24:47 +0000110 for (Bundle bundle : bundles)
Richard S. Hall46754b52007-07-16 18:36:11 +0000111 {
Richard S. Hall0db88872012-03-07 16:24:47 +0000112 if (bundle.getState() == Bundle.ACTIVE)
Richard S. Hall46754b52007-07-16 18:36:11 +0000113 {
Richard S. Hall0db88872012-03-07 16:24:47 +0000114 m_bundles.add(bundle);
115 addedBundle(bundle);
Richard S. Hall46754b52007-07-16 18:36:11 +0000116 }
117 }
118 }
119 }
120
121 /**
122 * Call this method to stop the tracking of active bundles.
123 **/
124 public synchronized void close()
125 {
126 if (m_open)
127 {
128 m_open = false;
129
130 m_context.removeBundleListener(m_listener);
131
Richard S. Hall0db88872012-03-07 16:24:47 +0000132 for (Iterator<Bundle> itr = m_bundles.iterator(); itr.hasNext();)
Richard S. Hall46754b52007-07-16 18:36:11 +0000133 {
Richard S. Hall0db88872012-03-07 16:24:47 +0000134 Bundle bundle = itr.next();
135 itr.remove();
136 removedBundle(bundle);
Richard S. Hall46754b52007-07-16 18:36:11 +0000137 }
138 }
139 }
140
141 /**
Richard S. Hall88287352007-07-16 19:22:36 +0000142 * Subclasses must implement this method; it can be used to perform
143 * actions upon the activation of a bundle. Subclasses should keep
144 * this method implementation as simple as possible and should not
145 * cause the change in any bundle state to avoid concurrency issues.
Richard S. Hall46754b52007-07-16 18:36:11 +0000146 * @param bundle The bundle being added to the active set.
147 **/
Richard S. Hall88287352007-07-16 19:22:36 +0000148 protected abstract void addedBundle(Bundle bundle);
Richard S. Hall46754b52007-07-16 18:36:11 +0000149
150 /**
Richard S. Hall88287352007-07-16 19:22:36 +0000151 * Subclasses must implement this method; it can be used to perform
152 * actions upon the deactivation of a bundle. Subclasses should keep
153 * this method implementation as simple as possible and should not
154 * cause the change in any bundle state to avoid concurrency issues.
Richard S. Hall46754b52007-07-16 18:36:11 +0000155 * @param bundle The bundle being removed from the active set.
156 **/
Richard S. Hall88287352007-07-16 19:22:36 +0000157 protected abstract void removedBundle(Bundle bundle);
Richard S. Hall46754b52007-07-16 18:36:11 +0000158}