blob: d074404e5b1fff883804ca867a61037621c805b9 [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 Offermans26081d32010-07-12 12:43:42 +000021import java.lang.reflect.InvocationTargetException;
Marcel Offermansa8c213f2010-07-02 17:27:20 +000022import java.net.URL;
Marcel Offermans203bdad2009-12-04 09:23:04 +000023import java.util.ArrayList;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000024import java.util.Dictionary;
Marcel Offermans203bdad2009-12-04 09:23:04 +000025import java.util.List;
Marcel Offermanse14b3422009-11-25 23:04:32 +000026import java.util.Properties;
27
Marcel Offermans8b93efa2010-07-02 18:27:21 +000028import org.apache.felix.dm.Dependency;
Marcel Offermans3d921212010-08-09 13:37:02 +000029import org.apache.felix.dm.DependencyActivation;
30import org.apache.felix.dm.DependencyService;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000031import org.apache.felix.dm.ResourceDependency;
32import org.apache.felix.dm.ResourceHandler;
33import org.apache.felix.dm.Service;
34import org.apache.felix.dm.ServiceComponentDependency;
Marcel Offermans26081d32010-07-12 12:43:42 +000035import org.apache.felix.dm.impl.InvocationUtil;
Pierre De Rope8c339f2009-12-04 22:51:51 +000036import org.apache.felix.dm.impl.Logger;
Marcel Offermanse14b3422009-11-25 23:04:32 +000037import org.osgi.framework.BundleContext;
38import org.osgi.framework.ServiceRegistration;
Marcel Offermans26081d32010-07-12 12:43:42 +000039import org.osgi.service.log.LogService;
Marcel Offermanse14b3422009-11-25 23:04:32 +000040
Marcel Offermansb1959f42010-07-01 12:23:51 +000041public class ResourceDependencyImpl extends DependencyBase implements ResourceDependency, ResourceHandler, DependencyActivation, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000042 private volatile BundleContext m_context;
43 private volatile ServiceRegistration m_registration;
Marcel Offermansb99e7e42009-12-10 09:11:32 +000044// private long m_resourceCounter;
Marcel Offermanse14b3422009-11-25 23:04:32 +000045
46 private Object m_callbackInstance;
47 private String m_callbackAdded;
48 private String m_callbackChanged;
49 private String m_callbackRemoved;
50 private boolean m_autoConfig;
Marcel Offermanse14b3422009-11-25 23:04:32 +000051 private String m_autoConfigInstance;
Marcel Offermans203bdad2009-12-04 09:23:04 +000052 protected List m_services = new ArrayList();
Marcel Offermanse14b3422009-11-25 23:04:32 +000053 private String m_resourceFilter;
Marcel Offermansa8c213f2010-07-02 17:27:20 +000054 private URL m_trackedResource;
Marcel Offermans203bdad2009-12-04 09:23:04 +000055 private boolean m_isStarted;
Marcel Offermansb99e7e42009-12-10 09:11:32 +000056 private List m_resources = new ArrayList();
Marcel Offermansa8c213f2010-07-02 17:27:20 +000057 private URL m_resourceInstance;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000058 private boolean m_propagate;
Marcel Offermans26081d32010-07-12 12:43:42 +000059 private Object m_propagateCallbackInstance;
60 private String m_propagateCallbackMethod;
Marcel Offermanse14b3422009-11-25 23:04:32 +000061
Pierre De Rope8c339f2009-12-04 22:51:51 +000062 public ResourceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermans61a81142010-04-02 15:16:50 +000063 super(logger);
Marcel Offermanse14b3422009-11-25 23:04:32 +000064 m_context = context;
Marcel Offermanse14b3422009-11-25 23:04:32 +000065 m_autoConfig = true;
66 }
67
Marcel Offermansb1959f42010-07-01 12:23:51 +000068 public ResourceDependencyImpl(ResourceDependencyImpl prototype) {
69 super(prototype);
70 m_context = prototype.m_context;
71 m_autoConfig = prototype.m_autoConfig;
72 m_callbackInstance = prototype.m_callbackInstance;
73 m_callbackAdded = prototype.m_callbackAdded;
74 m_callbackChanged = prototype.m_callbackChanged;
75 m_callbackRemoved = prototype.m_callbackRemoved;
76 m_autoConfigInstance = prototype.m_autoConfigInstance;
77 m_resourceFilter = prototype.m_resourceFilter;
78 m_trackedResource = prototype.m_trackedResource;
79 m_propagate = prototype.m_propagate;
80 }
81
82 public Dependency createCopy() {
83 return new ResourceDependencyImpl(this);
84 }
85
Marcel Offermanse14b3422009-11-25 23:04:32 +000086 public synchronized boolean isAvailable() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +000087 return m_resources.size() > 0;
Marcel Offermanse14b3422009-11-25 23:04:32 +000088 }
89
Marcel Offermanse14b3422009-11-25 23:04:32 +000090 public void start(DependencyService service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +000091 boolean needsStarting = false;
92 synchronized (this) {
93 m_services.add(service);
94 if (!m_isStarted) {
95 m_isStarted = true;
96 needsStarting = true;
97 }
98 }
99 if (needsStarting) {
Marcel Offermans3d921212010-08-09 13:37:02 +0000100 Dictionary props = null;
101 if (m_trackedResource != null) {
102 props = new Properties();
103 props.put(ResourceHandler.URL, m_trackedResource);
104 }
105 else if (m_resourceFilter != null) {
Marcel Offermans266eee52009-12-08 10:56:09 +0000106 props = new Properties();
Marcel Offermans3d921212010-08-09 13:37:02 +0000107 props.put(ResourceHandler.FILTER, m_resourceFilter);
Marcel Offermans266eee52009-12-08 10:56:09 +0000108 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000109 m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
110 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000111 }
112
113 public void stop(DependencyService service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000114 boolean needsStopping = false;
115 synchronized (this) {
116 if (m_services.size() == 1 && m_services.contains(service)) {
117 m_isStarted = false;
118 needsStopping = true;
119 m_services.remove(service);
120 }
121 }
122 if (needsStopping) {
123 m_registration.unregister();
124 m_registration = null;
125 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000126 }
127
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000128 public void added(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000129 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
130 long counter;
131 Object[] services;
132 synchronized (this) {
133 m_resources.add(resource);
134 counter = m_resources.size();
135 services = m_services.toArray();
136 }
137 for (int i = 0; i < services.length; i++) {
138 DependencyService ds = (DependencyService) services[i];
139 if (counter == 1) {
140 ds.dependencyAvailable(this);
141 if (!isRequired()) {
142 invokeAdded(ds, resource);
143 }
144 }
145 else {
146 ds.dependencyChanged(this);
Marcel Offermans203bdad2009-12-04 09:23:04 +0000147 invokeAdded(ds, resource);
148 }
149 }
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000150 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000151 }
152
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000153 public void changed(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000154 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
155 Object[] services;
156 synchronized (this) {
157 services = m_services.toArray();
158 }
159 for (int i = 0; i < services.length; i++) {
160 DependencyService ds = (DependencyService) services[i];
161 invokeChanged(ds, resource);
162 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000163 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000164 }
165
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000166 public void removed(URL resource) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000167 if (m_trackedResource == null || m_trackedResource.equals(resource)) {
168 long counter;
169 Object[] services;
170 synchronized (this) {
171 m_resources.remove(resource);
172 counter = m_resources.size();
173 services = m_services.toArray();
174 }
175 for (int i = 0; i < services.length; i++) {
176 DependencyService ds = (DependencyService) services[i];
177 if (counter == 0) {
178 ds.dependencyUnavailable(this);
179 if (!isRequired()) {
180 invokeRemoved(ds, resource);
181 }
182 }
183 else {
184 ds.dependencyChanged(this);
Marcel Offermans203bdad2009-12-04 09:23:04 +0000185 invokeRemoved(ds, resource);
186 }
187 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000188 }
189 }
190
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000191 public void invokeAdded(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000192 invoke(ds, serviceInstance, m_callbackAdded);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000193 }
194
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000195 public void invokeChanged(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000196 invoke(ds, serviceInstance, m_callbackChanged);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000197 }
198
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000199 public void invokeRemoved(DependencyService ds, URL serviceInstance) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000200 invoke(ds, serviceInstance, m_callbackRemoved);
201 }
202
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000203 private void invoke(DependencyService ds, URL serviceInstance, String name) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000204 if (name != null) {
205 ds.invokeCallbackMethod(getCallbackInstances(ds), name,
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000206 new Class[][] {{ Service.class, URL.class }, { Service.class, Object.class }, { Service.class }, { URL.class }, { Object.class }, {}},
Marcel Offermansea89b862010-06-24 13:14:43 +0000207 new Object[][] {{ ds.getServiceInterface(), serviceInstance }, { ds.getServiceInterface(), serviceInstance }, { ds.getServiceInterface() }, { serviceInstance }, { serviceInstance }, {}}
Marcel Offermans61a81142010-04-02 15:16:50 +0000208 );
Marcel Offermanse14b3422009-11-25 23:04:32 +0000209 }
210 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000211
Marcel Offermanse14b3422009-11-25 23:04:32 +0000212 /**
213 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
214 * dependency is added or removed. When you specify callbacks, the auto configuration
215 * feature is automatically turned off, because we're assuming you don't need it in this
216 * case.
217 *
218 * @param added the method to call when a service was added
219 * @param removed the method to call when a service was removed
220 * @return this service dependency
221 */
222 public synchronized ResourceDependency setCallbacks(String added, String removed) {
223 return setCallbacks(null, added, null, removed);
224 }
225
226 /**
227 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
228 * dependency is added, changed or removed. When you specify callbacks, the auto
229 * configuration feature is automatically turned off, because we're assuming you don't
230 * need it in this case.
231 *
232 * @param added the method to call when a service was added
233 * @param changed the method to call when a service was changed
234 * @param removed the method to call when a service was removed
235 * @return this service dependency
236 */
237 public synchronized ResourceDependency setCallbacks(String added, String changed, String removed) {
238 return setCallbacks(null, added, changed, removed);
239 }
240
241 /**
242 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
243 * dependency is added or removed. They are called on the instance you provide. When you
244 * specify callbacks, the auto configuration feature is automatically turned off, because
245 * we're assuming you don't need it in this case.
246 *
247 * @param instance the instance to call the callbacks on
248 * @param added the method to call when a service was added
249 * @param removed the method to call when a service was removed
250 * @return this service dependency
251 */
252 public synchronized ResourceDependency setCallbacks(Object instance, String added, String removed) {
253 return setCallbacks(instance, added, null, removed);
254 }
255
256 /**
257 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
258 * dependency is added, changed or removed. They are called on the instance you provide. When you
259 * specify callbacks, the auto configuration feature is automatically turned off, because
260 * we're assuming you don't need it in this case.
261 *
262 * @param instance the instance to call the callbacks on
263 * @param added the method to call when a service was added
264 * @param changed the method to call when a service was changed
265 * @param removed the method to call when a service was removed
266 * @return this service dependency
267 */
268 public synchronized ResourceDependency setCallbacks(Object instance, String added, String changed, String removed) {
269 ensureNotActive();
270 // if at least one valid callback is specified, we turn off auto configuration
271 if (added != null || removed != null || changed != null) {
272 setAutoConfig(false);
273 }
274 m_callbackInstance = instance;
275 m_callbackAdded = added;
276 m_callbackChanged = changed;
277 m_callbackRemoved = removed;
278 return this;
279 }
280
281 private void ensureNotActive() {
282 if (m_registration != null) {
283 throw new IllegalStateException("Cannot modify state while active.");
284 }
285 }
286
287 /**
288 * Sets auto configuration for this service. Auto configuration allows the
289 * dependency to fill in any attributes in the service implementation that
290 * are of the same type as this dependency. Default is on.
291 *
292 * @param autoConfig the value of auto config
293 * @return this service dependency
294 */
295 public synchronized ResourceDependency setAutoConfig(boolean autoConfig) {
296 ensureNotActive();
297 m_autoConfig = autoConfig;
298 return this;
299 }
300
301 /**
302 * Sets auto configuration for this service. Auto configuration allows the
303 * dependency to fill in the attribute in the service implementation that
304 * has the same type and instance name.
305 *
306 * @param instanceName the name of attribute to auto config
307 * @return this service dependency
308 */
309 public synchronized ResourceDependency setAutoConfig(String instanceName) {
310 ensureNotActive();
311 m_autoConfig = (instanceName != null);
312 m_autoConfigInstance = instanceName;
313 return this;
314 }
315
Marcel Offermans61a81142010-04-02 15:16:50 +0000316// private void invokeCallbackMethod(Object[] instances, String methodName, Object service) {
317// for (int i = 0; i < instances.length; i++) {
318// try {
319// invokeCallbackMethod(instances[i], methodName, service);
320// }
321// catch (NoSuchMethodException e) {
322// m_logger.log(Logger.LOG_DEBUG, "Method '" + methodName + "' does not exist on " + instances[i] + ". Callback skipped.");
323// }
324// }
325// }
326//
327// private void invokeCallbackMethod(Object instance, String methodName, Object service) throws NoSuchMethodException {
328// Class currentClazz = instance.getClass();
329// boolean done = false;
330// while (!done && currentClazz != null) {
331// done = invokeMethod(instance, currentClazz, methodName,
332// new Class[][] {{Resource.class}, {Object.class}, {}},
333// new Object[][] {{service}, {service}, {}},
334// false);
335// if (!done) {
336// currentClazz = currentClazz.getSuperclass();
337// }
338// }
339// if (!done && currentClazz == null) {
340// throw new NoSuchMethodException(methodName);
341// }
342// }
343//
344// private boolean invokeMethod(Object object, Class clazz, String name, Class[][] signatures, Object[][] parameters, boolean isSuper) {
345// Method m = null;
346// for (int i = 0; i < signatures.length; i++) {
347// Class[] signature = signatures[i];
348// try {
349// m = clazz.getDeclaredMethod(name, signature);
350// if (!(isSuper && Modifier.isPrivate(m.getModifiers()))) {
351// m.setAccessible(true);
352// try {
353// m.invoke(object, parameters[i]);
354// }
355// catch (InvocationTargetException e) {
356// m_logger.log(Logger.LOG_ERROR, "Exception while invoking method " + m + ".", e);
357// }
358// // we did find and invoke the method, so we return true
359// return true;
360// }
361// }
362// catch (NoSuchMethodException e) {
363// // ignore this and keep looking
364// }
365// catch (Exception e) {
366// // could not even try to invoke the method
367// m_logger.log(Logger.LOG_ERROR, "Exception while trying to invoke method " + m + ".", e);
368// }
369// }
370// return false;
371// }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000372
373 private synchronized Object[] getCallbackInstances(DependencyService ds) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000374 if (m_callbackInstance == null) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000375 return ds.getCompositionInstances();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000376 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000377 else {
378 return new Object[] { m_callbackInstance };
379 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000380 }
381
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000382 public ResourceDependency setResource(URL resource) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000383 m_trackedResource = resource;
384 return this;
385 }
386
387 public synchronized ResourceDependency setRequired(boolean required) {
388 ensureNotActive();
Marcel Offermans61a81142010-04-02 15:16:50 +0000389 setIsRequired(required);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000390 return this;
391 }
392
393 public ResourceDependency setFilter(String resourceFilter) {
Marcel Offermans001db052009-12-08 08:58:40 +0000394 ensureNotActive();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000395 m_resourceFilter = resourceFilter;
396 return this;
397 }
398 public synchronized boolean isAutoConfig() {
399 return m_autoConfig;
400 }
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000401
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000402 public URL getResource() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000403 return lookupResource();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000404 }
Marcel Offermans001db052009-12-08 08:58:40 +0000405
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000406 private URL lookupResource() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000407 try {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000408 return (URL) m_resources.get(0);
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000409 }
410 catch (IndexOutOfBoundsException e) {
411 return null;
412 }
413 }
414
Marcel Offermans001db052009-12-08 08:58:40 +0000415 public Object getAutoConfigInstance() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000416 return lookupResource();
Marcel Offermans001db052009-12-08 08:58:40 +0000417 }
418
419 public String getAutoConfigName() {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000420 return m_autoConfigInstance;
Marcel Offermans001db052009-12-08 08:58:40 +0000421 }
422
423 public Class getAutoConfigType() {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000424 return URL.class;
Marcel Offermans001db052009-12-08 08:58:40 +0000425 }
426
427 public void invokeAdded(DependencyService service) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000428 // we remember these for future reference, needed for required callbacks
429 m_resourceInstance = lookupResource();
430 invokeAdded(service, m_resourceInstance);
Marcel Offermans001db052009-12-08 08:58:40 +0000431 }
432
433 public void invokeRemoved(DependencyService service) {
Marcel Offermansb99e7e42009-12-10 09:11:32 +0000434 invokeRemoved(service, m_resourceInstance);
435 m_resourceInstance = null;
Marcel Offermans001db052009-12-08 08:58:40 +0000436 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000437
438 public ResourceDependency setPropagate(boolean propagate) {
439 ensureNotActive();
440 m_propagate = propagate;
441 return this;
442 }
443
Marcel Offermans26081d32010-07-12 12:43:42 +0000444 public ResourceDependency setPropagate(Object instance, String method) {
445 setPropagate(instance != null && method != null);
446 m_propagateCallbackInstance = instance;
447 m_propagateCallbackMethod = method;
448 return this;
449 }
450
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000451 public Dictionary getProperties() {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000452 URL resource = lookupResource();
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000453 if (resource != null) {
Marcel Offermans26081d32010-07-12 12:43:42 +0000454 if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
455 try {
456 return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ URL.class }}, new Object[][] {{ resource }});
457 }
458 catch (InvocationTargetException e) {
459 m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
460 }
461 catch (Exception e) {
462 m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
463 }
464 throw new IllegalStateException("Could not invoke callback");
465 }
466 else {
467 Properties props = new Properties();
468 props.setProperty(ResourceHandler.HOST, resource.getHost());
469 props.setProperty(ResourceHandler.PATH, resource.getPath());
470 props.setProperty(ResourceHandler.PROTOCOL, resource.getProtocol());
471 props.setProperty(ResourceHandler.PORT, Integer.toString(resource.getPort()));
472 return props;
473 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000474 }
475 else {
476 throw new IllegalStateException("cannot find resource");
477 }
478 }
479
480 public boolean isPropagated() {
481 return m_propagate;
482 }
Marcel Offermans61a81142010-04-02 15:16:50 +0000483
484 public ResourceDependency setInstanceBound(boolean isInstanceBound) {
485 setIsInstanceBound(isInstanceBound);
486 return this;
487 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000488
489 public String getName() {
490 StringBuilder sb = new StringBuilder();
491 if (m_resourceFilter != null) {
492 sb.append(m_resourceFilter);
493 }
494 if (m_trackedResource != null) {
Marcel Offermansa8c213f2010-07-02 17:27:20 +0000495 sb.append(m_trackedResource.toString());
Marcel Offermansb1959f42010-07-01 12:23:51 +0000496 }
497 return sb.toString();
498 }
499
500 public int getState() {
501 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
502 }
503
504 public String getType() {
505 return "resource";
506 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000507}