blob: 0148cc092dadcb1c9642c31b09544e2a063c154f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2008 Cognos Incorporated, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cognos Incorporated - initial API and implementation
* IBM Corporation - bug fixes and enhancements
*******************************************************************************/
package org.eclipse.equinox.internal.cm;
import java.util.*;
import java.util.Map.Entry;
import org.osgi.framework.*;
import org.osgi.service.cm.*;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
/**
* ManagedServiceTracker tracks... ManagedServices and notifies them about related configuration changes
*/
class ManagedServiceTracker extends ServiceTracker {
final ConfigurationAdminFactory configurationAdminFactory;
private final ConfigurationStore configurationStore;
// managedServiceReferences guards both managedServices and managedServiceReferences
private final Map managedServices = new HashMap();
private final Map managedServiceReferences = new HashMap();
private final SerializedTaskQueue queue = new SerializedTaskQueue("ManagedService Update Queue"); //$NON-NLS-1$
public ManagedServiceTracker(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, BundleContext context) {
super(context, ManagedService.class.getName(), null);
this.configurationAdminFactory = configurationAdminFactory;
this.configurationStore = configurationStore;
}
protected void notifyDeleted(ConfigurationImpl config) {
config.checkLocked();
String pid = config.getPid(false);
ServiceReference reference = getManagedServiceReference(pid);
if (reference != null && config.bind(reference.getBundle()))
asynchUpdated(getManagedService(pid), null);
}
protected void notifyUpdated(ConfigurationImpl config) {
config.checkLocked();
String pid = config.getPid();
ServiceReference reference = getManagedServiceReference(pid);
if (reference != null && config.bind(reference.getBundle())) {
Dictionary properties = config.getProperties();
configurationAdminFactory.modifyConfiguration(reference, properties);
asynchUpdated(getManagedService(pid), properties);
}
}
public Object addingService(ServiceReference reference) {
String pid = (String) reference.getProperty(Constants.SERVICE_PID);
if (pid == null)
return null;
ManagedService service = (ManagedService) context.getService(reference);
if (service == null)
return null;
synchronized (configurationStore) {
add(reference, pid, service);
}
return service;
}
public void modifiedService(ServiceReference reference, Object service) {
String pid = (String) reference.getProperty(Constants.SERVICE_PID);
synchronized (configurationStore) {
if (getManagedService(pid) == service)
return;
String previousPid = getPidForManagedService(service);
remove(reference, previousPid);
addingService(reference);
}
}
public void removedService(ServiceReference reference, Object service) {
String pid = (String) reference.getProperty(Constants.SERVICE_PID);
synchronized (configurationStore) {
remove(reference, pid);
}
context.ungetService(reference);
}
private void add(ServiceReference reference, String pid, ManagedService service) {
ConfigurationImpl config = configurationStore.findConfiguration(pid);
if (config == null && trackManagedService(pid, reference, service)) {
asynchUpdated(service, null);
} else {
try {
config.lock();
if (trackManagedService(pid, reference, service)) {
if (config.getFactoryPid() != null) {
configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + pid + " should only be used by a " + ManagedServiceFactory.class.getName()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
} else if (config.isDeleted()) {
asynchUpdated(service, null);
} else if (config.bind(reference.getBundle())) {
Dictionary properties = config.getProperties();
configurationAdminFactory.modifyConfiguration(reference, properties);
asynchUpdated(service, properties);
} else {
configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + pid + " could not be bound to " + reference.getBundle().getLocation()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
}
} finally {
config.unlock();
}
}
}
private void remove(ServiceReference reference, String pid) {
ConfigurationImpl config = configurationStore.findConfiguration(pid);
if (config == null) {
untrackManagedService(pid, reference);
} else {
try {
config.lock();
untrackManagedService(pid, reference);
} finally {
config.unlock();
}
}
}
private boolean trackManagedService(String pid, ServiceReference reference, ManagedService service) {
synchronized (managedServiceReferences) {
if (managedServiceReferences.containsKey(pid)) {
String message = ManagedService.class.getName() + " already registered for " + Constants.SERVICE_PID + "=" + pid; //$NON-NLS-1$ //$NON-NLS-2$
configurationAdminFactory.log(LogService.LOG_WARNING, message);
return false;
}
managedServiceReferences.put(pid, reference);
managedServices.put(pid, service);
return true;
}
}
private void untrackManagedService(String pid, ServiceReference reference) {
synchronized (managedServiceReferences) {
managedServiceReferences.remove(pid);
managedServices.remove(pid);
}
}
private ManagedService getManagedService(String pid) {
synchronized (managedServiceReferences) {
return (ManagedService) managedServices.get(pid);
}
}
private ServiceReference getManagedServiceReference(String pid) {
synchronized (managedServiceReferences) {
return (ServiceReference) managedServiceReferences.get(pid);
}
}
private String getPidForManagedService(Object service) {
synchronized (managedServiceReferences) {
for (Iterator it = managedServices.entrySet().iterator(); it.hasNext();) {
Entry entry = (Entry) it.next();
if (entry.getValue() == service)
return (String) entry.getKey();
}
return null;
}
}
private void asynchUpdated(final ManagedService service, final Dictionary properties) {
queue.put(new Runnable() {
public void run() {
try {
service.updated(properties);
} catch (ConfigurationException e) {
// we might consider doing more for ConfigurationExceptions
Throwable cause = e.getCause();
configurationAdminFactory.log(LogService.LOG_ERROR, e.getMessage(), cause != null ? cause : e);
} catch (Throwable t) {
configurationAdminFactory.log(LogService.LOG_ERROR, t.getMessage(), t);
}
}
});
}
}