blob: b7faaabc346e78a4c968ddb15e4b187ef6fd47f9 [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 Rope8c339f2009-12-04 22:51:51 +000019package org.apache.felix.dm.impl.dependencies;
Marcel Offermanse14b3422009-11-25 23:04:32 +000020
Marcel Offermansa8c213f2010-07-02 17:27:20 +000021import java.net.URL;
Marcel Offermans203bdad2009-12-04 09:23:04 +000022import java.util.ArrayList;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000023import java.util.Dictionary;
Marcel Offermans203bdad2009-12-04 09:23:04 +000024import java.util.List;
Marcel Offermanse14b3422009-11-25 23:04:32 +000025import java.util.Properties;
26
Marcel Offermansb1959f42010-07-01 12:23:51 +000027import org.apache.felix.dm.dependencies.Dependency;
Pierre De Rope8c339f2009-12-04 22:51:51 +000028import org.apache.felix.dm.dependencies.ResourceDependency;
29import org.apache.felix.dm.impl.Logger;
Marcel Offermansb1959f42010-07-01 12:23:51 +000030import org.apache.felix.dm.management.ServiceComponentDependency;
Pierre De Rope8c339f2009-12-04 22:51:51 +000031import org.apache.felix.dm.resources.ResourceHandler;
Marcel Offermansea89b862010-06-24 13:14:43 +000032import org.apache.felix.dm.service.Service;
Marcel Offermanse14b3422009-11-25 23:04:32 +000033import org.osgi.framework.BundleContext;
34import org.osgi.framework.ServiceRegistration;
35
Marcel Offermansb1959f42010-07-01 12:23:51 +000036public class ResourceDependencyImpl extends DependencyBase implements ResourceDependency, ResourceHandler, DependencyActivation, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000037 private volatile BundleContext m_context;
38 private volatile ServiceRegistration m_registration;
Marcel Offermansb99e7e42009-12-10 09:11:32 +000039// private long m_resourceCounter;
Marcel Offermanse14b3422009-11-25 23:04:32 +000040
41 private Object m_callbackInstance;
42 private String m_callbackAdded;
43 private String m_callbackChanged;
44 private String m_callbackRemoved;
45 private boolean m_autoConfig;
Marcel Offermanse14b3422009-11-25 23:04:32 +000046 private String m_autoConfigInstance;
Marcel Offermans203bdad2009-12-04 09:23:04 +000047 protected List m_services = new ArrayList();
Marcel Offermanse14b3422009-11-25 23:04:32 +000048 private String m_resourceFilter;
Marcel Offermansa8c213f2010-07-02 17:27:20 +000049 private URL m_trackedResource;
Marcel Offermans203bdad2009-12-04 09:23:04 +000050 private boolean m_isStarted;
Marcel Offermansb99e7e42009-12-10 09:11:32 +000051 private List m_resources = new ArrayList();
Marcel Offermansa8c213f2010-07-02 17:27:20 +000052 private URL m_resourceInstance;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000053 private boolean m_propagate;
Marcel Offermanse14b3422009-11-25 23:04:32 +000054
Pierre De Rope8c339f2009-12-04 22:51:51 +000055 public ResourceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermans61a81142010-04-02 15:16:50 +000056 super(logger);
Marcel Offermanse14b3422009-11-25 23:04:32 +000057 m_context = context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000058 m_autoConfig = true;
59 }
60
Marcel Offermansb1959f42010-07-01 12:23:51 +000061 public ResourceDependencyImpl(ResourceDependencyImpl prototype) {
62 super(prototype);
63 m_context = prototype.m_context;
64 m_autoConfig = prototype.m_autoConfig;
65 m_callbackInstance = prototype.m_callbackInstance;
66 m_callbackAdded = prototype.m_callbackAdded;
67 m_callbackChanged = prototype.m_callbackChanged;
68 m_callbackRemoved = prototype.m_callbackRemoved;
69 m_autoConfigInstance = prototype.m_autoConfigInstance;
70 m_resourceFilter = prototype.m_resourceFilter;
71 m_trackedResource = prototype.m_trackedResource;
72 m_propagate = prototype.m_propagate;
73 }
74
75 public Dependency createCopy() {
76 return new ResourceDependencyImpl(this);
77 }
78
Marcel Offermanse14b3422009-11-25 23:04:32 +000079 public synchronized boolean isAvailable() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +000080 return m_resources.size() > 0;
Marcel Offermanse14b3422009-11-25 23:04:32 +000081 }
82
Marcel Offermanse14b3422009-11-25 23:04:32 +000083 public void start(DependencyService service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +000084 boolean needsStarting = false;
85 synchronized (this) {
86 m_services.add(service);
87 if (!m_isStarted) {
88 m_isStarted = true;
89 needsStarting = true;
90 }
91 }
92 if (needsStarting) {
Marcel Offermans266eee52009-12-08 10:56:09 +000093 Properties props = null;
94 if (m_resourceFilter != null) {
95 props = new Properties();
Marcel Offermansa8c213f2010-07-02 17:27:20 +000096 props.setProperty(ResourceHandler.FILTER, m_resourceFilter);
Marcel Offermans266eee52009-12-08 10:56:09 +000097 }
Marcel Offermans203bdad2009-12-04 09:23:04 +000098 m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
99 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000100 }
101
102 public void stop(DependencyService service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000103 boolean needsStopping = false;
104 synchronized (this) {
105 if (m_services.size() == 1 && m_services.contains(service)) {
106 m_isStarted = false;
107 needsStopping = true;
108 m_services.remove(service);
109 }
110 }
111 if (needsStopping) {
112 m_registration.unregister();
113 m_registration = null;
114 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000115 }
116
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000117 public void added(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000118 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
119 long counter;
120 Object[] services;
121 synchronized (this) {
122 m_resources.add(resource);
123 counter = m_resources.size();
124 services = m_services.toArray();
125 }
126 for (int i = 0; i < services.length; i++) {
127 DependencyService ds = (DependencyService) services[i];
128 if (counter == 1) {
129 ds.dependencyAvailable(this);
130 if (!isRequired()) {
131 invokeAdded(ds, resource);
132 }
133 }
134 else {
135 ds.dependencyChanged(this);
Marcel Offermans203bdad2009-12-04 09:23:04 +0000136 invokeAdded(ds, resource);
137 }
138 }
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000139 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000140 }
141
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000142 public void changed(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000143 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
144 Object[] services;
145 synchronized (this) {
146 services = m_services.toArray();
147 }
148 for (int i = 0; i < services.length; i++) {
149 DependencyService ds = (DependencyService) services[i];
150 invokeChanged(ds, resource);
151 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000152 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000153 }
154
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000155 public void removed(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000156 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
157 long counter;
158 Object[] services;
159 synchronized (this) {
160 m_resources.remove(resource);
161 counter = m_resources.size();
162 services = m_services.toArray();
163 }
164 for (int i = 0; i < services.length; i++) {
165 DependencyService ds = (DependencyService) services[i];
166 if (counter == 0) {
167 ds.dependencyUnavailable(this);
168 if (!isRequired()) {
169 invokeRemoved(ds, resource);
170 }
171 }
172 else {
173 ds.dependencyChanged(this);
Marcel Offermans203bdad2009-12-04 09:23:04 +0000174 invokeRemoved(ds, resource);
175 }
176 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000177 }
178 }
179
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000180 public void invokeAdded(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000181 invoke(ds, serviceInstance, m_callbackAdded);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000182 }
183
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000184 public void invokeChanged(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000185 invoke(ds, serviceInstance, m_callbackChanged);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000186 }
187
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000188 public void invokeRemoved(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000189 invoke(ds, serviceInstance, m_callbackRemoved);
190 }
191
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000192 private void invoke(DependencyService ds, URL serviceInstance, String name) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000193 if (name != null) {
194 ds.invokeCallbackMethod(getCallbackInstances(ds), name,
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000195 new Class[][] {{ Service.class, URL.class }, { Service.class, Object.class }, { Service.class }, { URL.class }, { Object.class }, {}},
Marcel Offermansea89b862010-06-24 13:14:43 +0000196 new Object[][] {{ ds.getServiceInterface(), serviceInstance }, { ds.getServiceInterface(), serviceInstance }, { ds.getServiceInterface() }, { serviceInstance }, { serviceInstance }, {}}
Marcel Offermans61a81142010-04-02 15:16:50 +0000197 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000198 }
199 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000200
Marcel Offermanse14b3422009-11-25 23:04:32 +0000201 /**
202 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
203 * dependency is added or removed. When you specify callbacks, the auto configuration
204 * feature is automatically turned off, because we're assuming you don't need it in this
205 * case.
206 *
207 * @param added the method to call when a service was added
208 * @param removed the method to call when a service was removed
209 * @return this service dependency
210 */
211 public synchronized ResourceDependency setCallbacks(String added, String removed) {
212 return setCallbacks(null, added, null, removed);
213 }
214
215 /**
216 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
217 * dependency is added, changed or removed. When you specify callbacks, the auto
218 * configuration feature is automatically turned off, because we're assuming you don't
219 * need it in this case.
220 *
221 * @param added the method to call when a service was added
222 * @param changed the method to call when a service was changed
223 * @param removed the method to call when a service was removed
224 * @return this service dependency
225 */
226 public synchronized ResourceDependency setCallbacks(String added, String changed, String removed) {
227 return setCallbacks(null, added, changed, removed);
228 }
229
230 /**
231 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
232 * dependency is added or removed. They are called on the instance you provide. When you
233 * specify callbacks, the auto configuration feature is automatically turned off, because
234 * we're assuming you don't need it in this case.
235 *
236 * @param instance the instance to call the callbacks on
237 * @param added the method to call when a service was added
238 * @param removed the method to call when a service was removed
239 * @return this service dependency
240 */
241 public synchronized ResourceDependency setCallbacks(Object instance, String added, String removed) {
242 return setCallbacks(instance, added, null, removed);
243 }
244
245 /**
246 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
247 * dependency is added, changed or removed. They are called on the instance you provide. When you
248 * specify callbacks, the auto configuration feature is automatically turned off, because
249 * we're assuming you don't need it in this case.
250 *
251 * @param instance the instance to call the callbacks on
252 * @param added the method to call when a service was added
253 * @param changed the method to call when a service was changed
254 * @param removed the method to call when a service was removed
255 * @return this service dependency
256 */
257 public synchronized ResourceDependency setCallbacks(Object instance, String added, String changed, String removed) {
258 ensureNotActive();
259 // if at least one valid callback is specified, we turn off auto configuration
260 if (added != null || removed != null || changed != null) {
261 setAutoConfig(false);
262 }
263 m_callbackInstance = instance;
264 m_callbackAdded = added;
265 m_callbackChanged = changed;
266 m_callbackRemoved = removed;
267 return this;
268 }
269
270 private void ensureNotActive() {
271 if (m_registration != null) {
272 throw new IllegalStateException("Cannot modify state while active.");
273 }
274 }
275
276 /**
277 * Sets auto configuration for this service. Auto configuration allows the
278 * dependency to fill in any attributes in the service implementation that
279 * are of the same type as this dependency. Default is on.
280 *
281 * @param autoConfig the value of auto config
282 * @return this service dependency
283 */
284 public synchronized ResourceDependency setAutoConfig(boolean autoConfig) {
285 ensureNotActive();
286 m_autoConfig = autoConfig;
287 return this;
288 }
289
290 /**
291 * Sets auto configuration for this service. Auto configuration allows the
292 * dependency to fill in the attribute in the service implementation that
293 * has the same type and instance name.
294 *
295 * @param instanceName the name of attribute to auto config
296 * @return this service dependency
297 */
298 public synchronized ResourceDependency setAutoConfig(String instanceName) {
299 ensureNotActive();
300 m_autoConfig = (instanceName != null);
301 m_autoConfigInstance = instanceName;
302 return this;
303 }
304
Marcel Offermans61a81142010-04-02 15:16:50 +0000305// private void invokeCallbackMethod(Object[] instances, String methodName, Object service) {
306// for (int i = 0; i < instances.length; i++) {
307// try {
308// invokeCallbackMethod(instances[i], methodName, service);
309// }
310// catch (NoSuchMethodException e) {
311// m_logger.log(Logger.LOG_DEBUG, "Method '" + methodName + "' does not exist on " + instances[i] + ". Callback skipped.");
312// }
313// }
314// }
315//
316// private void invokeCallbackMethod(Object instance, String methodName, Object service) throws NoSuchMethodException {
317// Class currentClazz = instance.getClass();
318// boolean done = false;
319// while (!done && currentClazz != null) {
320// done = invokeMethod(instance, currentClazz, methodName,
321// new Class[][] {{Resource.class}, {Object.class}, {}},
322// new Object[][] {{service}, {service}, {}},
323// false);
324// if (!done) {
325// currentClazz = currentClazz.getSuperclass();
326// }
327// }
328// if (!done && currentClazz == null) {
329// throw new NoSuchMethodException(methodName);
330// }
331// }
332//
333// private boolean invokeMethod(Object object, Class clazz, String name, Class[][] signatures, Object[][] parameters, boolean isSuper) {
334// Method m = null;
335// for (int i = 0; i < signatures.length; i++) {
336// Class[] signature = signatures[i];
337// try {
338// m = clazz.getDeclaredMethod(name, signature);
339// if (!(isSuper && Modifier.isPrivate(m.getModifiers()))) {
340// m.setAccessible(true);
341// try {
342// m.invoke(object, parameters[i]);
343// }
344// catch (InvocationTargetException e) {
345// m_logger.log(Logger.LOG_ERROR, "Exception while invoking method " + m + ".", e);
346// }
347// // we did find and invoke the method, so we return true
348// return true;
349// }
350// }
351// catch (NoSuchMethodException e) {
352// // ignore this and keep looking
353// }
354// catch (Exception e) {
355// // could not even try to invoke the method
356// m_logger.log(Logger.LOG_ERROR, "Exception while trying to invoke method " + m + ".", e);
357// }
358// }
359// return false;
360// }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000361
362 private synchronized Object[] getCallbackInstances(DependencyService ds) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000363 if (m_callbackInstance == null) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000364 return ds.getCompositionInstances();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000365 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000366 else {
367 return new Object[] { m_callbackInstance };
368 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000369 }
370
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000371 public ResourceDependency setResource(URL resource) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000372 m_trackedResource = resource;
373 return this;
374 }
375
376 public synchronized ResourceDependency setRequired(boolean required) {
377 ensureNotActive();
Marcel Offermans61a81142010-04-02 15:16:50 +0000378 setIsRequired(required);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000379 return this;
380 }
381
382 public ResourceDependency setFilter(String resourceFilter) {
Marcel Offermans001db052009-12-08 08:58:40 +0000383 ensureNotActive();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000384 m_resourceFilter = resourceFilter;
385 return this;
386 }
387 public synchronized boolean isAutoConfig() {
388 return m_autoConfig;
389 }
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000390
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000391 public URL getResource() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000392 return lookupResource();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000393 }
Marcel Offermans001db052009-12-08 08:58:40 +0000394
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000395 private URL lookupResource() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000396 try {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000397 return (URL) m_resources.get(0);
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000398 }
399 catch (IndexOutOfBoundsException e) {
400 return null;
401 }
402 }
403
Marcel Offermans001db052009-12-08 08:58:40 +0000404 public Object getAutoConfigInstance() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000405 return lookupResource();
Marcel Offermans001db052009-12-08 08:58:40 +0000406 }
407
408 public String getAutoConfigName() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000409 return m_autoConfigInstance;
Marcel Offermans001db052009-12-08 08:58:40 +0000410 }
411
412 public Class getAutoConfigType() {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000413 return URL.class;
Marcel Offermans001db052009-12-08 08:58:40 +0000414 }
415
416 public void invokeAdded(DependencyService service) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000417 // we remember these for future reference, needed for required callbacks
418 m_resourceInstance = lookupResource();
419 invokeAdded(service, m_resourceInstance);
Marcel Offermans001db052009-12-08 08:58:40 +0000420 }
421
422 public void invokeRemoved(DependencyService service) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000423 invokeRemoved(service, m_resourceInstance);
424 m_resourceInstance = null;
Marcel Offermans001db052009-12-08 08:58:40 +0000425 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000426
427 public ResourceDependency setPropagate(boolean propagate) {
428 ensureNotActive();
429 m_propagate = propagate;
430 return this;
431 }
432
433 public Dictionary getProperties() {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000434 URL resource = lookupResource();
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000435 if (resource != null) {
436 Properties props = new Properties();
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000437 props.setProperty(ResourceHandler.HOST, resource.getHost());
438 props.setProperty(ResourceHandler.PATH, resource.getPath());
439 props.setProperty(ResourceHandler.PROTOCOL, resource.getProtocol());
440 props.setProperty(ResourceHandler.PORT, Integer.toString(resource.getPort()));
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000441 return props;
442 }
443 else {
444 throw new IllegalStateException("cannot find resource");
445 }
446 }
447
448 public boolean isPropagated() {
449 return m_propagate;
450 }
Marcel Offermans61a81142010-04-02 15:16:50 +0000451
452 public ResourceDependency setInstanceBound(boolean isInstanceBound) {
453 setIsInstanceBound(isInstanceBound);
454 return this;
455 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000456
457 public String getName() {
458 StringBuilder sb = new StringBuilder();
459 if (m_resourceFilter != null) {
460 sb.append(m_resourceFilter);
461 }
462 if (m_trackedResource != null) {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000463 sb.append(m_trackedResource.toString());
Marcel Offermansb1959f42010-07-01 12:23:51 +0000464 }
465 return sb.toString();
466 }
467
468 public int getState() {
469 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
470 }
471
472 public String getType() {
473 return "resource";
474 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000475}