blob: 836e8a967d915c0b65db16b1d529fe7a92f3607d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.ds.instance;
import java.io.IOException;
import java.util.*;
import org.eclipse.equinox.ds.Activator;
import org.eclipse.equinox.ds.Log;
import org.eclipse.equinox.ds.model.ComponentDescription;
import org.eclipse.equinox.ds.model.ComponentDescriptionProp;
import org.eclipse.equinox.ds.resolver.Reference;
import org.eclipse.equinox.ds.service.ComponentFactoryImpl;
import org.eclipse.equinox.ds.service.ComponentInstanceImpl;
import org.eclipse.equinox.ds.workqueue.WorkQueue;
import org.osgi.framework.*;
import org.osgi.service.cm.*;
import org.osgi.service.component.ComponentException;
import org.osgi.service.component.ComponentFactory;
/**
* Register services for satisfied Component Configurations and listen for
* configuration changes from ConfigAdmin
*
*/
public class InstanceProcess implements ConfigurationListener {
/* set this to true to compile in debug messages */
private static final boolean DEBUG = false;
/** Main SCR class */
private Activator main;
/* Actually does the work of building and disposing of instances */
public BuildDispose buildDispose;
protected WorkQueue workQueue;
//configListener service registered by this class
private ServiceRegistration configListener;
/**
* Handle Instance processing
*
* @param main - the Main class of the SCR
*/
public InstanceProcess(Activator main) {
this.main = main;
// use Main's workqueue
workQueue = main.workQueue;
buildDispose = new BuildDispose(main);
configListener = main.context.registerService(ConfigurationListener.class.getName(), this, null);
}
/**
* dispose cleanup, the SCR is shutting down
*/
public void dispose() {
if (configListener != null) {
main.context.ungetService(configListener.getReference());
}
buildDispose.dispose();
buildDispose = null;
main = null;
workQueue = null;
}
/**
* Register and possibly activate Component Configurations.
*
* Activate each Service Component that has the attribute immediate=true.
*
* If Service Component has a service element, register the service or
* service factory.
*
* If Service Component has the factory attribute set, register a
* {@link org.osgi.service.component.ComponentFactory}.
*
* @param componentDescriptionProps - List of satisfied Component Configurations
*/
public void registerComponentConfigs(List componentDescriptionProps) {
ComponentDescriptionProp cdp;
ComponentDescription cd;
String factoryPid = null;
// loop through CD+P list
Iterator it = componentDescriptionProps.iterator();
while (it.hasNext()) {
cdp = (ComponentDescriptionProp) it.next();
cd = cdp.getComponentDescription();
if (DEBUG)
System.out.println("InstanceProcess: buildInstances: component name = " + cd.getName());
// if component is immediate - create instance immediately
if (cd.isImmediate()) {
try {
buildDispose.buildComponentConfigInstance(null, cdp);
} catch (ComponentException e) {
Log.log(1, "[SCR] Error attempting to build Component.", e);
}
}
// ComponentFactory
if (cdp.isComponentFactory()) {
if (DEBUG)
System.out.println("InstanceProcess: buildInstances: ComponentFactory");
// check if MSF
ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) main.resolver.configAdminTracker.getService();
if (configurationAdmin != null) {
try {
Configuration config = configurationAdmin.getConfiguration(cd.getName());
if (config != null)
factoryPid = config.getFactoryPid();
} catch (IOException e) {
Log.log(1, "[SCR] Error attempting to create componentFactory. ", e);
}
}
// if MSF throw exception - can't be ComponentFactory and
// MSF
if (factoryPid != null) {
throw new org.osgi.service.component.ComponentException("ManagedServiceFactory and ConfigurationFactory are incompatible");
}
// if the factory attribute is set on the component element
// then register a component factory service
// for the Service Component on behalf of the Service
// Component.
cdp.setServiceRegistration(cd.getBundleContext().registerService(ComponentFactory.class.getName(), new ComponentFactoryImpl(cdp, main), cdp.getProperties()));
// if ServiceFactory or Service
} else if (cd.getService() != null) {
RegisterComponentService.registerService(this, cdp);
}
}// end while(more componentDescriptionProps)
}
/**
*
* Dispose of Component Configurations
*
* @param componentDescriptionProps - list of Component Configurations to be
* disposed
*/
public void disposeComponentConfigs(List componentDescriptionProps) {
// loop through CD+P list to be disposed
Iterator it = componentDescriptionProps.iterator();
while (it.hasNext()) {
ComponentDescriptionProp cdp = (ComponentDescriptionProp) it.next();
// dispose component
buildDispose.disposeComponentConfig(cdp);
}
}
/**
* Dynamically bind references.
*
* @param references List of {@link Reference}s to dynamically bind
*/
public void dynamicBind(List references) {
Iterator it = references.iterator();
while (it.hasNext()) {
Reference reference = (Reference) it.next();
List instances = reference.getComponentDescriptionProp().getInstances();
Iterator it2 = instances.iterator();
while (it2.hasNext()) {
ComponentInstanceImpl compInstance = (ComponentInstanceImpl) it2.next();
buildDispose.bindReference(reference, compInstance);
}
}
}
/**
* Dynamically unbind references.
*
* @param unbindJobs Map of {@link Reference}:{@link ServiceReference}
* to be unbound
*/
public void dynamicUnBind(Map unbindJobs) {
// for each unbind job
Iterator itr = unbindJobs.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry unbindJob = (Map.Entry) itr.next();
Reference reference = (Reference) unbindJob.getKey();
ComponentDescriptionProp cdp = reference.getComponentDescriptionProp();
ServiceReference serviceReference = (ServiceReference) unbindJob.getValue();
// get the list of instances created
List instances = cdp.getInstances();
Iterator it = instances.iterator();
while (it.hasNext()) {
ComponentInstanceImpl compInstance = (ComponentInstanceImpl) it.next();
Object instance = compInstance.getInstance();
if (instance != null) {
try {
buildDispose.unbindDynamicReference(reference, compInstance, serviceReference);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// all instances are now unbound
reference.removeServiceReference(serviceReference);
}
}
/**
* Listen for configuration changes
*
* Service Components can receive properties from the Configuration Admin
* service. If a Component Configuration 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
*
* @see ConfigurationListener#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
*/
public void configurationEvent(ConfigurationEvent event) {
Configuration[] config = null;
String pid = event.getPid();
if (DEBUG)
System.out.println("pid = " + pid);
String fpid = event.getFactoryPid();
if (DEBUG)
System.out.println("fpid = " + fpid);
//See if this configuration event is for declarative services
ComponentDescription cd;
if (fpid != null) {
// find the fpid == component name in the CD list
cd = (ComponentDescription) main.resolver.enabledCDsByName.get(fpid);
} else {
// find the spid == component name in the CD list
cd = (ComponentDescription) main.resolver.enabledCDsByName.get(pid);
}
if (cd == null) {
//this configuration event has nothing to do with declarative services
return;
}
switch (event.getType()) {
case ConfigurationEvent.CM_UPDATED :
String filter = (fpid != null ? "(&" : "") + "(" + Constants.SERVICE_PID + "=" + pid + ")" + (fpid != null ? ("(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + fpid + "))") : "");
// Get the config for this service.pid
ConfigurationAdmin cm = (ConfigurationAdmin) main.resolver.configAdminTracker.getService();
try {
config = cm.listConfigurations(filter);
} catch (IOException e) {
Log.log(1, "[SCR] Error attempting to list CM Configurations ", e);
} catch (InvalidSyntaxException e) {
Log.log(1, "[SCR] Error attempting to list CM Configurations ", e);
}
// if NOT a factory
if (fpid == null) {
// there is only one CDP for this CD, so we can disable the
// CD
main.resolver.disableComponents(Collections.singletonList(cd));
// now re-enable the CD - the resolver will pick up the new
// config
workQueue.enqueueWork(main, Activator.ADD, Collections.singletonList(cd));
// If a MSF
// create a new CDP or update an existing one
} else {
// get cdp with this PID
ComponentDescriptionProp cdp = cd.getComponentDescriptionPropByPID(pid);
// if only the no-props cdp exists, replace it
if (cdp == null && cd.getComponentDescriptionProps().size() == 1 && ((ComponentDescriptionProp) cd.getComponentDescriptionProps().get(0)).getProperties().get(Constants.SERVICE_PID) == null) {
cdp = (ComponentDescriptionProp) cd.getComponentDescriptionProps().get(0);
}
// if old cdp exists, dispose of it
if (cdp != null) {
// config already exists - dispose of it
cd.removeComponentDescriptionProp(cdp);
main.resolver.disposeComponentConfigs(Collections.singletonList(cdp));
}
// create a new cdp (adds to resolver enabledCDPs list)
main.resolver.map(cd, config[0].getProperties());
// kick the resolver to figure out if CDP is satisfied, etc
workQueue.enqueueWork(main, Activator.ADD, Collections.EMPTY_LIST);
}
break;
case ConfigurationEvent.CM_DELETED :
// if not a factory
if (fpid == null) {
// there is only one CDP for this CD, so we can disable the
// CD
main.resolver.disableComponents(Collections.singletonList(cd));
// now re-enable the CD - the resolver will create CDP with
// no
// configAdmin properties
workQueue.enqueueWork(main, Activator.ADD, Collections.singletonList(cd));
} else {
// config is a factory
// get CDP created for this config (with this PID)
ComponentDescriptionProp cdp = cd.getComponentDescriptionPropByPID(pid);
// if this was the last CDP created for this factory
if (cd.getComponentDescriptionProps().size() == 1) {
// there is only one CDP for this CD, so we can disable
// the CD
main.resolver.disableComponents(Collections.singletonList(cd));
// now re-enable the CD - the resolver will create CDP
// with no
// configAdmin properties
workQueue.enqueueWork(main, Activator.ADD, Collections.singletonList(cd));
} else {
// we can just dispose this CDP
cd.removeComponentDescriptionProp(cdp);
disposeComponentConfigs(Collections.singletonList(cdp));
main.resolver.satisfiedCDPs.remove(cdp);
main.resolver.enabledCDPs.remove(cdp);
}
}
break;
}
}
}