blob: f53b9653706ed24cb158b931e833db881ac1aa92 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1997-2010 by ProSyst Software GmbH
* http://www.prosyst.com
* 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:
* ProSyst Software GmbH - initial API and implementation
* Andrew Teirney - bug.id = 278732
*******************************************************************************/
package org.eclipse.equinox.internal.ds;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import org.apache.felix.scr.Component;
import org.eclipse.equinox.internal.ds.model.*;
import org.eclipse.equinox.internal.util.event.Queue;
import org.eclipse.equinox.internal.util.threadpool.ThreadPoolManager;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.cm.*;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentException;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
/**
* Acts as a "Bundle Manager" - a listener for bundle events. Whenever a bundle
* is stopped or started it will invoke the resolver to respectively enable or
* disable the contained components. Notice, the SynchronousBundleListener
* bundle listeners are called prior bundle event is completed.
*
* It is also a listener for update and delete configuration events, sent by
* Configuration Admin, thus handling the changes in configurations which are meant
* to configure the properties of DS components
*
* @author Maria Ivanova
* @author Stoyan Boshev
* @author Pavlin Dobrev
*/
public class SCRManager implements ServiceListener, SynchronousBundleListener, ConfigurationListener, WorkPerformer, PrivilegedAction {
/** work action type */
public final int ENABLE_COMPONENTS = 1;
public final int DISABLE_COMPONENTS = 2;
protected Hashtable bundleToServiceComponents;
protected Queue queue;
private Resolver resolver;
private WorkThread workThread;
protected boolean running = false;
protected boolean stopped = false;
private ServiceTracker threadPoolManagerTracker;
private boolean hasRegisteredServiceListener = false;
private ComponentStorage storage;
/**
* Constructs the SCRManager.
*/
public SCRManager() {
hasRegisteredServiceListener = true;
queue = new Queue(10);
if (Activator.startup)
Activator.timeLog("Queue instantiated for "); //$NON-NLS-1$
threadPoolManagerTracker = new ServiceTracker(Activator.bc, ThreadPoolManager.class.getName(), null);
threadPoolManagerTracker.open();
if (Activator.startup)
Activator.timeLog("Threadpool service tracker opened for "); //$NON-NLS-1$
resolver = new Resolver(this);
if (Activator.startup)
Activator.timeLog("Resolver instantiated for "); //$NON-NLS-1$
resolver.synchronizeServiceReferences();
if (Activator.startup)
Activator.timeLog("resolver.synchronizeServiceReferences() method took "); //$NON-NLS-1$
Activator.bc.addBundleListener(this);
if (Activator.startup)
Activator.timeLog("addBundleListener() method took "); //$NON-NLS-1$
String storageClass = Activator.bc.getProperty("scr.storage.class"); //$NON-NLS-1$
if (storageClass == null) {
storageClass = "org.eclipse.equinox.internal.ds.storage.file.FileStorage"; //$NON-NLS-1$
}
try {
storage = (ComponentStorage) Class.forName(storageClass).getConstructor(new Class[] {BundleContext.class}).newInstance(new Object[] {Activator.bc});
} catch (Exception e) {
Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.COULD_NOT_CREATE_INSTANCE, storageClass), e);
}
}
public void startIt() {
// loop through the currently installed bundles
Bundle[] bundles = Activator.bc.getBundles();
if (bundles != null) {
for (int i = 0; i < bundles.length; i++) {
Bundle current = bundles[i];
// try to process the active ones.
if (current.getState() == Bundle.ACTIVE) {
startedBundle(current);
} else if (current.getState() == Bundle.STARTING) {
String lazy = (String) current.getHeaders("").get(Constants.BUNDLE_ACTIVATIONPOLICY); //$NON-NLS-1$
if (lazy != null && lazy.indexOf(Constants.ACTIVATION_LAZY) >= 0) {
startedBundle(current);
}
}
}
}
}
/**
* Add an event to the queue. The event will be forwarded to target service
* as soon as possible.
*
* @param upEv
* event, holding info for update/deletion of a configuration.
*/
public void addEvent(Object upEv, boolean securityCall) {
try {
synchronized (queue) {
queue.put(upEv);
if (!running) {
if (queue.size() > 0) {
running = true;
workThread = new WorkThread(this);
if (securityCall) {
AccessController.doPrivileged(this);
return;
}
ThreadPoolManager threadPool = (ThreadPoolManager) threadPoolManagerTracker.getService();
if (threadPool != null) {
threadPool.execute(workThread, Thread.MAX_PRIORITY, "Component Resolve Thread"); //$NON-NLS-1$
} else {
new Thread(workThread, "Component Resolve Thread").start(); //$NON-NLS-1$
}
}
} else if (workThread.waiting > 0) {
queue.notifyAll();
}
}
} catch (Throwable e) {
Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, e);
}
}
public Object run() {
ThreadPoolManager threadPool = (ThreadPoolManager) threadPoolManagerTracker.getService();
if (threadPool != null) {
threadPool.execute(workThread, Thread.MAX_PRIORITY, "Component Resolve Thread"); //$NON-NLS-1$
} else {
new Thread(workThread, "Component Resolve Thread").start(); //$NON-NLS-1$
}
return null;
}
public void queueBlocked() {
resolver.queueBlocked();
synchronized (queue) {
running = false;
addEvent(null, Activator.security); // will result in starting new
// WorkThread to process the queued work
}
}
/**
* This methods takes the input parameters and creates a Queued object and
* queues it. The thread is notified.
*
* @param d
* Dispatcher for this item
* @param a
* Action for this item
* @param o
* Object for this item
* @param securityCall specifies whether to use security privileged call
*/
public void enqueueWork(WorkPerformer d, int a, Object o, boolean securityCall) {
addEvent(new QueuedJob(d, a, o), securityCall);
}
/**
* Stops this thread, making it getting out of method run.
*/
public void stopIt() {
stopped = true;
disposeBundles();
if (queue != null) {
queue.clear();
}
if (running) {
synchronized (queue) {
queue.notify();
}
int counter = 0;
while (running && counter < 20) {
// wait maximum 2 seconds to complete current task in the queue
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
//nothing to do
}
counter++;
}
}
stopped = true;
threadPoolManagerTracker.close();
storage.stop();
}
public void serviceChanged(ServiceEvent sEv) {
resolver.getEligible(sEv);
}
public final void bundleChanged(BundleEvent event) {
long start = 0l;
if (Activator.PERF) {
start = System.currentTimeMillis();
Activator.log.info("[DS perf] Started processing bundle event " + event); //$NON-NLS-1$
}
int type = event.getType();
if (type == BundleEvent.STOPPING) {
stoppingBundle(event.getBundle());
} else if (type == BundleEvent.STARTED) {
startedBundle(event.getBundle());
} else if (type == BundleEvent.LAZY_ACTIVATION) {
startedBundle(event.getBundle());
} else if (type == BundleEvent.UNINSTALLED && Activator.DBSTORE) {
storage.deleteComponentDefinitions(event.getBundle().getBundleId());
}
if (Activator.PERF) {
start = System.currentTimeMillis() - start;
Activator.log.info("[DS perf] Processed bundle event '" + event + "' for " + start + "ms"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
}
// -- begin 'CM listener'
/**
* Listen for configuration changes
*
* Service Components can receive properties from the Configuration Admin
* service. If a Service Component is activated and it�s properties are
* updated in the Configuration Admin service, the SCR must deactivate the
* component and activate the component again using the new properties.
*
* @param event
* ConfigurationEvent
*/
public void configurationEvent(ConfigurationEvent event) {
if (bundleToServiceComponents != null && !bundleToServiceComponents.isEmpty()) {
addEvent(event, true);
}
}
protected void processConfigurationEvent(ConfigurationEvent event) {
if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
// no components found till now
return;
}
long start = 0l;
try {
if (Activator.DEBUG) {
Activator.log.debug(" Resolver.configurationEvent(): pid = " + event.getPid() + ", fpid = " + event.getFactoryPid(), null); //$NON-NLS-1$ //$NON-NLS-2$
}
if (Activator.PERF) {
start = System.currentTimeMillis();
Activator.log.info("[DS perf] Started processing configuration event " + event); //$NON-NLS-1$
}
String pid = event.getPid();
String fpid = event.getFactoryPid();
for (Enumeration keys = bundleToServiceComponents.keys(); keys.hasMoreElements();) {
Vector bundleComps = (Vector) bundleToServiceComponents.get(keys.nextElement());
// bundleComps may be null since bundleToServiceComponents
// may have been modified by another thread
if (bundleComps != null) {
for (int i = 0; i < bundleComps.size(); i++) {
ServiceComponent sc = (ServiceComponent) bundleComps.elementAt(i);
if (sc.getConfigurationPolicy() == ServiceComponent.CONF_POLICY_IGNORE) {
//skip processing of this component - it is not interested in configuration changes
continue;
}
String name = sc.name;
if (name.equals(pid) || name.equals(fpid)) {
if (name.equals(fpid) && sc.factory != null) {
Activator.log(sc.bc, LogService.LOG_ERROR, NLS.bind(Messages.FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY, name), null);
return;
}
if (sc.enabled) {
if (Activator.DEBUG) {
Activator.log.debug("SCRManager.processConfigurationEvent(): found component - " + pid, null); //$NON-NLS-1$
}
processConfigurationEvent(event, sc);
}
return;
}
}
}
}
} catch (Throwable e) {
Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.ERROR_PROCESSING_CONFIGURATION, event.getReference().getBundle()), e);
} finally {
if (Activator.PERF) {
start = System.currentTimeMillis() - start;
Activator.log.info("[DS perf] Processed configuration event '" + event + "' for " + start + "ms"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
}
}
}
private void processConfigurationEvent(ConfigurationEvent event, ServiceComponent sc) {
Configuration[] config = null;
String pid = event.getPid();
String fpid = event.getFactoryPid();
switch (event.getType()) {
case ConfigurationEvent.CM_UPDATED :
String filter = (fpid != null ? "(&" : "") + "(" + Constants.SERVICE_PID + "=" + pid + ")" + (fpid != null ? ("(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + fpid + "))") : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
try {
config = Activator.listConfigurations(filter);
} catch (IOException e) {
Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_LISTING_CONFIGURATIONS, e);
} catch (InvalidSyntaxException e) {
Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_LISTING_CONFIGURATIONS, e);
}
if (config == null) {
// The configuration may have been deleted by the now
// If it does not exist we must do nothing
return;
}
// if NOT a factory
if (fpid == null) {
// there is only one SCP for this SC
boolean requiresRestart = true;
if (sc.namespace11 && sc.modifyMethodName != "") { //$NON-NLS-1$
ServiceComponentProp scp = sc.getServiceComponentProp();
if (scp != null && scp.isBuilt()) {
//process only built components
requiresRestart = processConfigurationChange(scp, config[0]);
}
}
if (requiresRestart) {
// there is only one SCP for this SC, so we can disable the SC
Vector components = new Vector();
components.addElement(sc);
resolver.disableComponents(components, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_MODIFIED);
// now re-enable the SC - the resolver will pick up the new config
sc.enabled = true;
resolver.enableComponents(components);
}
// If a MSF
// create a new SCP or update an existing one
} else {
// get scp with this PID
ServiceComponentProp scp = sc.getComponentPropByPID(pid);
// if only the no-props scp exists, replace it
if (scp == null && sc.componentProps != null) {
synchronized (sc.componentProps) {
if (sc.componentProps.size() == 1 && (((ServiceComponentProp) sc.componentProps.elementAt(0)).getProperties().get(Constants.SERVICE_PID) == null)) {
scp = (ServiceComponentProp) sc.componentProps.elementAt(0);
}
}
}
boolean requiresRestart = true;
if (sc.namespace11 && sc.modifyMethodName != "" && scp != null) { //$NON-NLS-1$
if (scp.isBuilt()) {
//process only built components
requiresRestart = processConfigurationChange(scp, config[0]);
}
}
if (requiresRestart) {
// if old scp exists, dispose it
if (scp != null) {
// config already exists - dispose of it
sc.componentProps.removeElement(scp);
Vector components = new Vector();
components.addElement(scp);
resolver.disposeComponentConfigs(components, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_MODIFIED);
scp.setState(Component.STATE_DISPOSED);
}
// create a new scp (adds to resolver enabledSCPs list)
resolver.map(sc, config[0]);
// kick the resolver to figure out if SCP is satisfied, etc
resolver.enableComponents(null);
}
}
break;
case ConfigurationEvent.CM_DELETED :
// if not a factory
if (fpid == null) {
// there is only one SCP for this SC, so we can disable the SC
Vector components = new Vector();
components.addElement(sc);
resolver.disableComponents(components, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED);
// now re-enable the SC - the resolver will create SCP with
// no configAdmin properties
sc.enabled = true;
resolver.enableComponents(components);
} else {
// config is a factory
// get SCP created for this config (with this PID)
ServiceComponentProp scp = sc.getComponentPropByPID(pid);
// if this was the last SCP created for this factory
if (sc.componentProps.size() == 1) {
// there is only one SCP for this SC, so we can disable the
// SC
Vector components = new Vector();
components.addElement(sc);
resolver.disableComponents(components, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED);
// now re-enable the SC - the resolver will create SCP
// with no configAdmin properties
sc.enabled = true;
sc.setState(Component.STATE_UNSATISFIED);
resolver.enableComponents(components);
} else {
// we can just dispose this SCP
sc.componentProps.removeElement(scp);
Vector components = new Vector();
components.addElement(scp);
resolver.disposeComponentConfigs(components, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED);
scp.setState(Component.STATE_DISPOSED);
}
}
break;
}
}
/**
* Process the modification of the specified component.
* If it cannot be modified, the method will return <code>true</code> indicating the component has to be restarted.
* @param scp the component to modify
* @param config the configuration that brings the new properties
* @return true, if the component needs restart (to be deactivated and then eventually activated again)
*/
private boolean processConfigurationChange(ServiceComponentProp scp, Configuration config) {
boolean result = false;
Hashtable currentProps = scp.properties;
Dictionary newProps = config.getProperties();
Enumeration keys = currentProps.keys();
Vector checkedFilters = new Vector();
while (keys.hasMoreElements() && !result) {
String key = (String) keys.nextElement();
if (key.endsWith(".target")) { //$NON-NLS-1$
checkedFilters.addElement(key);
String newFilter = (String) newProps.get(key);
Reference reference = null;
String refName = key.substring(0, key.length() - ".target".length()); //$NON-NLS-1$
Vector references = scp.references;
for (int i = 0; i < references.size(); i++) {
reference = (Reference) references.elementAt(i);
if (reference.reference.name.equals(refName)) {
break;
}
reference = null;
}
//check if there is a reference corresponding to the target property
if (reference != null) {
if (newFilter != null) {
if (!newFilter.equals(currentProps.get(key))) {
//the filter differs the old one
result = result || !reference.doSatisfy(newFilter);
}
} else {
//the target filter is removed. Using the default filter to check
if (reference.policy == ComponentReference.POLICY_STATIC) {
result = result || !reference.doSatisfy("(objectClass=" + reference.reference.interfaceName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
}
//now check the new properties if they have new target properties defined
keys = newProps.keys();
while (keys.hasMoreElements() && !result) {
String key = (String) keys.nextElement();
if (key.endsWith(".target") && !checkedFilters.contains(key)) { //$NON-NLS-1$
Reference reference = null;
String refName = key.substring(0, key.length() - ".target".length()); //$NON-NLS-1$
Vector references = scp.references;
for (int i = 0; i < references.size(); i++) {
reference = (Reference) references.elementAt(i);
if (reference.reference.name.equals(refName)) {
break;
}
reference = null;
}
//check if there is a reference corresponding to the target property
if (reference != null) {
result = result || !reference.doSatisfy((String) newProps.get(key));
}
}
}
if (!result) {
//do process component modification via the InstanceProcess
try {
InstanceProcess.staticRef.modifyComponent(scp, newProps);
} catch (ComponentException ce) {
//could happen if the modify method is not found
result = true;
}
}
return result;
}
private void disposeBundles() {
// dispose ALL bundles
if (bundleToServiceComponents != null) {
for (Enumeration e = bundleToServiceComponents.keys(); e.hasMoreElements();) {
Bundle bundle = (Bundle) e.nextElement();
stoppingBundle(bundle);
}
bundleToServiceComponents.clear();
bundleToServiceComponents = null;
}
}
void stoppingBundle(Bundle bundle) {
if (bundleToServiceComponents != null) {
Vector components = (Vector) bundleToServiceComponents.remove(bundle);
// disable the components which the bundle provides
if (components != null) {
if (Activator.DEBUG) {
String bundleName = bundle.getSymbolicName();
bundleName = (bundleName == null || "".equals(bundleName)) ? bundle.getLocation() : bundleName; //$NON-NLS-1$
Activator.log.debug("SCRManager.stoppingBundle : " + bundleName, null); //$NON-NLS-1$
}
resolver.disableComponents(components, ComponentConstants.DEACTIVATION_REASON_BUNDLE_STOPPED);
//set disposed state to all components since some of them might be still referenced by the ScrService
for (int i = 0; i < components.size(); i++) {
ServiceComponent sc = (ServiceComponent) components.elementAt(i);
sc.setState(Component.STATE_DISPOSED);
}
if (bundleToServiceComponents.size() == 0) {
hasRegisteredServiceListener = false;
Activator.bc.removeServiceListener(this);
}
}
}
}
void startedBundle(Bundle bundle) {
long start = 0l;
if (Activator.PERF) {
start = System.currentTimeMillis();
}
if (bundleToServiceComponents != null && bundleToServiceComponents.get(bundle) != null) {
// the bundle is already processed - skipping it
return;
}
String dsHeader = null;
Dictionary allHeaders = bundle.getHeaders(""); //$NON-NLS-1$
if (!((dsHeader = (String) allHeaders.get(ComponentConstants.SERVICE_COMPONENT)) != null)) {
// no component descriptions in this bundle
return;
}
Vector components = storage.loadComponentDefinitions(bundle, dsHeader);
if (components != null && !components.isEmpty()) {
if (!hasRegisteredServiceListener) {
hasRegisteredServiceListener = true;
Activator.bc.addServiceListener(this);
resolver.synchronizeServiceReferences();
}
if (Activator.PERF) {
start = System.currentTimeMillis() - start;
Activator.log.info("[DS perf] The components of bundle " + bundle + " are parsed for " + start + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (bundleToServiceComponents == null) {
synchronized (this) {
if (bundleToServiceComponents == null) {
bundleToServiceComponents = new Hashtable(11);
}
}
}
//check whether component's names are unique
ServiceComponent comp;
ServiceComponent comp2;
L1: for (int i = 0; i < components.size(); i++) {
comp = (ServiceComponent) components.elementAt(i);
//check if unique in its bundle
for (int j = i + 1; j < components.size(); j++) {
comp2 = (ServiceComponent) components.elementAt(j);
if (comp.name.equals(comp2.name)) {
Activator.log(comp.bc, LogService.LOG_ERROR, NLS.bind(Messages.FOUND_COMPONENTS_WITH_DUPLICATED_NAMES, comp), null);
//removing one of the components
components.remove(i);
i--;
continue L1;
}
}
//check if the component is globally unique
Enumeration keys = bundleToServiceComponents.keys();
while (keys.hasMoreElements()) {
Vector components2 = (Vector) bundleToServiceComponents.get(keys.nextElement());
for (int j = 0; j < components2.size(); j++) {
comp2 = (ServiceComponent) components2.elementAt(j);
if (comp.name.equals(comp2.name)) {
Activator.log(comp.bc, LogService.LOG_WARNING, NLS.bind(Messages.FOUND_COMPONENTS_WITH_DUPLICATED_NAMES2, comp, comp2), null);
}
}
}
if (comp.autoenable) {
comp.enabled = true;
}
}
// store the components in the cache
bundleToServiceComponents.put(bundle, components.clone());
if (workThread != null && workThread.processingThread == Thread.currentThread()) {
//we are in the queue thread already. Processing synchronously the job
resolver.enableComponents(components);
} else {
// this will also resolve the component dependencies!
enqueueWork(this, ENABLE_COMPONENTS, components, false);
synchronized (components) {
long startTime = System.currentTimeMillis();
try {
do {
components.wait(1000);
} while (!components.isEmpty() && (System.currentTimeMillis() - startTime < WorkThread.BLOCK_TIMEOUT));
if (System.currentTimeMillis() - startTime >= WorkThread.BLOCK_TIMEOUT) {
Activator.log(null, LogService.LOG_WARNING, NLS.bind(Messages.TIMEOUT_REACHED_ENABLING_COMPONENTS, getBundleName(bundle), Integer.toString(WorkThread.BLOCK_TIMEOUT)), null);
}
} catch (InterruptedException e) {
//do nothing
}
}
}
}
}
private String getBundleName(Bundle b) {
if (b.getSymbolicName() != null) {
return b.getSymbolicName();
}
return b.getLocation();
}
public void enableComponent(String name, Bundle bundle) {
changeComponent(name, bundle, true);
}
private void changeComponent(String name, Bundle bundle, boolean enable) {
if (bundleToServiceComponents == null) {
// already disposed!
return;
}
try {
Vector componentsToProcess = null;
if (Activator.DEBUG) {
String message = (enable ? "SCRManager.enableComponent(): " : "SCRManager.disableComponent(): ").concat(name != null ? name : "*all*") + " from bundle " + getBundleName(bundle); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Activator.log.debug(message, null);
}
Vector bundleComponents = (Vector) bundleToServiceComponents.get(bundle);
if (bundleComponents != null) {
if (name != null) {
boolean found = false;
for (int i = 0; i < bundleComponents.size(); i++) {
ServiceComponent component = (ServiceComponent) bundleComponents.elementAt(i);
if (component.name.equals(name)) {
found = true;
if (component.enabled != enable) {
component.enabled = enable;
component.setState(enable ? Component.STATE_ENABLING : Component.STATE_DISABLING);
componentsToProcess = new Vector(2);
componentsToProcess.addElement(component);
break;
}
}
}
if (!found) {
throw new IllegalArgumentException(NLS.bind(Messages.COMPONENT_NOT_FOUND, name, bundle));
}
} else {
if (enable) {
// processing null parameter should be done only when
// enabling components
ServiceComponent sc;
componentsToProcess = new Vector();
for (int i = 0; i < bundleComponents.size(); i++) {
sc = ((ServiceComponent) bundleComponents.elementAt(i));
if (!sc.enabled) {
componentsToProcess.addElement(sc);
sc.enabled = enable;
sc.setState(Component.STATE_ENABLING);
}
}
}
}
}
// publish to resolver the list of SCs to enable
if (componentsToProcess != null && !componentsToProcess.isEmpty()) {
if (enable) {
enqueueWork(this, ENABLE_COMPONENTS, componentsToProcess, Activator.security);
} else {
enqueueWork(this, DISABLE_COMPONENTS, componentsToProcess, Activator.security);
}
}
} catch (IllegalArgumentException iae) {
throw iae;
} catch (Throwable e) {
Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, e);
}
}
/**
* QueuedJob represents the items placed on the asynch dispatch queue.
*/
static class QueuedJob {
final WorkPerformer performer;
/** the required type of action to do */
final int actionType;
/** work input data to be performed */
final Object workToDo;
/**
* Constructor for work queue item
*
* @param d
* Dispatcher for this item
* @param a
* Action for this item
* @param o
* Object for this item
*/
QueuedJob(WorkPerformer d, int a, Object o) {
performer = d;
actionType = a;
workToDo = o;
}
void dispatch() {
try {
/* Call the WorkPerformer to process the work. */
performer.performWork(actionType, workToDo);
} catch (Throwable t) {
Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_DISPATCHING_WORK, t);
}
}
public String toString() {
return "[QueuedJob] WorkPerformer: " + performer + "; actionType " + actionType; //$NON-NLS-1$ //$NON-NLS-2$
}
}
// -- begin enable/disable components
/**
* disableComponent - The specified component name must be in the same
* bundle as this component. Called by SC componentContext method
*
* @param name
* The name of a component to disable
* @param bundle
* The bundle which contains the Service Component to be disabled
*/
public void disableComponent(String name, Bundle bundle) {
changeComponent(name, bundle, false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.equinox.internal.ds.util.WorkPerformer#performWork(int,
* java.lang.Object)
*/
public void performWork(int workAction, Object workObject) {
if (workAction == ENABLE_COMPONENTS) {
resolver.enableComponents((Vector) workObject);
//notify that the component enabling has finished
synchronized (workObject) {
((Vector) workObject).clear();
workObject.notify();
}
} else if (workAction == DISABLE_COMPONENTS) {
resolver.disableComponents((Vector) workObject, ComponentConstants.DEACTIVATION_REASON_DISABLED);
}
}
protected void configAdminRegistered(ConfigurationAdmin configAdmin, ServiceReference caReference) {
if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
// no components found till now
return;
}
Vector toProcess = new Vector(1);
Configuration[] configs = null;
try {
configs = configAdmin.listConfigurations(null);
} catch (Exception e) {
Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_LISTING_CONFIGURATIONS, e);
}
if (configs == null || configs.length == 0) {
//no configurations found
return;
}
//process all components to find such that need to be evaluated when ConfigAdmin is available
for (Enumeration keys = bundleToServiceComponents.keys(); keys.hasMoreElements();) {
Vector bundleComps = (Vector) bundleToServiceComponents.get(keys.nextElement());
// bundleComps may be null since bundleToServiceComponents
// may have been modified by another thread
if (bundleComps != null) {
for (int i = 0; i < bundleComps.size(); i++) {
ServiceComponent sc = (ServiceComponent) bundleComps.elementAt(i);
if (sc.getConfigurationPolicy() == ServiceComponent.CONF_POLICY_IGNORE) {
//skip processing of this component - it is not interested in configuration changes
continue;
}
if (sc.enabled) {
for (int j = 0; j < configs.length; j++) {
if (configs[j].getPid().equals(sc.name) || sc.name.equals(configs[j].getFactoryPid())) {
if (sc.name.equals(configs[j].getFactoryPid()) && sc.factory != null) {
Activator.log(sc.bc, LogService.LOG_ERROR, NLS.bind(Messages.FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY, sc.name), null);
break;
}
//found a configuration for this component
if (sc.componentProps == null || sc.componentProps.size() == 0) {
if (sc.getConfigurationPolicy() == ServiceComponent.CONF_POLICY_REQUIRE) {
//the component is not yet mapped because it is requiring configuration. Try to process it
toProcess.addElement(sc);
}
} else {
//process the component configurations and eventually modify or restart them
ConfigurationEvent ce = new ConfigurationEvent(caReference, ConfigurationEvent.CM_UPDATED, configs[j].getFactoryPid(), configs[j].getPid());
processConfigurationEvent(ce, sc);
}
break;
}
}
}
}
}
}
if (toProcess.size() > 0) {
resolver.enableComponents(toProcess);
}
}
public Component[] getComponents() {
if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
// no components found till now
return null;
}
Vector result = new Vector();
Enumeration en = bundleToServiceComponents.keys();
while (en.hasMoreElements()) {
Bundle b = (Bundle) en.nextElement();
Vector serviceComponents = (Vector) bundleToServiceComponents.get(b);
for (int i = 0; i < serviceComponents.size(); i++) {
ServiceComponent sc = (ServiceComponent) serviceComponents.elementAt(i);
if (sc.componentProps != null && !sc.componentProps.isEmpty()) {
//add the created runtime components props
result.addAll(sc.componentProps);
} else {
//add the declared component itself
result.add(sc);
}
}
}
if (!result.isEmpty()) {
Component[] res = new Component[result.size()];
result.copyInto(res);
return res;
}
return null;
}
public Component[] getComponents(Bundle bundle) {
if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
// no components found till now
return null;
}
Vector serviceComponents = (Vector) bundleToServiceComponents.get(bundle);
if (serviceComponents != null) {
Vector result = new Vector();
for (int i = 0; i < serviceComponents.size(); i++) {
ServiceComponent sc = (ServiceComponent) serviceComponents.elementAt(i);
if (sc.componentProps != null && !sc.componentProps.isEmpty()) {
//add the created runtime components props
result.addAll(sc.componentProps);
} else {
//add the declared component itself
result.add(sc);
}
}
if (!result.isEmpty()) {
Component[] res = new Component[result.size()];
result.copyInto(res);
return res;
}
}
return null;
}
public Component[] getComponents(String componentName) {
if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
// no components found till now
return null;
}
Vector result = new Vector();
Enumeration en = bundleToServiceComponents.keys();
while (en.hasMoreElements()) {
Bundle b = (Bundle) en.nextElement();
Vector serviceComponents = (Vector) bundleToServiceComponents.get(b);
for (int i = 0; i < serviceComponents.size(); i++) {
ServiceComponent sc = (ServiceComponent) serviceComponents.elementAt(i);
if (sc.getName().equals(componentName)) {
if (sc.componentProps != null && !sc.componentProps.isEmpty()) {
// add the created runtime components props
result.addAll(sc.componentProps);
} else {
// add the declared component itself
result.add(sc);
}
break;
}
}
}
if (!result.isEmpty()) {
Component[] res = new Component[result.size()];
result.copyInto(res);
return res;
}
return null;
}
}