/*******************************************************************************
 * Copyright (c) 1997-2009 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
 *    Simon Kaegi			 - bug.id = 296750
 *******************************************************************************/
package org.eclipse.equinox.internal.ds;

import java.util.*;
import org.apache.felix.scr.Component;
import org.eclipse.equinox.internal.ds.model.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentException;
import org.osgi.service.log.LogService;

/**
 * Resolver.java
 * 
 * @author Valentin Valchev
 * @author Stoyan Boshev
 * @author Pavlin Dobrev
 */
public final class Resolver implements WorkPerformer {

	// these strings are used only for debugging purpose
	static final String[] WORK_TITLES = {"BUILD ", "DYNAMICBIND ", "DISPOSE "}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

	/**
	 * Service Component instances need to be built.
	 */
	public static final int BUILD = 1;

	/**
	 * Service Component instances need to be rebound
	 */
	public static final int DYNAMICBIND = 2;

	/**
	 * Service Component instances need to be disposed
	 */
	public static final int DISPOSE = 3;

	/* Holds the enabled SCPs*/
	protected Vector scpEnabled;

	private InstanceProcess instanceProcess;

	private Object syncLock = new Object();

	private Hashtable serviceReferenceTable = new Hashtable();

	public SCRManager mgr;

	// TODO: Add a hashtable connecting servicereference to a list of References
	// which they are bound to
	// This way the search of references to unbind becomes faster when there are
	// plenty of components.
	// Keep in mind that build process is asynchronous.

	static {
		/** preload some DS bundle classes to avoid classloader deadlocks */
		Reference.class.getName();
		SCRUtil.class.getName();
	}

	/**
	 * Resolver constructor
	 * 
	 */
	Resolver(SCRManager mgr) {
		scpEnabled = new Vector();
		//		satisfiedSCPs = new Vector();
		instanceProcess = new InstanceProcess(this);
		this.mgr = mgr;
	}

	void synchronizeServiceReferences() {
		synchronized (syncLock) {
			try {
				ServiceReference[] references = Activator.bc.getAllServiceReferences(null, null);
				serviceReferenceTable.clear();
				if (references != null) {
					for (int i = 0; i < references.length; i++) {
						serviceReferenceTable.put(references[i], Boolean.TRUE);
					}
				}
			} catch (InvalidSyntaxException e) {
				Activator.log(Activator.bc, LogService.LOG_WARNING, "Resolver(): " + NLS.bind(Messages.INVALID_TARGET_FILTER, ""), e); //$NON-NLS-1$ //$NON-NLS-2$
			}
		}
	}

	public Object getSyncLock() {
		return syncLock;
	}

	// This method should be called when the event processing thread is blocked
	// in a user code
	void queueBlocked() {
		syncLock = new Object();
		instanceProcess = new InstanceProcess(this);
	}

	// -- begin *enable* component routines
	/**
	 * enableComponents - called by the dispatchWorker
	 * 
	 * @param serviceComponents -
	 *            a list of all component descriptions for a single bundle to be
	 *            enabled Receive ArrayList of enabled CD's from ComponentCache
	 *            For each CD add to list of enabled create list of CD:CD+P
	 *            create list of CD+P:ref ( where ref is a Reference Object)
	 *            resolve CD+P
	 */
	void enableComponents(Vector serviceComponents) {
		long start = 0l;
		if (Activator.DEBUG) {
			Activator.log.debug("Resolver.enableComponents(): " + (serviceComponents != null ? serviceComponents.toString() : "null"), null); //$NON-NLS-1$ //$NON-NLS-2$
		}
		if (Activator.PERF) {
			start = System.currentTimeMillis();
		}

		synchronized (syncLock) {
			Configuration[] configs = null;

			if (serviceComponents != null) {
				for (int i = 0; i < serviceComponents.size(); i++) {
					ServiceComponent current = (ServiceComponent) serviceComponents.elementAt(i);

					// don't enable components which are not marked enabled
					// this is done here, not in the activator just because it
					// saves a little memory
					if (!current.enabled) {
						if (Activator.DEBUG) {
							Activator.log.debug("Resolver.enableComponents(): ignoring not enabled component " + current.name, null); //$NON-NLS-1$
						}
						continue;
					}

					current.setState(Component.STATE_UNSATISFIED);

					if (current.getConfigurationPolicy() == ServiceComponent.CONF_POLICY_IGNORE) {
						//skip looking for configurations 
						map(current, (Dictionary) null);
						continue;
					}

					// check for a Configuration properties for this component
					try {
						String filter = "(|(" + Constants.SERVICE_PID + '=' + current.name + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID + '=' + current.name + "))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
						configs = Activator.listConfigurations(filter);
					} catch (Exception e) {
						Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.CANT_LIST_CONFIGURATIONS, current.name), e);
					}
					// if no Configuration
					if (configs == null || configs.length == 0) {
						if (current.getConfigurationPolicy() != ServiceComponent.CONF_POLICY_REQUIRE) {
							// create ServiceComponent + Prop
							map(current, (Dictionary) null);
						} else {
							String customReason = Activator.configAdmin != null ? "" : Messages.CONFIG_ADMIN_SERVICE_NOT_AVAILABLE; //$NON-NLS-1$
							if (Activator.DEBUG) {
								Activator.log.debug(NLS.bind(Messages.COMPONENT_REQURES_CONFIGURATION_ACTIVATION, current.name) + customReason, null);
							}
						}
					} else {
						// if ManagedServiceFactory
						Configuration config = configs[0];
						if (config.getFactoryPid() != null && config.getFactoryPid().equals(current.name)) {
							// if ComponentFactory is specified
							if (current.factory != null) {
								Activator.log(current.bc, LogService.LOG_ERROR, NLS.bind(Messages.REGISTERED_AS_COMPONENT_AND_MANAGED_SERVICE_FACORY, current.name), null);
								continue; // skip current component
							}
							if (Activator.DEBUG) {
								Activator.log.debug("[SCR - Resolver] Resolver.enableComponents(): " + current.name + " as *managed service factory*", null); //$NON-NLS-1$ //$NON-NLS-2$
							}
							try {
								configs = Activator.listConfigurations("(service.factoryPid=" + config.getFactoryPid() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
							} catch (Exception e) {
								Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.CANT_LIST_CONFIGURATIONS, current.name), e);
							}
							// for each MSF set of properties(P), map(CD, new
							// CD+P(CD,P))
							if (configs != null) {
								for (int index = 0; index < configs.length; index++) {
									map(current, configs[index]);
								}
							}
						} else {
							if (Activator.DEBUG) {
								Activator.log.debug("[SCR - Resolver] Resolver.enableComponents(): " + current.name + " as *service*", null); //$NON-NLS-1$ //$NON-NLS-2$
							} // if Service, not ManagedServiceFactory
							map(current, config);
						}
					} // end has configuration
				} // end process all components!
			}
		}

		buildNewlySatisfied(true);

		if (Activator.PERF) {
			start = System.currentTimeMillis() - start;
			Activator.log.info("[DS perf] " + (serviceComponents != null ? Integer.toString(serviceComponents.size()) : "") + " Components enabled for " + Long.toString(start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		}
	}

	protected ServiceComponentProp map(ServiceComponent component, Configuration config) {
		Dictionary configProps = null;
		if (config != null) {
			try {
				configProps = config.getProperties();
			} catch (IllegalStateException ise) {
				// the configuration may have beed deleted already
			}
		}
		ServiceComponentProp scp = map(component, configProps);
		if (config != null) {
			// set the service PID & Factory Pid
			String pid = config.getPid();
			String fpid = config.getFactoryPid();
			if (pid != null)
				scp.properties.put(Constants.SERVICE_PID, pid);
			if (fpid != null)
				scp.properties.put(ConfigurationAdmin.SERVICE_FACTORYPID, fpid);
		}
		return scp;
	}

	/**
	 * Create the SCP and add to the maps
	 * 
	 * @param component the component for which SCP will be created 
	 * @param configProperties CM configuration properties
	 */
	public ServiceComponentProp map(ServiceComponent component, Dictionary configProperties) {
		ServiceComponentProp scp = null;
		try {
			if (Activator.DEBUG) {
				Activator.log.debug("Resolver.map(): Creating SCP for component " + component.name, null); //$NON-NLS-1$
			}
			scp = new ServiceComponentProp(component, configProperties, mgr);

			// Get all the required service reference descriptions for this
			Vector referenceDescriptions = component.references;

			// for each Reference Description, create a reference object
			if (referenceDescriptions != null && !referenceDescriptions.isEmpty()) {
				Vector references = new Vector(referenceDescriptions.size());

				for (int i = 0; i < referenceDescriptions.size(); i++) {
					// create new Reference Object and add to CD+P:ref map
					ComponentReference cRef = (ComponentReference) referenceDescriptions.elementAt(i);

					Reference ref = new Reference(cRef, scp, scp.getProperties());
					references.addElement(ref);
				}
				scp.references = references;
			}
			component.addServiceComponentProp(scp);
			scpEnabled.addElement(scp);

		} catch (Throwable t) {
			Activator.log(component.bc, LogService.LOG_ERROR, NLS.bind(Messages.ERROR_CREATING_SCP, component), t);
		}
		return scp;
	}

	/**
	 * Get the Eligible Components
	 * 
	 * loop through CD+P list of enabled get references check if eligible if
	 * true add to eligible list send to Instance Process
	 * 
	 */
	void getEligible(ServiceEvent event) {

		if (Activator.DEBUG) {
			Activator.log.debug("Resolver.getEligible(): processing service event " + event.toString(), null); //$NON-NLS-1$
			String eventType = ""; //$NON-NLS-1$
			if (event.getType() == ServiceEvent.UNREGISTERING) {
				eventType = "UNREGISTERING"; //$NON-NLS-1$
			} else if (event.getType() == ServiceEvent.REGISTERED) {
				eventType = "REGISTERED"; //$NON-NLS-1$
			} else if (event.getType() == ServiceEvent.MODIFIED) {
				eventType = "MODIFIED"; //$NON-NLS-1$
			}
			Activator.log.debug("Service event type: " + eventType, null); //$NON-NLS-1$
		}

		Object target = null;
		Vector resolvedComponents = null;
		switch (event.getType()) {
			case ServiceEvent.REGISTERED :
				synchronized (syncLock) {
					serviceReferenceTable.put(event.getServiceReference(), Boolean.TRUE);
					if (scpEnabled.isEmpty())
						return; // check for any enabled configurations

					resolvedComponents = getComponentsToBuild();
					target = selectDynamicBind(scpEnabled, event.getServiceReference());
				}

				//do synchronous bind
				if (target != null) {
					Vector unboundRefs = instanceProcess.dynamicBind((Vector) target);
					if (unboundRefs != null) {
						// put delayed dynamic binds on the queue
						// (this is used to handle class circularity errors)
						mgr.enqueueWork(this, Resolver.DYNAMICBIND, unboundRefs, false);
					}
				}

				if (!resolvedComponents.isEmpty()) {
					instanceProcess.buildComponents(resolvedComponents, false);
				}

				break;
			case ServiceEvent.UNREGISTERING :
				Vector componentsToDispose;
				synchronized (syncLock) {
					//check for components with static reference to this service
					componentsToDispose = selectStaticUnBind(scpEnabled, event.getServiceReference(), false);
				}
				//dispose instances from staticUnbind
				if (componentsToDispose != null) {
					instanceProcess.disposeInstances(componentsToDispose, ComponentConstants.DEACTIVATION_REASON_REFERENCE);
				}

				Vector newlyUnsatisfiedSCPs;
				synchronized (syncLock) {
					serviceReferenceTable.remove(event.getServiceReference());
					if (scpEnabled.isEmpty())
						return; // check for any enabled configurations

					newlyUnsatisfiedSCPs = selectNewlyUnsatisfied(event.getServiceReference());
				}
				if (!newlyUnsatisfiedSCPs.isEmpty()) {
					// synchronously dispose newly unsatisfied components
					instanceProcess.disposeInstances(newlyUnsatisfiedSCPs, ComponentConstants.DEACTIVATION_REASON_REFERENCE);
				}

				synchronized (syncLock) {
					// Pass in the set of currently resolved components, check each one -
					// do we need to unbind
					target = selectDynamicUnBind(scpEnabled, event.getServiceReference(), false);

					if (componentsToDispose != null || !newlyUnsatisfiedSCPs.isEmpty()) {
						// some components with static references were disposed. Try to build them again
						// get list of newly satisfied SCPs and build them
						resolvedComponents = getComponentsToBuild();
					}
				}

				instanceProcess.dynamicUnBind((Hashtable) target); // do synchronous unbind

				if (resolvedComponents != null && !resolvedComponents.isEmpty()) {
					instanceProcess.buildComponents(resolvedComponents, false);
				}

				return;

			case ServiceEvent.MODIFIED :
				synchronized (syncLock) {
					if (scpEnabled.isEmpty())
						return; // check for any enabled configurations

					// check for newly unsatisfied components and synchronously
					// dispose them
					newlyUnsatisfiedSCPs = selectNewlyUnsatisfied(event.getServiceReference());
				}

				if (!newlyUnsatisfiedSCPs.isEmpty()) {
					instanceProcess.disposeInstances(newlyUnsatisfiedSCPs, ComponentConstants.DEACTIVATION_REASON_REFERENCE);
				}

				synchronized (syncLock) {
					//check for components with static reference to this service
					componentsToDispose = selectStaticUnBind(scpEnabled, event.getServiceReference(), true);
				}

				if (componentsToDispose != null) {
					instanceProcess.disposeInstances(componentsToDispose, ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED);
				}

				synchronized (syncLock) {
					// dynamic unbind
					// check each satisfied scp - do we need to unbind
					target = selectDynamicUnBind(scpEnabled, event.getServiceReference(), true);
				}

				if (target != null) {
					instanceProcess.dynamicUnBind((Hashtable) target);
				}

				synchronized (syncLock) {
					// dynamic bind
					target = selectDynamicBind(scpEnabled, event.getServiceReference());

					// get list of newly satisfied SCPs and build them
					resolvedComponents = getComponentsToBuild();
				}

				if (target != null) {
					Vector unboundRefs = instanceProcess.dynamicBind((Vector) target);
					if (unboundRefs != null) {
						// put delayed dynamic binds on the queue
						// (this is used to handle class circularity errors)
						mgr.enqueueWork(this, Resolver.DYNAMICBIND, unboundRefs, false);
					}
				}
				if (!resolvedComponents.isEmpty()) {
					instanceProcess.buildComponents(resolvedComponents, false);
				}
		}
	}

	public void buildNewlySatisfied(boolean checkForDependencyCycles) {
		Vector resolvedComponents;
		synchronized (syncLock) {
			if (checkForDependencyCycles) {
				findDependencyCycles();
			}
			resolvedComponents = getComponentsToBuild();
		}

		if (!resolvedComponents.isEmpty()) {
			instanceProcess.buildComponents(resolvedComponents, false);
		}
	}

	private Vector getComponentsToBuild() {
		Vector resolvedComponents = resolveEligible();
		// select the satisfied components only
		ServiceComponentProp scp;
		for (int i = resolvedComponents.size() - 1; i >= 0; i--) {
			scp = (ServiceComponentProp) resolvedComponents.elementAt(i);
			if (scp.getState() != Component.STATE_UNSATISFIED) {
				resolvedComponents.removeElementAt(i);
			}
		}
		return resolvedComponents;
	}

	/**
	 * Notifies the resolver that a component has been disposed. 
	 * It should accordingly update its data structures if needed
	 *
	 **/
	public void componentDisposed(ServiceComponentProp scp) {
		//
	}

	private Vector resolveEligible() {
		try {
			Vector enabledSCPs = (Vector) scpEnabled.clone();
			for (int k = enabledSCPs.size() - 1; k >= 0; k--) {
				ServiceComponentProp scp = (ServiceComponentProp) enabledSCPs.elementAt(k);
				try {
					Vector refs = scp.references;
					for (int i = 0; refs != null && i < refs.size(); i++) {
						// Loop though all the references (dependencies)for a given
						// scp. If a dependency is not met, remove it's associated scp and
						// re-run the algorithm
						Reference reference = (Reference) refs.elementAt(i);
						if (reference != null) {
							boolean resolved = !reference.isRequiredFor(scp.serviceComponent) || reference.hasProviders(this.serviceReferenceTable);

							if (!resolved) {
								if (Activator.DEBUG) {
									Activator.log.debug("Resolver.resolveEligible(): reference '" + reference.reference.name + "' of component '" + scp.name + "' is not resolved", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
								}
								enabledSCPs.removeElementAt(k);
								break;
							}
						}
					}
				} catch (IllegalStateException ise) {
					//the bundle of the scp is probably already uninstalled
					scpEnabled.removeElementAt(k);
					enabledSCPs.removeElementAt(k);
					continue;
				}
				// check if the bundle providing the service has permission to
				// register the provided interface(s)
				if (scp.serviceComponent.provides != null && System.getSecurityManager() != null) {
					String[] provides = scp.serviceComponent.provides;
					boolean hasPermission = true;
					int i = 0;
					for (; i < provides.length; i++) {
						// make sure bundle has permission to register the service
						try {
							if (!scp.bc.getBundle().hasPermission(new ServicePermission(provides[i], ServicePermission.REGISTER))) {
								hasPermission = false;
								break;
							}
						} catch (IllegalStateException ise) {
							// the bundle of the service component is uninstalled
							// System.out.println("IllegalStateException occured
							// while processing component "+scp);
							// ise.printStackTrace();
							hasPermission = false;
							break;
						} catch (Throwable t) {
							// System.out.println("Exception occured processing
							// component "+scp);
							// t.printStackTrace();
							hasPermission = false;
							break;
						}
					}
					if (!hasPermission) {
						Activator.log(null, LogService.LOG_WARNING, NLS.bind(Messages.COMPONENT_LACKS_APPROPRIATE_PERMISSIONS, scp.name, provides[i]), null);
						removeEnabledSCP(scp);
						enabledSCPs.removeElementAt(k);
						continue;
					}
				}
				if (!scp.isBuilt() && !(scp.getState() == Component.STATE_DEACTIVATING)) {
					scp.setState(Component.STATE_UNSATISFIED);
				}
			}

			if (Activator.DEBUG) {
				Activator.log.debug("Resolver.resolveEligible(): resolved components = " + enabledSCPs.toString(), null); //$NON-NLS-1$
			}
			return enabledSCPs;
		} catch (Throwable e) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, e);
			return new Vector();
		}
	}

	private Vector selectNewlyUnsatisfied(ServiceReference serviceRef) {
		try {
			Vector result = (Vector) scpEnabled.clone();
			for (int k = result.size() - 1; k >= 0; k--) {
				ServiceComponentProp scp = (ServiceComponentProp) result.elementAt(k);
				Vector refs = scp.references;
				boolean toDispose = false;
				for (int i = 0; refs != null && i < refs.size(); i++) {
					// Loop though all the references (dependencies)for a given
					// scp. If a dependency is not met, remove it's associated
					// scp and re-run the algorithm
					Reference reference = (Reference) refs.elementAt(i);
					if (reference != null) {
						if (serviceRef != null && reference.reference.bind != null && scp.getState() == Component.STATE_ACTIVE && !(reference.dynamicUnbindReference(serviceRef) || reference.staticUnbindReference(serviceRef))) {
							//make quick test - the service reference is not bound to the current component reference
							continue;
						}
						if (serviceRef != null && !isPossibleMatch(reference, serviceRef)) {
							// the service reference is not a possible match. Skipping further checks 
							continue;
						}
						boolean resolved = !reference.isRequiredFor(scp.serviceComponent) || reference.hasProviders(this.serviceReferenceTable);

						if (!resolved && scp.isBuilt()) {
							if (Activator.DEBUG) {
								Activator.log.debug("Resolver.selectNewlyUnsatisfied(): reference '" + reference.reference.name + "' of component '" + scp.name + "' is not resolved", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
							}
							toDispose = true;
							break;
						}
					}
				}
				if (!toDispose) {
					result.removeElementAt(k);
				}
			}
			return result;
		} catch (Throwable e) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, e);
			return new Vector(1);
		}
	}

	private boolean isPossibleMatch(Reference reference, ServiceReference serviceRef) {
		String[] serviceNames = (String[]) serviceRef.getProperty(Constants.OBJECTCLASS);
		boolean hasName = false;
		for (int i = 0; i < serviceNames.length; i++) {
			if (serviceNames[i].equals(reference.interfaceName)) {
				hasName = true;
				break;
			}
		}
		if (!hasName) {
			return false;
		}
		// check target filter
		try {
			Filter filter = FrameworkUtil.createFilter(reference.target);
			if (!filter.match(serviceRef)) {
				return false;
			}
		} catch (InvalidSyntaxException e) {
			return false;
		}
		return true;
	}

	// -- begin *disable* component routines
	/**
	 * Disable list of ComponentDescriptions
	 * 
	 * get all CD+P's from CD:CD+P Map get instances from CD+P:list of instance
	 * (1:n) map
	 * 
	 * Strip out of Map all CD+P's Continue to pull string check each Ref
	 * dependency and continue to pull out CD+P's if they become not eligible
	 * Then call Resolver to re-resolve
	 * 
	 * @param componentDescriptions
	 */
	void disableComponents(Vector componentDescriptions, int deactivateReason) {
		long start = 0l;
		if (Activator.PERF) {
			start = System.currentTimeMillis();
		}

		ServiceComponentProp scp;
		ServiceComponent component;

		Vector removeList = null;

		// Received list of CDs to disable
		if (componentDescriptions != null) {
			for (int i = 0; i < componentDescriptions.size(); i++) {
				// get the first CD
				component = (ServiceComponent) componentDescriptions.elementAt(i);
				component.enabled = false;
				component.setState(Component.STATE_DISABLED);
				if (Activator.DEBUG) {
					Activator.log.debug("Resolver.disableComponents() " + component.name, null); //$NON-NLS-1$
				}

				// then get the list of SCPs for this CD
				Vector scpList = component.componentProps;
				if (scpList != null) {
					for (int iter = 0; iter < scpList.size(); iter++) {
						scp = (ServiceComponentProp) scpList.elementAt(iter);
						if (removeList == null) {
							removeList = new Vector();
						}
						removeList.addElement(scp);
					}
				}
				if (removeList != null) {
					disposeComponentConfigs(removeList, deactivateReason);
					removeList.removeAllElements();
				}
				if (component.componentProps != null) {
					for (int j = 0; j < component.componentProps.size(); j++) {
						scp = (ServiceComponentProp) component.componentProps.elementAt(j);
						scp.setState(Component.STATE_DISPOSED);
					}
					component.componentProps.removeAllElements();
				}
			}
		}

		if (Activator.PERF) {
			start = System.currentTimeMillis() - start;
			Activator.log.info("[DS perf] " + Integer.toString(componentDescriptions.size()) + " Components disabled for " + Long.toString(start) + "ms"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
		}
	}

	public void disposeComponentConfigs(Vector scps, int deactivateReason) {
		// unregister, deactivate, and unbind
		synchronized (syncLock) {
			removeAll(scpEnabled, scps);
		}
		instanceProcess.disposeInstances(scps, deactivateReason);
	}

	// -- end *service listener*

	public void performWork(int workAction, Object workObject) {
		try {
			if (Activator.DEBUG) {
				String work = WORK_TITLES[workAction - 1];
				Activator.log.debug("Resolver.performWork(): " + work + workObject, null); //$NON-NLS-1$
			}
			switch (workAction) {
				case BUILD :
					if (workObject != null) {
						instanceProcess.buildComponents((Vector) workObject, false);
					}
					break;
				case DYNAMICBIND :
					if (workObject != null) {
						Vector toBind = (Vector) workObject;
						synchronized (syncLock) {
							// remove unsatisfied configs
							for (int i = toBind.size() - 1; i >= 0; i--) {
								Reference ref = (Reference) toBind.elementAt(i);
								if (ref.scp.isUnsatisfied()) {
									//System.out.println("--BIND: removing "+ref.scp);
									toBind.removeElementAt(i);
								}
							}
							if (toBind.isEmpty())
								return;
						}
						instanceProcess.dynamicBind(toBind);

					}
					break;
				case DISPOSE :
					if (workObject != null) {
						instanceProcess.disposeInstances((Vector) workObject, ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED);
					}
					break;
			}
		} catch (Throwable e) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, e);
		}
	}

	private Vector selectDynamicBind(Vector scps, ServiceReference serviceReference) {
		try {
			Vector toBind = null;
			for (int i = 0, size = scps.size(); i < size; i++) {
				ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i);
				if (scp.isUnsatisfied()) {
					//do not check disposed components
					continue;
				}
				// if it is not already eligible it will bind with the static
				// scps
				Vector references = scp.references;
				// it is absolutely legal component if it doesn't contains
				// references!
				if (references != null) {
					for (int j = 0; j < references.size(); j++) {
						Reference reference = (Reference) references.elementAt(j);
						if (reference.bindNewReference(serviceReference, true)) {
							if (toBind == null) {
								toBind = new Vector(2);
							}
							toBind.addElement(reference);
						}
					}
				}
			}
			if (toBind != null && Activator.DEBUG) {
				Activator.log.debug("Resolver.selectDynamicBind(): selected = " + toBind.toString(), null); //$NON-NLS-1$
			}
			return toBind;
		} catch (Throwable t) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, t);
			return null;
		}
	}

	private Vector selectStaticUnBind(Vector scpsToCheck, ServiceReference serviceReference, boolean checkSatisfied) {
		try {
			Vector toUnbind = null;
			for (int i = 0, size = scpsToCheck.size(); i < size; i++) {
				ServiceComponentProp scp = (ServiceComponentProp) scpsToCheck.elementAt(i);
				if (scp.isUnsatisfied()) {
					//the scp is already deactivated
					continue;
				}
				// if it is not already eligible it will bind with the static scps
				Vector references = scp.references;
				// it is absolutely legal component if it doesn't contains references!
				if (references != null) {
					for (int j = 0; j < references.size(); j++) {
						Reference reference = (Reference) references.elementAt(j);
						if (reference.staticUnbindReference(serviceReference)) {
							if (checkSatisfied && reference.isInSatisfiedList(serviceReference)) {
								//the service reference do still satisfy the reference and shall not be unbound
								continue;
							}
							if (toUnbind == null) {
								toUnbind = new Vector(2);
							}
							toUnbind.addElement(scp);
						}
					}
				}
			}
			if (toUnbind != null)
				if (Activator.DEBUG) {
					Activator.log.debug("Resolver.selectStaticUnBind(): selected = " + toUnbind.toString(), null); //$NON-NLS-1$
				}
			return toUnbind;
		} catch (Throwable t) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, t);
			return null;
		}
	}

	/**
	 * selectDynamicUnBind Determine which resolved component description with
	 * properties need to unbind from this unregistering service Return map of
	 * reference description and component description with properties, for
	 * each.
	 * 
	 * @param scps
	 * @param serviceReference
	 * @return this is fairly complex to explain ;(
	 */
	private Hashtable selectDynamicUnBind(Vector scps, ServiceReference serviceReference, boolean checkSatisfied) {
		try {
			if (Activator.DEBUG) {
				Activator.log.debug("Resolver.selectDynamicUnBind(): entered", null); //$NON-NLS-1$
			}
			Hashtable unbindTable = null; // ReferenceDescription:subTable
			for (int i = 0; i < scps.size(); i++) {
				Hashtable unbindSubTable = null; // scp:sr
				ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i);

				if (scp.isUnsatisfied()) {
					//do not check deactivated components
					continue;
				}
				Vector references = scp.references;
				// some components may not contain references and it is
				// absolutely valid
				if (references != null) {
					for (int j = 0; j < references.size(); j++) {
						Reference reference = (Reference) references.elementAt(j);
						// Does the scp require this service, use the Reference
						// object to check
						if (reference.dynamicUnbindReference(serviceReference)) {
							if (checkSatisfied && reference.isInSatisfiedList(serviceReference)) {
								//the service reference do still satisfy the reference and shall not be unbound
								continue;
							}
							if (Activator.DEBUG) {
								Activator.log.debug("Resolver.selectDynamicUnBind(): unbinding " + scp.toString(), null); //$NON-NLS-1$
							}
							if (unbindSubTable == null) {
								unbindSubTable = new Hashtable(11);
							}
							unbindSubTable.put(scp, serviceReference);
							if (unbindTable == null) {
								unbindTable = new Hashtable(11);
							}
							unbindTable.put(reference, unbindSubTable);
						} else {
							if (Activator.DEBUG) {
								Activator.log.debug("Resolver.selectDynamicUnBind(): not unbinding " + scp + " service ref=" + serviceReference, null); //$NON-NLS-1$ //$NON-NLS-2$
							}
						}
					}
				}
			}
			if (unbindTable != null && Activator.DEBUG) {
				Activator.log.debug("Resolver.selectDynamicUnBind(): unbindTable is " + unbindTable.toString(), null); //$NON-NLS-1$
			}
			return unbindTable;
		} catch (Throwable t) {
			Activator.log(null, LogService.LOG_ERROR, Messages.UNEXPECTED_EXCEPTION, t);
			return null;
		}
	}

	// used by the ComponentFactoryImpl to build new Component configurations
	public ServiceComponentProp mapNewFactoryComponent(ServiceComponent component, Dictionary configProperties) {
		synchronized (syncLock) {
			// create a new scp (adds to resolver enabledSCPs list)
			ServiceComponentProp newSCP = map(component, configProperties);
			newSCP.setComponentFactory(false); // avoid registration of new
			// ComponentFactory

			// we added a SCP, so check for circularity and mark cycles
			findDependencyCycles();

			// get list of newly satisfied SCPs and check whether the new SCP is
			// satisfied
			Vector eligibleSCPs = resolveEligible();
			if (!eligibleSCPs.contains(newSCP)) {
				removeEnabledSCP(newSCP);
				throw new ComponentException(NLS.bind(Messages.CANT_RESOLVE_COMPONENT_INSTANCE, newSCP, configProperties));
			}
			return newSCP;
		}
	}

	/**
	 * Check through the enabled list for cycles. Cycles can only exist if every
	 * service is provided by a Service Component (not legacy OSGi). If the
	 * cycle has no optional dependencies, log an error and disable a Component
	 * Configuration in the cycle. If cycle can be "broken" by an optional
	 * dependency, make a note (stored in the
	 * {@link ServiceComponentProp#delayActivateSCPNames} Vector).
	 * 
	 * @throws CircularityException
	 *             if cycle exists with no optional dependencies
	 */
	private void findDependencyCycles() {
		Vector emptyVector = new Vector();
		try {
			// find the SCPs that resolve using other SCPs and record their
			// dependencies
			Hashtable dependencies = new Hashtable();

			for (int i = scpEnabled.size() - 1; i >= 0; i--) {
				ServiceComponentProp enabledSCP = (ServiceComponentProp) scpEnabled.elementAt(i);
				if (enabledSCP.references != null) {
					Vector dependencyVector = new Vector(1);
					for (int j = 0; j < enabledSCP.references.size(); j++) {
						Reference reference = (Reference) enabledSCP.references.elementAt(j);

						// see if it resolves to one of the other enabled SCPs
						ServiceComponentProp[] providerSCPs = reference.selectProviders(scpEnabled);
						if (providerSCPs != null) {
							for (int k = 0; k < providerSCPs.length; k++) {
								dependencyVector.addElement(new ReferenceSCPWrapper(reference, providerSCPs[k]));
							}
						}
					} // end for

					if (!dependencyVector.isEmpty()) {
						// SCP resolves using some other SCPs, could be a cycle
						dependencies.put(enabledSCP, dependencyVector);
					} else {
						dependencies.put(enabledSCP, emptyVector);
					}
				}
			} // end for

			// traverse dependency tree and look for cycles
			Hashtable visited = new Hashtable(11);
			Enumeration keys = dependencies.keys();

			while (keys.hasMoreElements()) {
				ServiceComponentProp scp = (ServiceComponentProp) keys.nextElement();
				if (!visited.containsKey(scp)) {
					Vector currentStack = new Vector(2);
					checkDependencies(scp, visited, dependencies, currentStack);
				}
			}
		} catch (CircularityException e) {
			Activator.log(e.getCausingComponent().serviceComponent.bc, LogService.LOG_ERROR, NLS.bind(Messages.CIRCULARITY_EXCEPTION_FOUND, e.getCausingComponent().serviceComponent), e);
			// disable offending SCP
			removeEnabledSCP(e.getCausingComponent());
			// try again
			findDependencyCycles();
		}
	}

	/**
	 * Recursively do a depth-first traversal of a dependency tree, looking for
	 * cycles.
	 * <p>
	 * If a cycle is found, calls
	 * {@link Resolver#processDependencyCycle(ReferenceSCPWrapper, Vector)}.
	 * </p>
	 * 
	 * @param scp
	 *            current node in dependency tree
	 * @param visited
	 *            holdes the visited nodes
	 * @param dependencies
	 *            Dependency tree - a Hashtable of ({@link ServiceComponentProp}):(Vector
	 *            of {@link ReferenceSCPWrapper}s)
	 * @param currentStack
	 *            Vector of {@link ReferenceSCPWrapper}s - the history of our
	 *            traversal so far (the path back to the root of the tree)
	 * @throws CircularityException
	 *             if an cycle with no optional dependencies is found.
	 */
	private void checkDependencies(ServiceComponentProp scp, Hashtable visited, Hashtable dependencies, Vector currentStack) throws CircularityException {

		// the component has already been visited and it's dependencies checked
		// for cycles
		if (visited.containsKey(scp)) {
			return;
		}

		Vector refSCPs = (Vector) dependencies.get(scp);
		if (refSCPs != null) {
			for (int i = 0; i < refSCPs.size(); i++) {
				ReferenceSCPWrapper refSCP = (ReferenceSCPWrapper) refSCPs.elementAt(i);
				if (currentStack.contains(refSCP)) {
					// may throw circularity exception
					processDependencyCycle(refSCP, currentStack);
					continue;
				}
				currentStack.addElement(refSCP);

				checkDependencies(refSCP.producer, visited, dependencies, currentStack);

				currentStack.removeElement(refSCP);
			}
		}
		visited.put(scp, ""); //$NON-NLS-1$
	}

	/**
	 * A cycle was detected. SCP is referenced by the last element in
	 * currentStack. Throws CircularityException if the cycle does not contain
	 * an optional dependency, else choses a point at which to "break" the cycle
	 * (the break point must be immediately after an optional dependency) and
	 * adds a "cycle note".
	 * 
	 * @see ServiceComponentProp#delayActivateSCPNames
	 */
	private void processDependencyCycle(ReferenceSCPWrapper refSCP, Vector currentStack) throws CircularityException {
		// find an optional dependency
		ReferenceSCPWrapper optionalRefSCP = null;
		for (int i = currentStack.indexOf(refSCP); i < currentStack.size(); i++) {
			ReferenceSCPWrapper cycleRefSCP = (ReferenceSCPWrapper) currentStack.elementAt(i);
			if (!cycleRefSCP.ref.isRequired()) {
				optionalRefSCP = cycleRefSCP;
				break;
			}
		}
		if (optionalRefSCP == null) {
			throw new CircularityException(refSCP.ref.scp);
		}
		// check whether the optional reference is static - this is not allowed
		// because of the way components with static refereces are built
		if (optionalRefSCP.ref.policy == ComponentReference.POLICY_STATIC) {
			Activator.log(optionalRefSCP.ref.scp.bc, LogService.LOG_ERROR, NLS.bind(Messages.STATIC_OPTIONAL_REFERENCE_TO_BE_REMOVED, optionalRefSCP.ref.reference), null);

			optionalRefSCP.ref.scp.references.removeElement(optionalRefSCP.ref);
		}

		// the dependent component will be processed with delay whenever
		// necessary
		optionalRefSCP.ref.scp.setDelayActivateSCPName(optionalRefSCP.producer.serviceComponent.name);
	}

	// used to remove all elements of vector which occur in another vector
	private void removeAll(Vector src, Vector elementsToRemove) {
		for (int i = src.size() - 1; i >= 0; i--) {
			if (elementsToRemove.contains(src.elementAt(i))) {
				src.removeElementAt(i);
			}
		}
	}

	private void removeEnabledSCP(ServiceComponentProp scp) {
		scpEnabled.removeElement(scp);
		scp.serviceComponent.componentProps.remove(scp);
		scp.setState(Component.STATE_DISPOSED);
	}

	/**
	 * Reorder the specified SCP and place it at the end of the enabledSCPs list
	 * @param scp the SCP to reorder
	 */
	protected void reorderSCP(ServiceComponentProp scp) {
		synchronized (syncLock) {
			if (scpEnabled.removeElement(scp)) {
				scpEnabled.addElement(scp);
			}
		}
	}

	public void removeFromSatisfiedList(ServiceComponentProp scp) {
		Vector tmp = new Vector();
		tmp.addElement(scp);
		mgr.enqueueWork(this, Resolver.DISPOSE, tmp, false);
	}

	/**
	 * Used to traverse the dependency tree in order to find cycles.
	 * 
	 */
	private static class ReferenceSCPWrapper {
		public Reference ref;
		public ServiceComponentProp producer;

		protected ReferenceSCPWrapper(Reference ref, ServiceComponentProp producer) {
			this.ref = ref;
			this.producer = producer;
		}

		public String toString() {
			return "Reference : " + ref + " ::: SCP : " + producer; //$NON-NLS-1$ //$NON-NLS-2$
		}
	}

	public Component getComponent(long componentId) {
		synchronized (scpEnabled) {
			for (int i = 0; i < scpEnabled.size(); i++) {
				ServiceComponentProp scp = (ServiceComponentProp) scpEnabled.elementAt(i);
				if (scp.getId() == componentId) {
					return scp;
				}
			}
		}
		return null;
	}

}
