diff options
author | sboshev | 2009-04-27 13:57:37 +0000 |
---|---|---|
committer | sboshev | 2009-04-27 13:57:37 +0000 |
commit | 19f95122eb41299dc4aec7e82e45a3293e9ac416 (patch) | |
tree | 144431b9d6995d93f7cc5849c35ad5b827c0fe04 /bundles | |
parent | 26caae2241dbf56f8810d0301509e4e62048faa0 (diff) | |
download | rt.equinox.bundles-19f95122eb41299dc4aec7e82e45a3293e9ac416.tar.gz rt.equinox.bundles-19f95122eb41299dc4aec7e82e45a3293e9ac416.tar.xz rt.equinox.bundles-19f95122eb41299dc4aec7e82e45a3293e9ac416.zip |
Bug 272599. [ds] Add support for new modified attribute on component elementv20090427-1030
Diffstat (limited to 'bundles')
8 files changed, 492 insertions, 74 deletions
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java index 9202128f2..ef0a68fbb 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java @@ -459,7 +459,6 @@ public class InstanceProcess { * the component instance created by ComponentFactoryImpl! */ private void registerService(ServiceComponentProp scp, boolean factory, ComponentInstanceImpl ci) { - // register the service using a ServiceFactory ServiceRegistration reg = null; Object service; @@ -474,18 +473,7 @@ public class InstanceProcess { service = new ServiceReg(scp, ci); } - //remove the private properties from the component properties before registering as service - Hashtable props = scp.getProperties(); - Hashtable publicProps = (Hashtable) props.clone(); - Enumeration keys = props.keys(); - while (keys.hasMoreElements()) { - String key = (String) keys.nextElement(); - if (key.startsWith(".")) { //$NON-NLS-1$ - publicProps.remove(key); - } - } - - reg = scp.bc.registerService(scp.serviceComponent.provides, service, publicProps); + reg = scp.bc.registerService(scp.serviceComponent.provides, service, scp.getPublicServiceProperties()); if (Activator.DEBUG) { Activator.log.debug("InstanceProcess.registerService(): " + scp.name + " registered as " + ((factory) ? "*factory*" : "*service*"), null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ @@ -607,6 +595,37 @@ public class InstanceProcess { } } + public void modifyComponent(ServiceComponentProp scp, Dictionary newProps) throws ComponentException { + if (Activator.DEBUG) { + Activator.log.debug(NLS.bind(Messages.MODIFYING_COMPONENT, scp.name), null); + } + getLock(); + long start = 0l; + try { + if (Activator.PERF) { + start = System.currentTimeMillis(); + Activator.log.info(NLS.bind(Messages.MODIFYING_COMPONENT, scp)); + } + try { + scp.modify(newProps); + } catch (ComponentException e) { + Activator.log.error(e.getMessage(), e.getCause()); + throw e; + } catch (Throwable t) { + Activator.log.error(NLS.bind(Messages.ERROR_MODIFYING_COMPONENT, scp.serviceComponent), t); + throw new ComponentException(NLS.bind(Messages.ERROR_MODIFYING_COMPONENT, scp.serviceComponent), t); + } finally { + // keep track of how many times we have re-entered this method + if (Activator.PERF) { + start = System.currentTimeMillis() - start; + Activator.log.info(NLS.bind(Messages.COMPONENT_MODIFIED_FOR, scp, Long.toString(start))); + } + } + } finally { + freeLock(); + } + } + /** * Acquire a service object from a {@link ServiceReference}. * diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Messages.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Messages.java index c61f5671b..423203165 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Messages.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Messages.java @@ -20,6 +20,7 @@ public class Messages extends NLS { public static String CANNOT_GET_LOGSERVICE; public static String CANNOT_GET_REFERENCES; public static String CANNOT_GET_SERVICE_BECAUSEOF_CIRCULARITY; + public static String CANNOT_MODIFY_INSTANCE__MODIFY_METHOD_NOT_FOUND; public static String CANT_ACTIVATE_INSTANCE; public static String CANT_GET_SERVICE; public static String CANT_GET_SERVICE_OBJECT; @@ -35,6 +36,7 @@ public class Messages extends NLS { public static String COMPONENT_ID_DEFINIED_BY_LIST_COMMAND; public static String COMPONENT_INSTANCE_BUILT; public static String COMPONENT_LACKS_APPROPRIATE_PERMISSIONS; + public static String COMPONENT_MODIFIED_FOR; public static String COMPONENT_NAME; public static String COMPONENT_NAME_IS_NULL; public static String COMPONENT_NOT_FOUND; @@ -81,12 +83,14 @@ public class Messages extends NLS { public static String ERROR_PROCESSING_PROPERTY; public static String ERROR_PROCESSING_START_TAG; public static String ERROR_UNBINDING_REFERENCE; + public static String ERROR_UNBINDING_REFERENCE2; public static String EXCEPTION_ACTIVATING_INSTANCE; public static String EXCEPTION_BUILDING_COMPONENT; public static String EXCEPTION_CREATING_COMPONENT_INSTANCE; public static String EXCEPTION_GETTING_METHOD; public static String EXCEPTION_LOCATING_SERVICE; public static String EXCEPTION_LOCATING_SERVICES; + public static String EXCEPTION_MODIFYING_COMPONENT; public static String EXCEPTION_UNBINDING_REFERENCE; public static String EXPECTED_PARAMETER_COMPONENT_ID; public static String FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY; @@ -130,6 +134,7 @@ public class Messages extends NLS { public static String LOCATED_IN_BUNDLE; public static String METHOD_UNACCESSABLE; public static String MISSING_CHARACTER; + public static String MODIFYING_COMPONENT; public static String NEW_SERVICE_CREATED; public static String NO_BUILT_COMPONENT_CONFIGURATIONS; public static String NO_COMPONENT_INSTANCES; @@ -179,6 +184,7 @@ public class Messages extends NLS { public static String ERROR_READING_OBJECT; public static String DBMANAGER_SERVICE_TRACKER_OPENED; public static String ERROR_LOADING_COMPONENT_DEFINITIONS; + public static String ERROR_MODIFYING_COMPONENT; public static String ERROR_SAVING_COMPONENT_DEFINITIONS; public static String FILE_DOESNT_EXIST_OR_DIRECTORY; static { diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java index 0881ff42d..fbd0b8f54 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1997-2007 by ProSyst Software GmbH + * 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 @@ -12,8 +12,7 @@ *******************************************************************************/ package org.eclipse.equinox.internal.ds; -import java.util.Dictionary; -import java.util.Vector; +import java.util.*; import org.eclipse.equinox.internal.ds.model.*; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; @@ -29,7 +28,6 @@ import org.osgi.service.log.LogService; * @author Valentin Valchev * @author Stoyan Boshev * @author Pavlin Dobrev - * @version 1.1 */ public final class Reference { @@ -112,6 +110,10 @@ public final class Reference { return target; } + public void setTarget(String newTarget) { + target = newTarget; + } + // used in Resolver.resolveEligible() final boolean hasProviders() { // check whether the component's bundle has service GET permission @@ -195,6 +197,91 @@ public final class Reference { return false; } + /** + * Called to determine if the specified new target filter will still satisfy the current state of the reference + * @param newTargetFilter the new target filter to be checked + * @return true if the reference will still be satisfied after the filter replacement + */ + public boolean doSatisfy(String newTargetFilter) { + ServiceReference[] refs = null; + try { + refs = scp.bc.getServiceReferences(reference.interfaceName, newTargetFilter); + } catch (InvalidSyntaxException e) { + Activator.log(scp.bc, LogService.LOG_WARNING, "[SCR] " + NLS.bind(Messages.INVALID_TARGET_FILTER, newTargetFilter), e); //$NON-NLS-1$ + return false; + } + + if (refs == null) { + if (cardinalityLow > 0) { + //the reference is mandatory, but there are no matching services with the new target filter + return false; + } + if (policy == ComponentReference.POLICY_STATIC) { + if (this.reference.bind != null) { + if (this.reference.serviceReferences.size() > 0) { + //have bound services which are not matching the new filter + return false; + } + } else { + //custom case: static reference with no bind method - check its bound service references list + if (boundServiceReferences.size() > 0) { + //have bound services which are not matching the new filter + return false; + } + } + } + //the reference is not mandatory and the dynamic bound services can be unbound + return true; + } + if (policy == ComponentReference.POLICY_STATIC) { + if (this.reference.bind != null) { + Enumeration keys = this.reference.serviceReferences.keys(); + while (keys.hasMoreElements()) { + Object serviceRef = keys.nextElement(); + boolean found = false; + for (int i = 0; i < refs.length; i++) { + if (refs[i] == serviceRef) { + found = true; + break; + } + } + if (!found) { + //the bound service reference is not already in the satisfied references set. + //since this is a static reference a restart of the component is required + return false; + } + } + if (cardinalityHigh > 1 && this.reference.serviceReferences.size() < refs.length) { + //there are more services to bind. this requires restart of the component since the reference is static + return false; + } + } else { + //custom case: static reference with no bind method + for (int i = 0; i < boundServiceReferences.size(); i++) { + Object serviceRef = boundServiceReferences.elementAt(i); + boolean found = false; + for (int j = 0; j < refs.length; j++) { + if (refs[j] == serviceRef) { + found = true; + break; + } + } + if (!found) { + //the bound service reference is not already in the satisfied references set. + //since this is a static reference a restart of the component is required + return false; + } + } + if (cardinalityHigh > 1 && boundServiceReferences.size() < refs.length) { + //there are more services to bind. this requires restart of the component since the reference is static + return false; + } + + } + } + return true; + } + // used in Resolver.selectDynamicUnBind(); final boolean dynamicUnbindReference(ServiceReference changedReference) { // nothing dynamic to do if static @@ -268,6 +355,13 @@ public final class Reference { return res; } + public boolean isBound() { + if (this.reference.bind != null) { + return (this.reference.serviceReferences.size() >= cardinalityLow); + } + return true; + } + public Vector getBoundServiceReferences() { return boundServiceReferences; } diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java index f0409ef06..233bcfb05 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java @@ -15,8 +15,7 @@ import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; -import org.eclipse.equinox.internal.ds.model.ServiceComponent; -import org.eclipse.equinox.internal.ds.model.ServiceComponentProp; +import org.eclipse.equinox.internal.ds.model.*; import org.eclipse.equinox.internal.util.event.Queue; import org.eclipse.equinox.internal.util.ref.Log; import org.eclipse.equinox.internal.util.threadpool.ThreadPoolManager; @@ -24,6 +23,7 @@ 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; @@ -35,7 +35,6 @@ import org.osgi.util.tracker.ServiceTracker; * @author Maria Ivanova * @author Stoyan Boshev * @author Pavlin Dobrev - * @version 1.2 */ public class SCRManager implements ServiceListener, SynchronousBundleListener, ConfigurationListener, WorkPerformer, PrivilegedAction { @@ -348,15 +347,27 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C // 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_MODIFIED); + // there is only one SCP for this SC + boolean requiresRestart = true; + if (sc.namespace11) { + if (sc.componentProps != null && sc.modifyMethodName != "") { //$NON-NLS-1$ + ServiceComponentProp scp = (ServiceComponentProp) sc.componentProps.elementAt(0); + if (scp.getState() > ServiceComponentProp.SATISFIED) { + //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); + // 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 @@ -369,20 +380,29 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C if (scp == null && sc.componentProps != null && sc.componentProps.size() == 1 && (((ServiceComponentProp) sc.componentProps.elementAt(0)).getProperties().get(Constants.SERVICE_PID) == null)) { scp = (ServiceComponentProp) sc.componentProps.elementAt(0); } - // 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); + boolean requiresRestart = true; + if (sc.namespace11 && sc.modifyMethodName != "" && scp != null) { //$NON-NLS-1$ + if (scp.getState() > ServiceComponentProp.SATISFIED) { + //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); + } - // create a new scp (adds to resolver enabledSCPs list) - resolver.map(sc, config[0]); + // 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); + // kick the resolver to figure out if SCP is satisfied, etc + resolver.enableComponents(null); + } } break; @@ -429,6 +449,85 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C } } + /** + * 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) { diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRmessages.properties b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRmessages.properties index b6a48cd04..6f901fb91 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRmessages.properties +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRmessages.properties @@ -14,6 +14,7 @@ CANNOT_GET_CONFIGURATION=[SCR] Cannot get configuration for component {0} CANNOT_GET_LOGSERVICE=Cannot get LogService for bundle {0} CANNOT_GET_REFERENCES=[SCR] Cannot get references for {0} CANNOT_GET_SERVICE_BECAUSEOF_CIRCULARITY=InstanceProcess.getService(): cannot get service because of circularity\! Reference is: {0} ; The service reference is {1} +CANNOT_MODIFY_INSTANCE__MODIFY_METHOD_NOT_FOUND=[SCR] Cannot modify instance {0} of component {1}\! The specified modify method was not found\! CANT_ACTIVATE_INSTANCE=[SCR] Cannot activate instance {0} of component {1} CANT_GET_SERVICE=FactoryReg.getService(): Cannot create instance of {0} CANT_GET_SERVICE_OBJECT=[SCR] Could not get the service object relevant to the reference. A very possible reason is a circularity problem. @@ -29,6 +30,7 @@ COMPONENT_HAS_ILLEGAL_REFERENCE=The component ''{0}'' defined at line {1} contai COMPONENT_ID_DEFINIED_BY_LIST_COMMAND=The ID of the component as displayed by the list command COMPONENT_INSTANCE_BUILT=[DS perf] The instance of component {0} is built for {1}ms COMPONENT_LACKS_APPROPRIATE_PERMISSIONS=Resolver.resolveEligible(): Cannot satisfy component ''{0}'' because its bundle does not have permissions to register service with interface {1} +COMPONENT_MODIFIED_FOR=Component {0} modified for {1}ms COMPONENT_NAME=\t\t\tComponent Name COMPONENT_NAME_IS_NULL=Component name must not be null COMPONENT_NOT_FOUND=component {0} not found in bundle {1} @@ -75,12 +77,14 @@ ERROR_PROCESSING_END_TAG=[SCR] Error occurred while processing end tag of XML '' ERROR_PROCESSING_PROPERTY=[SCR - DeclarationParser.doProperty()] Error while processing property ''{0}'' in XML {1}! ERROR_PROCESSING_START_TAG=[SCR] Error occurred while processing start tag of XML ''{0}'' in bundle {1}! ERROR_UNBINDING_REFERENCE=[SCR] Error while dynamically unbinding reference ''{0}'' of component instance {1} +ERROR_UNBINDING_REFERENCE2=Exception while unbinding reference {0} EXCEPTION_ACTIVATING_INSTANCE=[SCR] Exception while activating instance {0} of component {1} EXCEPTION_BUILDING_COMPONENT=[SCR] Exception occurred while building component configuration of component {0} EXCEPTION_CREATING_COMPONENT_INSTANCE=Exception occurred while creating new instance of component {0} EXCEPTION_GETTING_METHOD=[SCR] Exception occurred while getting method ''{0}'' of class {1} EXCEPTION_LOCATING_SERVICE=Exception occurred while locating service for interface {0} EXCEPTION_LOCATING_SERVICES=Exception occurred while locating services for interface {0} +EXCEPTION_MODIFYING_COMPONENT=[SCR] Exception while modifying instance {0} of component {1} EXCEPTION_UNBINDING_REFERENCE=[SCR] Exception occurred while unbinding reference {0} EXPECTED_PARAMETER_COMPONENT_ID=This command expects a component ID as parameter\! FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY=[SCR - SCRManager] ComponentFactory {0} cannot be managed using factory configuration! @@ -124,6 +128,7 @@ LIST_ALL_COMPONENTS=Lists all components; add -c to display the complete info fo LOCATED_IN_BUNDLE=\t\t\tLocated in bundle METHOD_UNACCESSABLE=[SCR] Method ''{0}'' is not public or protected and cannot be executed! The method is located in the class: {1} MISSING_CHARACTER=Missing character +MODIFYING_COMPONENT=Modifying component {0} NEW_SERVICE_CREATED=FactoryReg.getService(): created new service for component {0} NO_BUILT_COMPONENT_CONFIGURATIONS=\ \ *The component has NO built configurations\! The reason might be that it requires initialization by configuration provided by Configuration Admin but none was found NO_COMPONENT_INSTANCES=InstanceProcess.dynamicBind(): null instances for component {0} @@ -173,5 +178,6 @@ ERROR_WRITING_OBJECT=Error writing object! ERROR_READING_OBJECT=Error reading object! DBMANAGER_SERVICE_TRACKER_OPENED=DBManager service tracker opened for ERROR_LOADING_COMPONENT_DEFINITIONS=Error while loading component's definitions! +ERROR_MODIFYING_COMPONENT=Error modifying component {0} ERROR_SAVING_COMPONENT_DEFINITIONS=Error while saving component's definitions! FILE_DOESNT_EXIST_OR_DIRECTORY=File doesn't exist or is a directory! diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java index e119c99a9..f90c3a4d4 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java @@ -48,7 +48,7 @@ public class DeclarationParser implements ExTagListener { private static final String ATTR_CONF_POLICY = "configuration-policy"; //$NON-NLS-1$ private static final String ATTR_ACTIVATE = "activate"; //$NON-NLS-1$ private static final String ATTR_DEACTIVATE = "deactivate"; //$NON-NLS-1$ - private static final String ATTR_MODIFY = "modify"; //$NON-NLS-1$ + private static final String ATTR_MODIFIED = "modified"; //$NON-NLS-1$ private static final String TAG_IMPLEMENTATION = "implementation"; //$NON-NLS-1$ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ @@ -512,8 +512,8 @@ public class DeclarationParser implements ExTagListener { if (tmp != null) { currentComponent.deactivateMethodName = tmp; } - //processing attribute modify - tmp = tag.getAttribute(ATTR_MODIFY); + //processing attribute modified + tmp = tag.getAttribute(ATTR_MODIFIED); if (tmp != null && tmp.length() == 0) { tmp = null; } @@ -530,8 +530,8 @@ public class DeclarationParser implements ExTagListener { if (tag.getAttribute(ATTR_DEACTIVATE) != null) { throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_0, ATTR_DEACTIVATE, Integer.toString(tag.getLine()))); } - if (tag.getAttribute(ATTR_MODIFY) != null) { - throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_0, ATTR_MODIFY, Integer.toString(tag.getLine()))); + if (tag.getAttribute(ATTR_MODIFIED) != null) { + throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_0, ATTR_MODIFIED, Integer.toString(tag.getLine()))); } } } diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java index ce7366932..57a5d7b01 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.equinox.internal.ds.model; +import org.eclipse.equinox.internal.ds.Messages; + import java.io.*; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -49,7 +51,7 @@ public class ServiceComponent implements Externalizable { String configurationPolicy = CONF_POLICY_OPTIONAL; String activateMethodName = "activate"; //$NON-NLS-1$ String deactivateMethodName = "deactivate"; //$NON-NLS-1$ - String modifyMethodName = "modify"; //$NON-NLS-1$ + public String modifyMethodName = ""; //$NON-NLS-1$ // service public Vector serviceInterfaces; // all strings @@ -243,12 +245,14 @@ public class ServiceComponent implements Externalizable { } } - void modify(Object instance, ComponentContext context) throws ComponentException { + void modified(Object instance, ComponentContext context) throws ComponentException { try { if (namespace11) { if (!modifyCached) { modifyCached = true; - modifyMethod = getMethod(instance, modifyMethodName, true); + if (modifyMethodName != "") { //$NON-NLS-1$ + modifyMethod = getMethod(instance, modifyMethodName, true); + } } // invoke the method if any if (modifyMethod != null) { @@ -277,10 +281,10 @@ public class ServiceComponent implements Externalizable { } } } else { - if (modifyMethodName != "modify") { //$NON-NLS-1$ + if (modifyMethodName != "") { //$NON-NLS-1$ //the modify method is specified in the component description XML by the user. //It is expected to find it in the implementation class - throw new ComponentException(NLS.bind("[SCR] Cannot modify instance {0} of component {1}! The specified modify method was not found!", instance, this)); + throw new ComponentException(NLS.bind(Messages.CANNOT_MODIFY_INSTANCE__MODIFY_METHOD_NOT_FOUND, instance, this)); } } } @@ -288,10 +292,7 @@ public class ServiceComponent implements Externalizable { if (t instanceof ComponentException) { throw (ComponentException) t; } - Activator.log(bc, LogService.LOG_ERROR, NLS.bind("[SCR] Cannot modify instance {0} of component {1}", instance, this), null); - throw new ComponentException(NLS.bind("[SCR] Exception while modifying instance {0} of component {1}", instance, name), t); - // rethrow exception so resolver is eventually notified that - // the processed SCP is bad + Activator.log(bc, LogService.LOG_ERROR, NLS.bind(Messages.EXCEPTION_MODIFYING_COMPONENT, instance, this), t); } } @@ -506,7 +507,7 @@ public class ServiceComponent implements Externalizable { if (namespace11) { buffer.append("\n\tactivate = ").append(activateMethodName); //$NON-NLS-1$ buffer.append("\n\tdeactivate = ").append(deactivateMethodName); //$NON-NLS-1$ - buffer.append("\n\tmodify = ").append(modifyMethodName); //$NON-NLS-1$ + buffer.append("\n\tmodified = ").append(modifyMethodName); //$NON-NLS-1$ buffer.append("\n\tconfiguration-policy = ").append(configurationPolicy); //$NON-NLS-1$ } buffer.append("\n\tfactory = ").append(factory); //$NON-NLS-1$ @@ -600,7 +601,7 @@ public class ServiceComponent implements Externalizable { out.writeBoolean(true); out.writeUTF(deactivateMethodName); } - if (modifyMethodName == "modify") { //$NON-NLS-1$ + if (modifyMethodName == "") { //$NON-NLS-1$ //this is the default value. Do not write it. Just add a mark out.writeBoolean(false); } else { diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java index ed01c6b88..cb131cab1 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1997-2007 by ProSyst Software GmbH + * 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 @@ -36,7 +36,6 @@ import org.osgi.service.log.LogService; * @author Valentin Valchev * @author Stoyan Boshev * @author Pavlin Dobrev - * @version 1.2 */ public class ServiceComponentProp implements PrivilegedExceptionAction { @@ -85,7 +84,7 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { this.name = serviceComponent.name; this.bc = serviceComponent.bc; - initProperties(configProperties); + properties = initProperties(configProperties, null); isComponentFactory = serviceComponent.factory != null; @@ -122,10 +121,10 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { * This method will call the activate method on the specified object. * * @param usingBundle - * the bundle that is using the component - this hase only means + * the bundle that is using the component - this has only means * when the component is factory * @param componentInstance - * the component instance whcich will be activated. + * the component instance which will be activated. * @throws Exception * could be thrown if the activate fails for some reason but NOT * in case, if the instance doesn't define an activate method. @@ -157,6 +156,43 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { } /** + * This method will update the properties of the component + * + * @param newProps + * the new properties + * @throws Exception + * could be thrown if the modify method fails for some reason but NOT + * in case, if the instance doesn't define modify method + */ + public void modify(Dictionary newProps) throws Exception { + if (Activator.DEBUG) { + Activator.log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.modify(): name: " + name, null); //$NON-NLS-1$ + } + Hashtable oldProperties = null; + if (references != null && references.size() > 0) { + oldProperties = (Hashtable) properties.clone(); + } + //1. update the properties + properties = initProperties(newProps, (Long) properties.get(ComponentConstants.COMPONENT_ID)); + //2. call the modify method on the Service Component for all instances of this scp + for (int i = 0; i < instances.size(); i++) { + ComponentInstanceImpl componentInstance = (ComponentInstanceImpl) instances.elementAt(i); + Activator.log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.modify(): instance: " + componentInstance.toString(), null); //$NON-NLS-1$ + serviceComponent.modified(componentInstance.getInstance(), componentInstance.getComponentContext()); + } + //3. modify the bound services if necessary + if (oldProperties != null) { + handleBoundServicesUpdate(oldProperties, properties); + } + + //4. if the component configuration is registered as a service, + // modify the service’s service properties + if (registration != null) { + registration.setProperties(getPublicServiceProperties()); + } + } + + /** * Call the bind method for each of the Referenced Services in this Service * Component * @@ -165,16 +201,15 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { * @throws Exception */ public boolean bind(ComponentInstance componentInstance) throws Exception { - // Get all the required service Reference Descriptions for this Service - // Component + // Get all the required service Reference Descriptions for this ServiceComponent // call the Bind method if the Reference Description includes one if (references != null) { for (int i = 0; i < references.size(); i++) { Reference ref = (Reference) references.elementAt(i); if (ref.reference.bind != null) { bindReference(ref, componentInstance); - if (ref.reference.bindMethod == null) { - //the bind method is not found and called for some reason + if (ref.reference.bindMethod == null || !ref.isBound()) { + //the bind method is not found and called for some reason or it has thrown exception if (ref.reference.cardinality == ComponentReference.CARDINALITY_1_1 || ref.reference.cardinality == ComponentReference.CARDINALITY_1_N) { //unbind the already bound references for (int j = i - 1; j >= 0; j--) { @@ -400,6 +435,143 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { } /** + * Handles the update of the bound services in case the target properties have changed + * @param oldProps the old component properties + * @param newProps the new component properties + */ + private void handleBoundServicesUpdate(Hashtable oldProps, Dictionary newProps) { + Enumeration keys = oldProps.keys(); + Vector checkedFilters = new Vector(); + //check for changed target filters in the properties + while (keys.hasMoreElements()) { + 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$ + 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 && reference.reference.policy == ComponentReference.POLICY_DYNAMIC) { + if (newFilter != null) { + if (!newFilter.equals(oldProps.get(key))) { + //the filter differs the old one - update the reference bound services + processReferenceBoundServices(reference, newFilter); + } + } else { + //the target filter is removed. using the default one + processReferenceBoundServices(reference, "(objectClass=" + reference.reference.interfaceName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + } + //now check for newly added target filters + keys = newProps.keys(); + while (keys.hasMoreElements()) { + 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$ + 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 && reference.reference.policy == ComponentReference.POLICY_DYNAMIC) { + processReferenceBoundServices(reference, (String) newProps.get(key)); + } + } + } + } + + private void processReferenceBoundServices(Reference reference, String newTargetFilter) { + reference.setTarget(newTargetFilter); + ServiceReference[] refs = null; + try { + refs = bc.getServiceReferences(reference.reference.interfaceName, newTargetFilter); + } catch (InvalidSyntaxException e) { + Activator.log(bc, LogService.LOG_WARNING, "[SCR] " + NLS.bind(Messages.INVALID_TARGET_FILTER, newTargetFilter), e); //$NON-NLS-1$ + return; + } + + if (refs == null) { + //must remove all currently bound services + if (reference.reference.bind != null) { + if (reference.reference.serviceReferences.size() > 0) { + for (int i = 0; i < instances.size(); i++) { + ComponentInstance componentInstance = (ComponentInstance) instances.elementAt(i); + unbindReference(reference, componentInstance); + } + } + } + } else { + //find out which services has to be bound and which unbound + if (reference.reference.bind != null) { + Vector servicesToUnbind = new Vector(); + Enumeration keys = reference.reference.serviceReferences.keys(); + while (keys.hasMoreElements()) { + Object serviceRef = keys.nextElement(); + boolean found = false; + for (int i = 0; i < refs.length; i++) { + if (refs[i] == serviceRef) { + found = true; + break; + } + } + if (!found) { + //the bound service reference is not already in the satisfied references set. + servicesToUnbind.addElement(serviceRef); + } + } + if ((reference.reference.cardinality == ComponentReference.CARDINALITY_0_N || reference.reference.cardinality == ComponentReference.CARDINALITY_1_N) && (reference.reference.serviceReferences.size() - servicesToUnbind.size()) < refs.length) { + //there are more services to bind + for (int i = 0; i < refs.length; i++) { + keys = reference.reference.serviceReferences.keys(); + boolean found = false; + while (keys.hasMoreElements()) { + Object serviceRef = keys.nextElement(); + if (serviceRef == refs[i]) { + found = true; + break; + } + } + if (!found) { + for (int j = 0; j < instances.size(); j++) { + ComponentInstance componentInstance = (ComponentInstance) instances.elementAt(j); + try { + reference.reference.bind(reference, componentInstance, refs[i]); + } catch (Exception e) { + Activator.log.error(NLS.bind(Messages.ERROR_BINDING_REFERENCE, reference), e); + } + } + } + } + } + //finally unbind all services that do not match the target filter + for (int i = 0; i < servicesToUnbind.size(); i++) { + for (int j = 0; j < instances.size(); j++) { + ComponentInstance componentInstance = (ComponentInstance) instances.elementAt(j); + try { + unbindDynamicReference(reference, componentInstance, (ServiceReference) servicesToUnbind.elementAt(i)); + } catch (Exception e) { + Activator.log.error(NLS.bind(Messages.ERROR_UNBINDING_REFERENCE2, reference), e); + } + } + } + } + } + } + + /** * Call the unbind method for this Reference Description * * @param reference @@ -456,17 +628,20 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { * * @param configProperties * the configuration properties + * @param componentId specifies the component ID. If null, a new one will be generated + * @return the fully initialized properties */ - private void initProperties(Dictionary configProperties) { + private Hashtable initProperties(Dictionary configProperties, Long componentId) { + Hashtable result = null; // default component service properties Properties propertyDescriptions = serviceComponent.properties; if (propertyDescriptions != null && !propertyDescriptions.isEmpty()) { - properties = (Hashtable) propertyDescriptions.clone(); + result = (Hashtable) propertyDescriptions.clone(); } // set the component.name - if (properties == null) { - properties = new Hashtable(7); + if (result == null) { + result = new Hashtable(7); } // put the references in the properties @@ -475,7 +650,7 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { for (int i = 0; i < serviceComponent.references.size(); i++) { ref = (ComponentReference) serviceComponent.references.elementAt(i); if (ref.target != null) { - properties.put(ref.name + ComponentConstants.REFERENCE_TARGET_SUFFIX, ref.target); + result.put(ref.name + ComponentConstants.REFERENCE_TARGET_SUFFIX, ref.target); } } } @@ -485,20 +660,21 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { for (Enumeration keys = configProperties.keys(); keys.hasMoreElements();) { Object key = keys.nextElement(); Object val = configProperties.get(key); - properties.put(key, val); + result.put(key, val); } } // always set the component name & the id - Long nextId = new Long(getNewComponentID()); - properties.put(ComponentConstants.COMPONENT_ID, nextId); - properties.put(ComponentConstants.COMPONENT_NAME, serviceComponent.name); + Long nextId = (componentId == null) ? new Long(getNewComponentID()) : componentId; + result.put(ComponentConstants.COMPONENT_ID, nextId); + result.put(ComponentConstants.COMPONENT_NAME, serviceComponent.name); if (serviceComponent.provides != null) { String[] provides = new String[serviceComponent.provides.length]; System.arraycopy(serviceComponent.provides, 0, provides, 0, provides.length); - properties.put(Constants.OBJECTCLASS, provides); + result.put(Constants.OBJECTCLASS, provides); } + return result; } private void assertCreateSingleInstance() { @@ -516,6 +692,23 @@ public class ServiceComponentProp implements PrivilegedExceptionAction { } /** + * Removes the private properties and returns the public properties that are set to the registered service provided by this component + * @return the public properties used in the registration of the service which is provided by this component + */ + public Hashtable getPublicServiceProperties() { + //remove the private properties from the component properties before registering as service + Hashtable publicProps = (Hashtable) properties.clone(); + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + if (key.startsWith(".")) { //$NON-NLS-1$ + publicProps.remove(key); + } + } + return publicProps; + } + + /** * Add a new Component Configuration name we should not activate in order to * prevent a cycle. * |