blob: e48e06f5402f73bc210831109a298be9e3a1a716 [file] [log] [blame]
Marcel Offermanse14b3422009-11-25 23:04:32 +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 */
Pierre De Rope4d80b92009-12-04 22:48:32 +000019package org.apache.felix.dm.impl.dependencies;
Marcel Offermanse14b3422009-11-25 23:04:32 +000020
Marcel Offermanscae61362009-12-01 08:37:10 +000021import java.util.ArrayList;
Marcel Offermanse14b3422009-11-25 23:04:32 +000022import java.util.Dictionary;
Marcel Offermanscae61362009-12-01 08:37:10 +000023import java.util.List;
Marcel Offermanse14b3422009-11-25 23:04:32 +000024
Pierre De Rope4d80b92009-12-04 22:48:32 +000025import org.apache.felix.dm.dependencies.BundleDependency;
26import org.apache.felix.dm.impl.Logger;
27import org.apache.felix.dm.impl.tracker.BundleTracker;
28import org.apache.felix.dm.impl.tracker.BundleTrackerCustomizer;
29import org.apache.felix.dm.management.ServiceComponentDependency;
Marcel Offermanse14b3422009-11-25 23:04:32 +000030import org.osgi.framework.Bundle;
31import org.osgi.framework.BundleContext;
32import org.osgi.framework.BundleEvent;
33import org.osgi.framework.Filter;
34import org.osgi.framework.InvalidSyntaxException;
35
Pierre De Rope4d80b92009-12-04 22:48:32 +000036public class BundleDependencyImpl extends AbstractDependency implements BundleDependency, BundleTrackerCustomizer, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000037 private final BundleContext m_context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000038 private boolean m_isStarted;
39 private BundleTracker m_tracker;
Marcel Offermansd66c5ce2009-11-26 09:58:44 +000040 private int m_stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
Marcel Offermanscae61362009-12-01 08:37:10 +000041 private List m_services = new ArrayList();
Marcel Offermansb196d722009-11-26 17:12:12 +000042 private boolean m_isAvailable;
Marcel Offermanse14b3422009-11-25 23:04:32 +000043
44 private Object m_callbackInstance;
45 private String m_callbackAdded;
46 private String m_callbackChanged;
47 private String m_callbackRemoved;
48 private boolean m_autoConfig;
49 private Bundle m_bundleInstance;
50 private Filter m_filter;
51 private long m_bundleId = -1;
Marcel Offermansb196d722009-11-26 17:12:12 +000052
Pierre De Rope4d80b92009-12-04 22:48:32 +000053 public BundleDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +000054 super(logger);
Marcel Offermanse14b3422009-11-25 23:04:32 +000055 m_context = context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000056 m_autoConfig = true;
57 }
58
Marcel Offermanse14b3422009-11-25 23:04:32 +000059 public boolean isInstanceBound() {
60 return false; // TODO for now we are never bound to the service implementation instance
61 }
62
Marcel Offermansb196d722009-11-26 17:12:12 +000063 public synchronized boolean isAvailable() {
64 return m_isAvailable;
65 }
66
67
68 public void start(DependencyService service) {
Marcel Offermanscae61362009-12-01 08:37:10 +000069 boolean needsStarting = false;
Marcel Offermanse14b3422009-11-25 23:04:32 +000070 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +000071 m_services.add(service);
72 if (!m_isStarted) {
73 m_tracker = new BundleTracker(m_context, m_stateMask, this);
74 m_isStarted = true;
75 needsStarting = true;
76 }
Marcel Offermanse14b3422009-11-25 23:04:32 +000077 }
Marcel Offermanscae61362009-12-01 08:37:10 +000078 if (needsStarting) {
79 m_tracker.open();
80 }
Marcel Offermanse14b3422009-11-25 23:04:32 +000081 }
82
83 public void stop(DependencyService service) {
Marcel Offermanscae61362009-12-01 08:37:10 +000084 boolean needsStopping = false;
Marcel Offermanse14b3422009-11-25 23:04:32 +000085 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +000086 if (m_services.size() == 1 && m_services.contains(service)) {
87 m_isStarted = false;
88 needsStopping = true;
Marcel Offermanse14b3422009-11-25 23:04:32 +000089 }
Marcel Offermanse14b3422009-11-25 23:04:32 +000090 }
Marcel Offermanscae61362009-12-01 08:37:10 +000091 if (needsStopping) {
92 m_tracker.close();
93 m_tracker = null;
94 m_services.remove(service);
95 }
Marcel Offermanse14b3422009-11-25 23:04:32 +000096 }
97
98 public String getName() {
Marcel Offermanscae61362009-12-01 08:37:10 +000099 StringBuilder sb = new StringBuilder();
100 sb.append(m_bundleInstance.getSymbolicName());
101 sb.append(' ');
102 sb.append(m_bundleInstance.getVersion());
103 sb.append(' ');
104 sb.append(Integer.toString(m_stateMask, 2));
105 if (m_filter != null) {
106 sb.append(' ');
107 sb.append(m_filter.toString());
108 }
109 return sb.toString();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000110 }
111
112 public int getState() {
113 // TODO Auto-generated method stub
114 return 0;
115 }
116
117 public String getType() {
Marcel Offermanscae61362009-12-01 08:37:10 +0000118 return "bundle";
Marcel Offermanse14b3422009-11-25 23:04:32 +0000119 }
120
121 public Object addingBundle(Bundle bundle, BundleEvent event) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000122 // if we don't like a bundle, we could reject it here by returning null
123 if (m_bundleId >= 0 && m_bundleId != bundle.getBundleId()) {
124 return null;
125 }
126 Filter filter = m_filter;
127 if (filter != null) {
128 Dictionary headers = bundle.getHeaders();
129 if (!m_filter.match(headers)) {
130 return null;
131 }
132 }
133 return bundle;
134 }
135
136 public void addedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000137 boolean makeAvailable = makeAvailable();
138 Object[] services = m_services.toArray();
139 for (int i = 0; i < services.length; i++) {
140 DependencyService ds = (DependencyService) services[i];
141 if (makeAvailable) {
142 ds.dependencyAvailable(this);
143 if (!isRequired()) {
144 invokeAdded(ds, bundle);
145 }
146 }
147 else {
148 ds.dependencyChanged(this);
149 invokeAdded(ds, bundle);
150 }
151 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000152 }
153
154 public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000155 Object[] services = m_services.toArray();
156 for (int i = 0; i < services.length; i++) {
157 DependencyService ds = (DependencyService) services[i];
158 ds.dependencyChanged(this);
159 if (ds.isRegistered()) {
160 invokeChanged(ds, bundle);
161 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000162 }
163 }
164
165 public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000166 boolean makeUnavailable = makeUnavailable();
167 Object[] services = m_services.toArray();
168 for (int i = 0; i < services.length; i++) {
169 DependencyService ds = (DependencyService) services[i];
170 if (makeUnavailable) {
171 ds.dependencyUnavailable(this);
172 if (!isRequired()) {
173 invokeRemoved(ds, bundle);
174 }
Marcel Offermans9f3c5f42009-11-26 11:17:36 +0000175 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000176 else {
177 ds.dependencyChanged(this);
178 invokeRemoved(ds, bundle);
179 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000180 }
181 }
182
183 private synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000184 if (!isAvailable()) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000185 m_isAvailable = true;
186 return true;
187 }
188 return false;
189 }
190
191 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000192 if ((isAvailable()) && (m_tracker.getTrackingCount() == 0)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000193 m_isAvailable = false;
194 return true;
195 }
196 return false;
197 }
198
Marcel Offermanscae61362009-12-01 08:37:10 +0000199 public void invokeAdded(DependencyService dependencyService, Bundle service) {
200 Object[] callbackInstances = getCallbackInstances(dependencyService);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000201 if ((callbackInstances != null) && (m_callbackAdded != null)) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000202 invokeCallbackMethod(callbackInstances, m_callbackAdded,
203 new Class[][] {{Bundle.class}, {Object.class}, {}},
204 new Object[][] {{service}, {service}, {}}
205 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000206 }
207 }
208
Marcel Offermanscae61362009-12-01 08:37:10 +0000209 public void invokeChanged(DependencyService dependencyService, Bundle service) {
210 Object[] callbackInstances = getCallbackInstances(dependencyService);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000211 if ((callbackInstances != null) && (m_callbackChanged != null)) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000212 invokeCallbackMethod(callbackInstances, m_callbackChanged,
213 new Class[][] {{Bundle.class}, {Object.class}, {}},
214 new Object[][] {{service}, {service}, {}}
215 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000216 }
217 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000218
Marcel Offermanscae61362009-12-01 08:37:10 +0000219 public void invokeRemoved(DependencyService dependencyService, Bundle service) {
220 Object[] callbackInstances = getCallbackInstances(dependencyService);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000221 if ((callbackInstances != null) && (m_callbackRemoved != null)) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000222 invokeCallbackMethod(callbackInstances, m_callbackRemoved,
223 new Class[][] {{Bundle.class}, {Object.class}, {}},
224 new Object[][] {{service}, {service}, {}}
225 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000226 }
227 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000228
229 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000230 if (m_callbackInstance == null) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000231 return dependencyService.getCompositionInstances();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000232 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000233 else {
234 return new Object[] { m_callbackInstance };
235 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000236 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000237
Marcel Offermanse14b3422009-11-25 23:04:32 +0000238 /**
239 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
240 * dependency is added or removed. When you specify callbacks, the auto configuration
241 * feature is automatically turned off, because we're assuming you don't need it in this
242 * case.
243 *
244 * @param added the method to call when a service was added
245 * @param removed the method to call when a service was removed
246 * @return this service dependency
247 */
248 public synchronized BundleDependency setCallbacks(String added, String removed) {
249 return setCallbacks(null, added, null, removed);
250 }
251
252 /**
253 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
254 * dependency is added, changed or removed. When you specify callbacks, the auto
255 * configuration feature is automatically turned off, because we're assuming you don't
256 * need it in this case.
257 *
258 * @param added the method to call when a service was added
259 * @param changed the method to call when a service was changed
260 * @param removed the method to call when a service was removed
261 * @return this service dependency
262 */
263 public synchronized BundleDependency setCallbacks(String added, String changed, String removed) {
264 return setCallbacks(null, added, changed, removed);
265 }
266
267 /**
268 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
269 * dependency is added or removed. They are called on the instance you provide. When you
270 * specify callbacks, the auto configuration feature is automatically turned off, because
271 * we're assuming you don't need it in this case.
272 *
273 * @param instance the instance to call the callbacks on
274 * @param added the method to call when a service was added
275 * @param removed the method to call when a service was removed
276 * @return this service dependency
277 */
278 public synchronized BundleDependency setCallbacks(Object instance, String added, String removed) {
279 return setCallbacks(instance, added, null, removed);
280 }
281
282 /**
283 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
284 * dependency is added, changed or removed. They are called on the instance you provide. When you
285 * specify callbacks, the auto configuration feature is automatically turned off, because
286 * we're assuming you don't need it in this case.
287 *
288 * @param instance the instance to call the callbacks on
289 * @param added the method to call when a service was added
290 * @param changed the method to call when a service was changed
291 * @param removed the method to call when a service was removed
292 * @return this service dependency
293 */
294 public synchronized BundleDependency setCallbacks(Object instance, String added, String changed, String removed) {
295 ensureNotActive();
296 // if at least one valid callback is specified, we turn off auto configuration
297 if (added != null || removed != null || changed != null) {
298 setAutoConfig(false);
299 }
300 m_callbackInstance = instance;
301 m_callbackAdded = added;
302 m_callbackChanged = changed;
303 m_callbackRemoved = removed;
304 return this;
305 }
306
307 private void ensureNotActive() {
308 if (m_tracker != null) {
309 throw new IllegalStateException("Cannot modify state while active.");
310 }
311 }
312 public synchronized BundleDependency setAutoConfig(boolean autoConfig) {
313 ensureNotActive();
314 m_autoConfig = autoConfig;
315 return this;
316 }
317
318 public synchronized BundleDependency setRequired(boolean required) {
319 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000320 setIsRequired(required);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000321 return this;
322 }
323
324 public BundleDependency setBundle(Bundle bundle) {
325 m_bundleId = bundle.getBundleId();
326 return this;
327 }
328
329 public BundleDependency setFilter(String filter) throws IllegalArgumentException {
330 if (filter != null) {
331 try {
332 m_filter = m_context.createFilter(filter);
333 }
334 catch (InvalidSyntaxException e) {
335 throw new IllegalArgumentException(e.getMessage());
336 }
337 }
338 return this;
339 }
340
341 public BundleDependency setStateMask(int mask) {
342 m_stateMask = mask;
343 return this;
344 }
345
346 public synchronized boolean isAutoConfig() {
347 return m_autoConfig;
348 }
349
350 public Bundle getBundle() {
351 Bundle[] bundles = m_tracker.getBundles();
352 if (bundles != null && bundles.length > 0) {
353 return bundles[0];
354 }
355 return null;
356 }
357}