blob: 2946486dd3475da08ded90dba87d644a1b9ebb71 [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 Offermansd665eaf2010-02-16 15:56:35 +000021import java.lang.reflect.Proxy;
Marcel Offermanscae61362009-12-01 08:37:10 +000022import java.util.ArrayList;
Marcel Offermanse14b3422009-11-25 23:04:32 +000023import java.util.Dictionary;
Marcel Offermanscae61362009-12-01 08:37:10 +000024import java.util.List;
Marcel Offermanse14b3422009-11-25 23:04:32 +000025
Pierre De Rope4d80b92009-12-04 22:48:32 +000026import org.apache.felix.dm.dependencies.BundleDependency;
Marcel Offermansb1959f42010-07-01 12:23:51 +000027import org.apache.felix.dm.dependencies.Dependency;
Marcel Offermansd665eaf2010-02-16 15:56:35 +000028import org.apache.felix.dm.impl.DefaultNullObject;
Pierre De Rope4d80b92009-12-04 22:48:32 +000029import org.apache.felix.dm.impl.Logger;
30import org.apache.felix.dm.impl.tracker.BundleTracker;
31import org.apache.felix.dm.impl.tracker.BundleTrackerCustomizer;
32import org.apache.felix.dm.management.ServiceComponentDependency;
Marcel Offermanse14b3422009-11-25 23:04:32 +000033import org.osgi.framework.Bundle;
34import org.osgi.framework.BundleContext;
35import org.osgi.framework.BundleEvent;
36import org.osgi.framework.Filter;
37import org.osgi.framework.InvalidSyntaxException;
38
Marcel Offermans61a81142010-04-02 15:16:50 +000039public class BundleDependencyImpl extends DependencyBase implements BundleDependency, BundleTrackerCustomizer, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000040 private final BundleContext m_context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000041 private boolean m_isStarted;
42 private BundleTracker m_tracker;
Marcel Offermansd66c5ce2009-11-26 09:58:44 +000043 private int m_stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
Marcel Offermanscae61362009-12-01 08:37:10 +000044 private List m_services = new ArrayList();
Marcel Offermansb196d722009-11-26 17:12:12 +000045 private boolean m_isAvailable;
Marcel Offermanse14b3422009-11-25 23:04:32 +000046
47 private Object m_callbackInstance;
48 private String m_callbackAdded;
49 private String m_callbackChanged;
50 private String m_callbackRemoved;
51 private boolean m_autoConfig;
52 private Bundle m_bundleInstance;
53 private Filter m_filter;
54 private long m_bundleId = -1;
Marcel Offermansd665eaf2010-02-16 15:56:35 +000055 private boolean m_propagate;
56 private String m_autoConfigInstance;
57 private Object m_nullObject;
58 private boolean m_autoConfigInvoked;
59
Marcel Offermansb196d722009-11-26 17:12:12 +000060
Pierre De Rope4d80b92009-12-04 22:48:32 +000061 public BundleDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +000062 super(logger);
Marcel Offermanse14b3422009-11-25 23:04:32 +000063 m_context = context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000064 m_autoConfig = true;
65 }
Marcel Offermansb1959f42010-07-01 12:23:51 +000066
67 public BundleDependencyImpl(BundleDependencyImpl prototype) {
68 super(prototype);
69 m_context = prototype.m_context;
70 m_autoConfig = prototype.m_autoConfig;
71 m_stateMask = prototype.m_stateMask;
72 m_nullObject = prototype.m_nullObject;
73 m_bundleInstance = prototype.m_bundleInstance;
74 m_filter = prototype.m_filter;
75 m_bundleId = prototype.m_bundleId;
76 m_propagate = prototype.m_propagate;
77 m_callbackInstance = prototype.m_callbackInstance;
78 m_callbackAdded = prototype.m_callbackAdded;
79 m_callbackChanged = prototype.m_callbackChanged;
80 m_callbackRemoved = prototype.m_callbackRemoved;
81 m_autoConfigInstance = prototype.m_autoConfigInstance;
82 }
83
84 public Dependency createCopy() {
85 return new BundleDependencyImpl(this);
86 }
Marcel Offermanse14b3422009-11-25 23:04:32 +000087
Marcel Offermans61a81142010-04-02 15:16:50 +000088 public BundleDependency setInstanceBound(boolean isInstanceBound) {
89 setIsInstanceBound(isInstanceBound);
90 return this;
91 }
92
Marcel Offermansb196d722009-11-26 17:12:12 +000093 public synchronized boolean isAvailable() {
94 return m_isAvailable;
95 }
96
Marcel Offermansb196d722009-11-26 17:12:12 +000097 public void start(DependencyService service) {
Marcel Offermanscae61362009-12-01 08:37:10 +000098 boolean needsStarting = false;
Marcel Offermanse14b3422009-11-25 23:04:32 +000099 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000100 m_services.add(service);
101 if (!m_isStarted) {
102 m_tracker = new BundleTracker(m_context, m_stateMask, this);
103 m_isStarted = true;
104 needsStarting = true;
105 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000106 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000107 if (needsStarting) {
108 m_tracker.open();
109 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000110 }
111
112 public void stop(DependencyService service) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000113 boolean needsStopping = false;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000114 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000115 if (m_services.size() == 1 && m_services.contains(service)) {
116 m_isStarted = false;
117 needsStopping = true;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000118 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000119 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000120 if (needsStopping) {
121 m_tracker.close();
122 m_tracker = null;
123 m_services.remove(service);
124 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000125 }
126
127 public String getName() {
Marcel Offermanscae61362009-12-01 08:37:10 +0000128 StringBuilder sb = new StringBuilder();
Marcel Offermansb1959f42010-07-01 12:23:51 +0000129 if ((m_stateMask & Bundle.ACTIVE) != 0) {
130 sb.append("active ");
Marcel Offermans001db052009-12-08 08:58:40 +0000131 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000132 if ((m_stateMask & Bundle.INSTALLED) != 0) {
133 sb.append("installed ");
134 }
135 if ((m_stateMask & Bundle.RESOLVED) != 0) {
136 sb.append("resolved ");
137 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000138 if (m_filter != null) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000139 sb.append(m_filter.toString());
140 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000141 if (m_bundleId != -1) {
142 sb.append("bundle.id=" + m_bundleId);
143 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000144 return sb.toString();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000145 }
146
147 public int getState() {
Marcel Offermansb1959f42010-07-01 12:23:51 +0000148 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000149 }
150
151 public String getType() {
Marcel Offermanscae61362009-12-01 08:37:10 +0000152 return "bundle";
Marcel Offermanse14b3422009-11-25 23:04:32 +0000153 }
154
155 public Object addingBundle(Bundle bundle, BundleEvent event) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000156 // if we don't like a bundle, we could reject it here by returning null
Marcel Offermans001db052009-12-08 08:58:40 +0000157 long bundleId = bundle.getBundleId();
158 if (m_bundleId >= 0 && m_bundleId != bundleId) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000159 return null;
160 }
161 Filter filter = m_filter;
162 if (filter != null) {
163 Dictionary headers = bundle.getHeaders();
164 if (!m_filter.match(headers)) {
165 return null;
166 }
167 }
168 return bundle;
169 }
170
171 public void addedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000172 boolean makeAvailable = makeAvailable();
173 Object[] services = m_services.toArray();
174 for (int i = 0; i < services.length; i++) {
175 DependencyService ds = (DependencyService) services[i];
176 if (makeAvailable) {
177 ds.dependencyAvailable(this);
178 if (!isRequired()) {
179 invokeAdded(ds, bundle);
180 }
181 }
182 else {
183 ds.dependencyChanged(this);
184 invokeAdded(ds, bundle);
185 }
186 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000187 }
188
189 public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000190 Object[] services = m_services.toArray();
191 for (int i = 0; i < services.length; i++) {
192 DependencyService ds = (DependencyService) services[i];
193 ds.dependencyChanged(this);
194 if (ds.isRegistered()) {
195 invokeChanged(ds, bundle);
196 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000197 }
198 }
199
200 public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000201 boolean makeUnavailable = makeUnavailable();
202 Object[] services = m_services.toArray();
203 for (int i = 0; i < services.length; i++) {
204 DependencyService ds = (DependencyService) services[i];
205 if (makeUnavailable) {
206 ds.dependencyUnavailable(this);
207 if (!isRequired()) {
208 invokeRemoved(ds, bundle);
209 }
Marcel Offermans9f3c5f42009-11-26 11:17:36 +0000210 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000211 else {
212 ds.dependencyChanged(this);
213 invokeRemoved(ds, bundle);
214 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000215 }
216 }
217
218 private synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000219 if (!isAvailable()) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000220 m_isAvailable = true;
221 return true;
222 }
223 return false;
224 }
225
226 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000227 if ((isAvailable()) && (m_tracker.getTrackingCount() == 0)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000228 m_isAvailable = false;
229 return true;
230 }
231 return false;
232 }
233
Marcel Offermanscae61362009-12-01 08:37:10 +0000234 public void invokeAdded(DependencyService dependencyService, Bundle service) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000235 invoke(dependencyService, service, m_callbackAdded);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000236 }
237
Marcel Offermanscae61362009-12-01 08:37:10 +0000238 public void invokeChanged(DependencyService dependencyService, Bundle service) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000239 invoke(dependencyService, service, m_callbackChanged);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000240 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000241
Marcel Offermanscae61362009-12-01 08:37:10 +0000242 public void invokeRemoved(DependencyService dependencyService, Bundle service) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000243 invoke(dependencyService, service, m_callbackRemoved);
244 }
245
246 public void invoke(DependencyService dependencyService, Bundle service, String name) {
247 if (name != null) {
248 dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
Marcel Offermansb196d722009-11-26 17:12:12 +0000249 new Class[][] {{Bundle.class}, {Object.class}, {}},
250 new Object[][] {{service}, {service}, {}}
251 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000252 }
253 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000254
255 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000256 if (m_callbackInstance == null) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000257 return dependencyService.getCompositionInstances();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000258 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000259 else {
260 return new Object[] { m_callbackInstance };
261 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000262 }
Marcel Offermanscae61362009-12-01 08:37:10 +0000263
Marcel Offermanse14b3422009-11-25 23:04:32 +0000264 /**
265 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
266 * dependency is added or removed. When you specify callbacks, the auto configuration
267 * feature is automatically turned off, because we're assuming you don't need it in this
268 * case.
269 *
270 * @param added the method to call when a service was added
271 * @param removed the method to call when a service was removed
272 * @return this service dependency
273 */
274 public synchronized BundleDependency setCallbacks(String added, String removed) {
275 return setCallbacks(null, added, null, removed);
276 }
277
278 /**
279 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
280 * dependency is added, changed or removed. When you specify callbacks, the auto
281 * configuration feature is automatically turned off, because we're assuming you don't
282 * need it in this case.
283 *
284 * @param added the method to call when a service was added
285 * @param changed the method to call when a service was changed
286 * @param removed the method to call when a service was removed
287 * @return this service dependency
288 */
289 public synchronized BundleDependency setCallbacks(String added, String changed, String removed) {
290 return setCallbacks(null, added, changed, removed);
291 }
292
293 /**
294 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
295 * dependency is added or removed. They are called on the instance you provide. When you
296 * specify callbacks, the auto configuration feature is automatically turned off, because
297 * we're assuming you don't need it in this case.
298 *
299 * @param instance the instance to call the callbacks on
300 * @param added the method to call when a service was added
301 * @param removed the method to call when a service was removed
302 * @return this service dependency
303 */
304 public synchronized BundleDependency setCallbacks(Object instance, String added, String removed) {
305 return setCallbacks(instance, added, null, removed);
306 }
307
308 /**
309 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
310 * dependency is added, changed or removed. They are called on the instance you provide. When you
311 * specify callbacks, the auto configuration feature is automatically turned off, because
312 * we're assuming you don't need it in this case.
313 *
314 * @param instance the instance to call the callbacks on
315 * @param added the method to call when a service was added
316 * @param changed the method to call when a service was changed
317 * @param removed the method to call when a service was removed
318 * @return this service dependency
319 */
320 public synchronized BundleDependency setCallbacks(Object instance, String added, String changed, String removed) {
321 ensureNotActive();
322 // if at least one valid callback is specified, we turn off auto configuration
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000323 if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000324 setAutoConfig(false);
325 }
326 m_callbackInstance = instance;
327 m_callbackAdded = added;
328 m_callbackChanged = changed;
329 m_callbackRemoved = removed;
330 return this;
331 }
332
333 private void ensureNotActive() {
334 if (m_tracker != null) {
335 throw new IllegalStateException("Cannot modify state while active.");
336 }
337 }
338 public synchronized BundleDependency setAutoConfig(boolean autoConfig) {
339 ensureNotActive();
340 m_autoConfig = autoConfig;
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000341 m_autoConfigInvoked = true;
342 return this;
343 }
344
345 public synchronized BundleDependency setAutoConfig(String instanceName) {
346 ensureNotActive();
347 m_autoConfig = (instanceName != null);
348 m_autoConfigInstance = instanceName;
349 m_autoConfigInvoked = true;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000350 return this;
351 }
352
353 public synchronized BundleDependency setRequired(boolean required) {
354 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000355 setIsRequired(required);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000356 return this;
357 }
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000358
359 public BundleDependency setPropagate(boolean propagate) {
360 ensureNotActive();
361 m_propagate = propagate;
362 return this;
363 }
364
Marcel Offermanse14b3422009-11-25 23:04:32 +0000365 public BundleDependency setBundle(Bundle bundle) {
366 m_bundleId = bundle.getBundleId();
367 return this;
368 }
369
370 public BundleDependency setFilter(String filter) throws IllegalArgumentException {
371 if (filter != null) {
372 try {
373 m_filter = m_context.createFilter(filter);
374 }
375 catch (InvalidSyntaxException e) {
376 throw new IllegalArgumentException(e.getMessage());
377 }
378 }
379 return this;
380 }
381
382 public BundleDependency setStateMask(int mask) {
383 m_stateMask = mask;
384 return this;
385 }
386
387 public synchronized boolean isAutoConfig() {
388 return m_autoConfig;
389 }
390
391 public Bundle getBundle() {
392 Bundle[] bundles = m_tracker.getBundles();
393 if (bundles != null && bundles.length > 0) {
394 return bundles[0];
395 }
396 return null;
397 }
Marcel Offermans001db052009-12-08 08:58:40 +0000398
399 public Object getAutoConfigInstance() {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000400 return lookupBundle();
Marcel Offermans001db052009-12-08 08:58:40 +0000401 }
402
Marcel Offermansad760672010-03-03 15:30:01 +0000403 public Bundle lookupBundle() {
404 Bundle service = null;
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000405 if (m_isStarted) {
406 service = getBundle();
407 }
408 else {
409 Bundle[] bundles = m_context.getBundles();
410 for (int i = 0; i < bundles.length; i++) {
411 if ((bundles[i].getState() & m_stateMask) > 0) {
Marcel Offermans9ace4f42010-02-16 16:25:38 +0000412 Filter filter = m_filter;
413 if (filter == null) {
414 service = bundles[i];
415 break;
416 }
417 else if (filter.match(bundles[i].getHeaders())) {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000418 service = bundles[i];
419 break;
420 }
421 }
422 }
423 }
424 if (service == null && isAutoConfig()) {
425 // TODO does it make sense to add support for custom bundle impls?
426// service = getDefaultImplementation();
427 if (service == null) {
428 service = getNullObject();
429 }
430 }
431 return service;
432 }
433
Marcel Offermansad760672010-03-03 15:30:01 +0000434 private Bundle getNullObject() {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000435 if (m_nullObject == null) {
436 try {
437 m_nullObject = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Bundle.class }, new DefaultNullObject());
438 }
439 catch (Exception e) {
440 m_logger.log(Logger.LOG_ERROR, "Could not create null object for Bundle.", e);
441 }
442 }
Marcel Offermansad760672010-03-03 15:30:01 +0000443 return (Bundle) m_nullObject;
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000444 }
445
Marcel Offermans001db052009-12-08 08:58:40 +0000446 public String getAutoConfigName() {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000447 return m_autoConfigInstance;
Marcel Offermans001db052009-12-08 08:58:40 +0000448 }
449
450 public Class getAutoConfigType() {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000451 return Bundle.class;
Marcel Offermans001db052009-12-08 08:58:40 +0000452 }
453
454 public void invokeAdded(DependencyService service) {
455 // we remember these for future reference, needed for required service callbacks
Marcel Offermansad760672010-03-03 15:30:01 +0000456 m_bundleInstance = lookupBundle();
Marcel Offermans001db052009-12-08 08:58:40 +0000457 invokeAdded(service, m_bundleInstance);
458 }
459
460 public void invokeRemoved(DependencyService service) {
461 invokeRemoved(service, m_bundleInstance);
462 m_bundleInstance = null;
463 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000464
465 public Dictionary getProperties() {
466 // TODO Auto-generated method stub
467 return null;
468 }
469
470 public boolean isPropagated() {
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000471 return m_propagate;
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000472 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000473}