package com.buglabs.application;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.buglabs.util.ServiceFilterGenerator;
/**
* DO NOT USE THIS CLASS
*
* The functionality for filtering on Services w/ service properties was moved
* into the generated applications activator, combined with
* AbstractServiceTracker
*
* @author bballantine
* @deprecated Use ServiceTrackerHelper for ServiceTracker functionality instead.
*
*/
public abstract class AbstractServiceTracker2 implements ServiceTrackerCustomizer, IServiceProvider {
private BundleContext context;
private LogService logService;
private String trackerName;
private Map trackedServices;
private boolean isRunning;
private Map serviceProperties;
public AbstractServiceTracker2(BundleContext bundleContext) {
context = bundleContext;
trackedServices = new HashMap();
logService = getLogService(context);
trackerName = getTrackerName(context);
isRunning = false;
initServices();
}
/**
* Invoked when all services dependencies have been met
*
*/
public abstract void doStart();
/**
* Invoked when service dependencies are no longer met
*
*/
public abstract void doStop();
/**
* Overridable function for determining if app can start
*
*/
public boolean canStart() {
return true;
}
/**
* Implementations should add services of interest
*/
public void initServices() {
logService.log(LogService.LOG_DEBUG, trackerName + " A tracker in this bundle is tracking no services.");
}
/*
* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
public Object addingService(ServiceReference reference) {
//not a service we care about, return
// TODO - returning null might be an issue
if (!inServicePropertiesMap(reference))
return null;
Object serviceObject = trackService(reference) ? getServiceObject(reference) : null;
if (areServiceDependenciesMet() && !isRunning()) {
if (canStart())
performStart();
}
return serviceObject;
}
/**
* Called when a service is modified
*/
public void modifiedService(ServiceReference reference, Object service) {
//not a service we care about, return
if (!inServicePropertiesMap(reference))
return;
trackService(reference);
// if dependencies are met, update the trackedServices
if (areServiceDependenciesMet() && !isRunning()) {
if (canStart())
performStart();
} else if (isRunning()) {
performStop();
}
}
/**
* Called when a service is removed
*/
public void removedService(ServiceReference reference, Object service) {
//not a service we care about, return
if (!inServicePropertiesMap(reference))
return;
trackService(reference);
if (!areServiceDependenciesMet() && isRunning()) {
performStop();
}
}
/**
* Used to retrieve a list of qualified service names that we are filtering
* on.
*
* @return a list of Strings containing the fully qualified name of each
* service.
*
*/
public final List getServices() {
return new ArrayList(getServicePropertiesMap().keySet());
}
/**
* Stop the service tracker
*/
public final void stop() {
if (isRunning()) {
doStop();
setIsRunning(false);
}
}
/**
* Helps set up the serviceProperties map created to make generated code
* simpler
*
* @param serviceName
* @param properties
*/
protected final void addServiceFilters(String serviceName, String[][] properties) {
Map propMap = new HashMap();
for (int i = 0; i < properties.length; i++) {
propMap.put(properties[i][0], properties[i][1]);
}
getServicePropertiesMap().put(serviceName, propMap);
}
/**
* returns the map of services and properties that represent the service
* dependencies for this tracker the map, in pseudo-generic code, is:
* Map<String serviceName, Map<String propertyKey, String propertyVal>>
*
* @return
*/
public final Map getServicePropertiesMap() {
if (serviceProperties == null) {
serviceProperties = new HashMap();
}
return serviceProperties;
}
/**
* Decides if the service reference is for a service that matches our
* property filters. If so, it tracks it.
*
* If it doesn't satisfy our property filters, and we're already tracking
* it, then stop tracking it.
*
* @param reference
* @return
*/
private boolean trackService(ServiceReference reference) {
if (satisfiesServiceDependency(reference)) {
trackedServices.put(getServiceName(reference), getServiceObject(reference));
return true;
} else {
if (trackedServices.containsKey(getServiceName(reference)) && trackedServices.get(getServiceName(reference)).equals(getServiceObject(reference)))
trackedServices.remove(getServiceName(reference));
return false;
}
}
/**
* Helper to see if a ServiceReference satisfies one of our service
* dependencies
*
* @param reference
* @return
*/
private boolean satisfiesServiceDependency(ServiceReference reference) {
ServiceReference[] srs = getServiceReferences(getServiceName(reference), (Map) getServicePropertiesMap().get(getServiceName(reference)));
if (srs == null || srs.length < 1)
return false;
if (Arrays.asList(srs).contains(reference))
return true;
return false;
}
/**
* Check the running services against the services and their properties
* using a service filter, to decide if all the services with their
* properties match
*
* @return
*/
private boolean areServiceDependenciesMet() {
Iterator servicesItr = getServicePropertiesMap().keySet().iterator();
String service;
ServiceReference[] srs;
while (servicesItr.hasNext()) {
service = (String) servicesItr.next();
srs = getServiceReferences(service, new TreeMap((Map) getServicePropertiesMap().get(service)));
if (srs == null || srs.length < 1)
return false;
}
return true;
}
/**
* Helper to get an array of ServiceReferences based on a service name and a
* map of required service properties
*
* @param serviceName
* @param serviceProperties
* @return
*/
private ServiceReference[] getServiceReferences(String serviceName, Map serviceProperties) {
SortedMap servicesMap = new TreeMap();
servicesMap.put(serviceName, serviceProperties);
String serviceFilter = ServiceFilterGenerator.generateServiceFilter(servicesMap);
ServiceReference[] srs = null;
try {
srs = context.getServiceReferences(serviceName, serviceFilter);
} catch (InvalidSyntaxException e) {
logService.log(LogService.LOG_ERROR, e.getMessage());
}
return srs;
}
/**
* If we've called doStart() keep track that the tracker is running
*
* @param value
*/
private void setIsRunning(boolean value) {
isRunning = value;
}
/**
* As far as we know, is the tracker running?
*
* @return
*/
private boolean isRunning() {
return isRunning;
}
/**
* Helper to do the start stuff
*/
private void performStart() {
logService.log(LogService.LOG_DEBUG, trackerName + " Starting tracker, all service dependencies have been met.");
doStart();
setIsRunning(true);
}
/**
* Helper to do the stop stuff
*/
private void performStop() {
logService.log(LogService.LOG_DEBUG, trackerName + " Stopping tracker, service dependencies are no longer met.");
doStop();
setIsRunning(false);
}
/**
* return an instance of the service if we're tracking it
*/
public Object getService(Class clazz) {
return trackedServices.get(clazz);
}
/**
* Helper to determine if we care about a given ServiceReference
*
* @param reference
* @return
*/
private boolean inServicePropertiesMap(ServiceReference reference) {
return getServicePropertiesMap().containsKey(getServiceName(reference));
}
/**
* Helper to pull service name from ServiceReference
*
* @param reference
* @return
*/
private String getServiceName(ServiceReference reference) {
String[] objClassName = (String[]) reference.getProperty(Constants.OBJECTCLASS);
return objClassName[0];
}
/**
* Helper to get the service object from a service reference
*
* @param reference
* @return
*/
private Object getServiceObject(ServiceReference reference) {
return context.getService(reference);
}
/**
* Assume that a log service is always available.
*
* @param context
* @return
*/
private LogService getLogService(BundleContext context) {
ServiceReference sr = context.getServiceReference(LogService.class.getName());
return (LogService) context.getService(sr);
}
/**
* Helper to get the tracker name
*
* @param context2
* @return
*/
private String getTrackerName(BundleContext context2) {
String name = (String) context2.getBundle().getHeaders().get("Bundle-SymbolicName");
if (name == null) {
name = context.getBundle().getLocation();
}
name = name + " [" + this.getClass().toString() + "]";
return name;
}
}