diff options
author | Stoyan Boshev | 2012-01-10 13:36:50 +0000 |
---|---|---|
committer | Stoyan Boshev | 2012-01-10 13:36:50 +0000 |
commit | 6c0ac46a5c1824eef44ae09d3c2d35a791e5d21e (patch) | |
tree | 39d6ce140eb28a97a4e6823153c45215abee199f /bundles/org.eclipse.equinox.ds | |
parent | bafee66a1833f49fc24a3096af383a1e65ef77b2 (diff) | |
download | rt.equinox.bundles-6c0ac46a5c1824eef44ae09d3c2d35a791e5d21e.tar.gz rt.equinox.bundles-6c0ac46a5c1824eef44ae09d3c2d35a791e5d21e.tar.xz rt.equinox.bundles-6c0ac46a5c1824eef44ae09d3c2d35a791e5d21e.zip |
Bug 358108. [ds] Implement new functionality for R4.3 compendium (RFC
176)
Diffstat (limited to 'bundles/org.eclipse.equinox.ds')
13 files changed, 571 insertions, 120 deletions
diff --git a/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF index bfc36b796..9abad8126 100644 --- a/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %bundleName Bundle-SymbolicName: org.eclipse.equinox.ds;singleton:=true -Bundle-Version: 1.3.100.qualifier +Bundle-Version: 1.4.0.qualifier Bundle-Vendor: %bundleVendor Bundle-Activator: org.eclipse.equinox.internal.ds.Activator Bundle-Description: This bundle provides support for OSGi 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 09c9e90d3..81e77624a 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 @@ -227,12 +227,12 @@ public class InstanceProcess { // check if MSF try { - Configuration config = Activator.getConfiguration(sc.name); + Configuration config = Activator.getConfiguration(sc.getConfigurationPID()); if (config != null) { factoryPid = config.getFactoryPid(); } } catch (Exception e) { - Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.CANNOT_GET_CONFIGURATION, sc.name), e); + Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.CANNOT_GET_CONFIGURATION, sc.getConfigurationPID()), e); } // if MSF throw exception - can't be @@ -478,6 +478,37 @@ public class InstanceProcess { } /** + * Called by dispatcher ( Resolver) when service properties have been modified for some reference + * + * @param serviceReferenceTable Map of <Reference>:<Map of <ServiceComponentProp>:<ServiceReference>> + */ + final void referencePropertiesUpdated(Hashtable serviceReferenceTable) { + // for each element in the table + Enumeration e = serviceReferenceTable.keys(); + while (e.hasMoreElements()) { + Reference ref = (Reference) e.nextElement(); + Hashtable serviceSubTable = (Hashtable) serviceReferenceTable.get(ref); + Enumeration sub = serviceSubTable.keys(); + while (sub.hasMoreElements()) { + ServiceComponentProp scp = (ServiceComponentProp) sub.nextElement(); + ServiceReference serviceReference = (ServiceReference) serviceSubTable.get(scp); + // get the list of instances created + Vector instances = scp.instances; + for (int i = 0; i < instances.size(); i++) { + ComponentInstance compInstance = (ComponentInstance) instances.elementAt(i); + if (compInstance != null) { + try { + scp.updatedReference(ref, compInstance, serviceReference); + } catch (Throwable t) { + Activator.log(null, LogService.LOG_ERROR, NLS.bind(Messages.ERROR_UPDATING_REFERENCE, ref.reference, compInstance.getInstance()), t); + } + } + } + } + } + } + + /** * registerService * * @param scp 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 bbc3c0e01..2e7d6d503 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 @@ -18,6 +18,8 @@ public class Messages extends NLS { public static String ALL_COMPONENTS; public static String ALL_REFERENCES_RESOLVED; public static String BIND_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE; + public static String UPDATED_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE; + public static String UPDATED_METHOD_NOT_CALLED; public static String BUNDLE_NOT_FOUND; public static String CANNOT_BUILD_COMPONENT; public static String CANNOT_CREATE_INSTANCE; @@ -63,6 +65,7 @@ public class Messages extends NLS { public static String ENABLING_ALL_BUNDLE_COMPONENTS; public static String ENABLING_ALL_COMPONENTS; public static String ERROR_BINDING_REFERENCE; + public static String ERROR_UPDATING_REFERENCE; public static String ERROR_BUILDING_COMPONENT_INSTANCE; public static String ERROR_CREATING_SCP; public static String ERROR_DEACTIVATING_INSTANCE; @@ -112,6 +115,7 @@ public class Messages extends NLS { public static String INVALID_COMPONENT_TAG__NO_CLASS_ATTR; public static String INVALID_OBJECT; public static String INVALID_POLICY_ATTR; + public static String INVALID_POLICY_OPTION_ATTR; public static String INVALID_PROPERTIES_TAG__INVALID_ENTRY_VALUE; public static String INVALID_PROPERTIES_TAG__NO_ENTRY_ATTR; public static String INVALID_PROPERTY_TAG__NO_BODY_CONTENT; @@ -121,9 +125,11 @@ public class Messages extends NLS { public static String INVALID_REFERENCE_TAG__BIND_ATTR_EMPTY; public static String INVALID_REFERENCE_TAG__BIND_EQUALS_UNBIND; public static String INVALID_REFERENCE_TAG__UNBIND_ATTR_EMPTY; + public static String INVALID_REFERENCE_TAG__UPDATED_ATTR_EMPTY; public static String INVALID_SERVICE_REFERENCE; public static String INVALID_SERVICE_TAG__NO_PROVIDE_TAG; public static String INVALID_TAG_ACCORDING_TO_NAMESPACE1_0; + public static String INVALID_TAG_ACCORDING_TO_NAMESPACE1_2; public static String INVALID_TARGET_FILTER; public static String LIST_ALL_BUNDLE_COMPONENTS; public static String LIST_ALL_COMPONENTS; 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 c38adb807..0e6148354 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 @@ -30,10 +30,6 @@ import org.osgi.service.log.LogService; * @author Stoyan Boshev * @author Pavlin Dobrev */ -/** - * @author stoyan - * - */ public final class Reference implements org.apache.felix.scr.Reference { public ComponentReference reference; @@ -98,7 +94,7 @@ public final class Reference implements org.apache.felix.scr.Reference { break; case ComponentReference.CARDINALITY_0_N : cardinalityLow = 0; - cardinalityHigh = 999999999; + cardinalityHigh = Integer.MAX_VALUE; break; case ComponentReference.CARDINALITY_1_1 : cardinalityLow = 1; @@ -106,7 +102,7 @@ public final class Reference implements org.apache.felix.scr.Reference { break; case ComponentReference.CARDINALITY_1_N : cardinalityLow = 1; - cardinalityHigh = 999999999; + cardinalityHigh = Integer.MAX_VALUE; } } @@ -174,7 +170,11 @@ public final class Reference implements org.apache.felix.scr.Reference { if (policy == ComponentReference.POLICY_DYNAMIC) { return false; } + if (this.reference.policy_option == ComponentReference.POLICY_OPTION_RELUCTANT) { + return false; + } } + String[] serviceNames = (String[]) referenceToBind.getProperty(Constants.OBJECTCLASS); boolean hasName = false; for (int i = 0; i < serviceNames.length; i++) { @@ -186,16 +186,36 @@ public final class Reference implements org.apache.felix.scr.Reference { if (!hasName) { return false; } + if (this.reference.bind != null) { if (this.reference.serviceReferences.size() >= cardinalityHigh) { - return false; + if (this.reference.policy_option == ComponentReference.POLICY_OPTION_RELUCTANT) { + return false; + } else if (this.reference.policy_option == ComponentReference.POLICY_OPTION_GREEDY) { + //check if the single bound service needs replacement with higher ranked service + Object currentBoundServiceReference = this.reference.serviceReferences.keys().nextElement(); + int res = referenceToBind.compareTo(currentBoundServiceReference); + if (res <= 0) { + // bound service shall not be replaced + return false; + } + } } } else if (!dynamicBind) { //custom case: static reference with no bind method - check its bound service references list if (boundServiceReferences.size() >= cardinalityHigh) { - return false; + if (this.reference.policy_option == ComponentReference.POLICY_OPTION_GREEDY) { + //check if the single bound service needs replacement with higher ranked service + Object currentBoundServiceReference = boundServiceReferences.elementAt(0); + int res = referenceToBind.compareTo(currentBoundServiceReference); + if (res <= 0) { + // bound service shall not be replaced + return false; + } + } } } + // check target filter try { Filter filter = FrameworkUtil.createFilter(target); @@ -464,7 +484,9 @@ public final class Reference implements org.apache.felix.scr.Reference { * @see org.apache.felix.scr.Reference#getUpdatedMethodName() */ public String getUpdatedMethodName() { - // DS specification does not specify this method yet + if (reference.component.isNamespaceAtLeast12()) { + return reference.updated; + } return null; } diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java index cdcb43faa..1d6bdfbf0 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java @@ -159,7 +159,7 @@ public final class Resolver implements WorkPerformer { // 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$ + String filter = "(|(" + Constants.SERVICE_PID + '=' + current.getConfigurationPID() + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID + '=' + current.getConfigurationPID() + "))"; //$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); @@ -178,7 +178,7 @@ public final class Resolver implements WorkPerformer { } else { // if ManagedServiceFactory Configuration config = configs[0]; - if (config.getFactoryPid() != null && config.getFactoryPid().equals(current.name)) { + if (config.getFactoryPid() != null && config.getFactoryPid().equals(current.getConfigurationPID())) { // 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); @@ -305,11 +305,22 @@ public final class Resolver implements WorkPerformer { 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 + //check for any static references with policy option "greedy" that need to be bound with this service reference + target = selectStaticBind(scpEnabled, event.getServiceReference()); + } + + if (target != null) { + //dispose instances of components with static reference that needs to be bound with the service reference + instanceProcess.disposeInstances((Vector) target, ComponentConstants.DEACTIVATION_REASON_REFERENCE); + } + + synchronized (syncLock) { resolvedComponents = getComponentsToBuild(); target = selectDynamicBind(scpEnabled, event.getServiceReference()); } @@ -393,18 +404,35 @@ public final class Resolver implements WorkPerformer { } if (componentsToDispose != null) { - instanceProcess.disposeInstances(componentsToDispose, ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED); + instanceProcess.disposeInstances(componentsToDispose, ComponentConstants.DEACTIVATION_REASON_REFERENCE); } synchronized (syncLock) { + //check for any static references with policy option "greedy" that need to be bound with this service reference + componentsToDispose = selectStaticBind(scpEnabled, event.getServiceReference()); + } + + if (componentsToDispose != null) { + //dispose instances of components with static reference that needs to be bound with the modified service reference + instanceProcess.disposeInstances(componentsToDispose, ComponentConstants.DEACTIVATION_REASON_REFERENCE); + } + + Hashtable referencesToUpdate = null; + synchronized (syncLock) { // dynamic unbind // check each satisfied scp - do we need to unbind target = selectDynamicUnBind(scpEnabled, event.getServiceReference(), true); + + //check references that need to be updated + referencesToUpdate = selectReferencesToUpdate(scpEnabled, event.getServiceReference()); } if (target != null) { instanceProcess.dynamicUnBind((Hashtable) target); } + if (referencesToUpdate != null) { + instanceProcess.referencePropertiesUpdated(referencesToUpdate); + } synchronized (syncLock) { // dynamic bind @@ -765,6 +793,52 @@ public final class Resolver implements WorkPerformer { } } + //Returns the components with static reference that needs to be bound with the service reference. + //This can happen if the static reference has policy option "greedy" + private Vector selectStaticBind(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; + } + Vector references = scp.references; + if (references != null) { + for (int j = 0; j < references.size(); j++) { + Reference reference = (Reference) references.elementAt(j); + if (reference.bindNewReference(serviceReference, false)) { + if (toBind == null) { + toBind = new Vector(2); + } + toBind.addElement(reference); + } + } + } + } + Vector result = null; + Reference ref = null; + if (toBind != null) { + result = new Vector(); + for (int i = 0; i < toBind.size(); i++) { + ref = (Reference) toBind.elementAt(i); + if (!result.contains(ref.scp)) { + result.addElement(ref.scp); + } + } + } + + if (result != null && Activator.DEBUG) { + Activator.log.debug("Resolver.selectStaticBind(): selected = " + result.toString(), null); //$NON-NLS-1$ + } + return result; + } 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; @@ -870,6 +944,62 @@ public final class Resolver implements WorkPerformer { } } + /** + * Determine which component references needs to be updated by their specified updated method due to the current service references properties change + * + * @param scps + * @param serviceReference + * @return Map of <Reference>:<Map of <ServiceComponentProp>:<ServiceReference>> + * + */ + private Hashtable selectReferencesToUpdate(Vector scps, ServiceReference serviceReference) { + try { + if (Activator.DEBUG) { + Activator.log.debug("Resolver.selectReferencesToUpdate(): entered", null); //$NON-NLS-1$ + } + Hashtable referencesTable = null; + for (int i = 0; i < scps.size(); i++) { + Hashtable updateSubTable = null; + ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i); + + if (scp.isUnsatisfied() || !scp.serviceComponent.isNamespaceAtLeast12()) { + //do not check deactivated components or components which are not DS 1.2 compliant + continue; + } + Vector references = scp.references; + if (references != null) { + for (int j = 0; j < references.size(); j++) { + Reference reference = (Reference) references.elementAt(j); + if (reference.reference.updated == null) { + //the reference does not have updated method specified + continue; + } + if (reference.isStatic() ? reference.staticUnbindReference(serviceReference) : reference.dynamicUnbindReference(serviceReference)) { + if (Activator.DEBUG) { + Activator.log.debug("Resolver.selectReferencesToUpdate(): selected for update reference " + reference.reference.name + " of component " + scp.toString(), null); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (updateSubTable == null) { + updateSubTable = new Hashtable(11); + } + updateSubTable.put(scp, serviceReference); + if (referencesTable == null) { + referencesTable = new Hashtable(11); + } + referencesTable.put(reference, updateSubTable); + } + } + } + } + if (referencesTable != null && Activator.DEBUG) { + Activator.log.debug("Resolver.selectReferencesToUpdate(): referencesTable is " + referencesTable.toString(), null); //$NON-NLS-1$ + } + return referencesTable; + } 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) { 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 6ca9b2dfd..df693868a 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 @@ -289,10 +289,10 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C //skip processing of this component - it is not interested in configuration changes continue; } - String name = sc.name; + String name = sc.getConfigurationPID(); if (name.equals(pid) || name.equals(fpid)) { if (name.equals(fpid) && sc.factory != null) { - Activator.log(sc.bc, LogService.LOG_ERROR, NLS.bind(Messages.FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY, name), null); + Activator.log(sc.bc, LogService.LOG_ERROR, NLS.bind(Messages.FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY, sc.name), null); return; } if (sc.enabled) { @@ -344,7 +344,7 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C if (fpid == null) { // there is only one SCP for this SC boolean requiresRestart = true; - if (sc.namespace11 && sc.modifyMethodName != "") { //$NON-NLS-1$ + if (sc.isNamespaceAtLeast11() && sc.modifyMethodName != "") { //$NON-NLS-1$ ServiceComponentProp scp = sc.getServiceComponentProp(); if (scp != null && scp.isBuilt()) { //process only built components @@ -378,7 +378,7 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C } } boolean requiresRestart = true; - if (sc.namespace11 && sc.modifyMethodName != "" && scp != null) { //$NON-NLS-1$ + if (sc.isNamespaceAtLeast11() && sc.modifyMethodName != "" && scp != null) { //$NON-NLS-1$ if (scp.isBuilt()) { //process only built components requiresRestart = processConfigurationChange(scp, config[0]); @@ -837,9 +837,10 @@ public class SCRManager implements ServiceListener, SynchronousBundleListener, C continue; } if (sc.enabled) { + String componentPID = sc.getConfigurationPID(); for (int j = 0; j < configs.length; j++) { - if (configs[j].getPid().equals(sc.name) || sc.name.equals(configs[j].getFactoryPid())) { - if (sc.name.equals(configs[j].getFactoryPid()) && sc.factory != null) { + if (configs[j].getPid().equals(componentPID) || componentPID.equals(configs[j].getFactoryPid())) { + if (componentPID.equals(configs[j].getFactoryPid()) && sc.factory != null) { Activator.log(sc.bc, LogService.LOG_ERROR, NLS.bind(Messages.FACTORY_CONF_NOT_APPLICABLE_FOR_COMPONENT_FACTORY, sc.name), null); break; } diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java index 5315dbfce..05dad5a60 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java @@ -71,9 +71,9 @@ public final class SCRUtil implements ObjectCreator { /** * Checks whether the method can be accessed according to the DS v1.1 specification rules (112.8.4 Locating Component Methods) * @param implClass the component implementation class - * @param currentClass the class where the method is located. This class is in the component imlpementation class hierarchy + * @param currentClass the class where the method is located. This class is in the component implementation class hierarchy * @param methodToCheck the method to be checked - * @param isComponent11 specifies whether the component is according to schema 1.1 or 1.0. Its value is true in case it is a v1.1 component + * @param isComponent11 specifies whether the component is according to schema 1.1 or higher. Its value is true in case the component version is v1.1 or higher * @return true, if the method can be executed */ public static boolean checkMethodAccess(Class implClass, Class currentClass, Method methodToCheck, boolean isComponent11) { 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 2ab77c630..19d2a4898 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 @@ -12,6 +12,8 @@ ALL_COMPONENTS=All Components: ALL_REFERENCES_RESOLVED=\ \ All component references are satisfied BIND_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE=[SCR] ComponentReference.bind(): bind method ''{0}'' is not found or it is not accessible! +UPDATED_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE=[SCR] Updated method ''{0}'' is not found or it is not accessible! +UPDATED_METHOD_NOT_CALLED=[SCR] Updated method of reference {0} of component {1} cannot be called because its parameter service object cannot be retrieved! BUNDLE_NOT_FOUND=Bundle with ID {0} was not found! CANNOT_BUILD_COMPONENT=[SCR] Cannot build component {0} CANNOT_CREATE_INSTANCE=ServiceReg.getService(): Could not create instance of {0} @@ -73,6 +75,7 @@ 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_UPDATING_REFERENCE=[SCR] Error while updating 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} @@ -106,6 +109,7 @@ INVALID_COMPONENT_TAG__MULTIPLE_IMPL_ATTRIBS=The ''component'' tag must have exa INVALID_COMPONENT_TAG__NO_CLASS_ATTR=The ''implementation'' element must have ''class'' attribute set at line {0} INVALID_OBJECT=The Object ''{0}'' is not created by the component named {1} INVALID_POLICY_ATTR=The ''policy'' attribute has invalid value ''{0}'' at line {1} +INVALID_POLICY_OPTION_ATTR=The ''policy-option'' attribute has invalid value ''{0}'' at line {1} INVALID_PROPERTIES_TAG__INVALID_ENTRY_VALUE=The specified ''entry'' for the ''properties'' tag at line {0} doesn''t contain valid reference to a property file: {1} INVALID_PROPERTIES_TAG__NO_ENTRY_ATTR=The ''properties'' tag must include ''entry'' attribute, at line {0} INVALID_PROPERTY_TAG__NO_BODY_CONTENT=The 'property' tag must have body content if 'value' attribute is not specified\! @@ -115,9 +119,11 @@ INVALID_PROVIDE_TAG__NO_INTERFACE_ATTR=The ''provide'' tag must have ''interface INVALID_REFERENCE_TAG__BIND_ATTR_EMPTY=The ''reference'' tag at line {0} is invalid: ''bind'' attribute is empty! INVALID_REFERENCE_TAG__BIND_EQUALS_UNBIND=The ''reference'' tag at line {0} is invalid: ''bind'' and ''unbind'' values are equal! INVALID_REFERENCE_TAG__UNBIND_ATTR_EMPTY=The ''reference'' tag at line {0} is invalid: ''unbind'' attribute is empty! +INVALID_REFERENCE_TAG__UPDATED_ATTR_EMPTY=The ''reference'' tag at line {0} is invalid: ''updated'' attribute is empty! INVALID_SERVICE_REFERENCE=[SCR] ComponentReference.unbind(): invalid service reference {0} INVALID_SERVICE_TAG__NO_PROVIDE_TAG=The ''service'' tag must have one ''provide'' tag set at line {0} INVALID_TAG_ACCORDING_TO_NAMESPACE1_0=The component is according to namespace v1.0.0 and must not have ''{0}'' tag set, at line {1} +INVALID_TAG_ACCORDING_TO_NAMESPACE1_2=The component must have namespace v1.2.0 in order to accept attribute ''{0}'' set, at line {1} INVALID_TARGET_FILTER=invalid target filter {0} LIST_ALL_BUNDLE_COMPONENTS=use [bundle id] to list the components of the specified bundle LIST_ALL_COMPONENTS=Lists all components; add -c to display the complete info for each component; diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java index 665297363..7e0395783 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java @@ -39,22 +39,30 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. public static final int POLICY_STATIC = 0; public static final int POLICY_DYNAMIC = 1; + public static final int POLICY_OPTION_RELUCTANT = 0; // default + public static final int POLICY_OPTION_GREEDY = 1; + // --- begin: XML def - public String name; // required + public String name; public String interfaceName; // required public int cardinality = CARDINALITY_1_1; public int policy = POLICY_STATIC; public String target; public String bind; public String unbind; - public ServiceComponent component; + //defined by DS specification v1.2 - schema v1.2.0 + public String updated; + public int policy_option = POLICY_OPTION_RELUCTANT; // --- end: XML def + public ServiceComponent component; // --- begin: cache private boolean bindCached; private boolean unbindCached; + private boolean updatedCached; Method bindMethod; Method unbindMethod; + Method updatedMethod; // --- end: cache // --- begin: model @@ -101,7 +109,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. logWarning(NLS.bind(Messages.EXCEPTION_GETTING_METHOD, methodName, consumerClass.getName()), err, reference); } - if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.namespace11)) + if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.isNamespaceAtLeast11())) break; // we need a serviceObject to keep looking, create one if necessary @@ -157,7 +165,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. // this may happen on skelmir VM or in case of class loading problems logWarning(NLS.bind(Messages.EXCEPTION_GETTING_METHOD, methodName, consumerClass.getName()), err, reference); } - if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.namespace11)) + if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.isNamespaceAtLeast11())) break; // 3) check for bind(class.isAssignableFrom(serviceObjectClass)) @@ -171,11 +179,11 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. break; } } - if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.namespace11)) + if (method != null && SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.isNamespaceAtLeast11())) break; //implement search for bind/unbind methods according to schema v1.1.0 - if (component.namespace11) { + if (component.isNamespaceAtLeast11()) { for (int i = 0; i < methods.length; i++) { Class[] params = methods[i].getParameterTypes(); if (params.length == 2 && methods[i].getName().equals(methodName) && params[0] == interfaceClass && params[1] == Map.class) { @@ -206,7 +214,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. return null; } - if (!SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.namespace11)) { + if (!SCRUtil.checkMethodAccess(componentInstance.getInstance().getClass(), consumerClass, method, component.isNamespaceAtLeast11())) { // if method is not visible, log error message logMethodNotVisible(componentInstance, reference, methodName, method.getParameterTypes()); return null; @@ -299,8 +307,9 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. return new StringBuffer(400); } - final void bind(Reference reference, ComponentInstance instance, ServiceReference serviceReference) throws Exception { + final boolean bind(Reference reference, ComponentInstance instance, ServiceReference serviceReference) throws Exception { if (bind != null) { + boolean bound = false; // DON'T rebind the same object again synchronized (serviceReferences) { Vector instances = (Vector) serviceReferences.get(serviceReference); @@ -312,7 +321,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. if (reference.isUnary()) { logWarning(NLS.bind(Messages.SERVICE_REFERENCE_ALREADY_BOUND, serviceReference, instance), null, reference); } - return; + return false; } else { instances.addElement(instance); } @@ -345,7 +354,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. //remove the component instance marked as bound removeServiceReference(serviceReference, instance); - return; + return false; } } @@ -365,6 +374,7 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. try { bindMethod.invoke(instance.getInstance(), params); + bound = true; } catch (Throwable t) { logError(NLS.bind(Messages.ERROR_BINDING_REFERENCE, this), t, reference); //remove the component instance marked as bound @@ -380,7 +390,9 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. // could be also circularity break logWarning(NLS.bind(Messages.BIND_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE, bind), null, reference); } + return bound; } + return false; } private void removeServiceReference(ServiceReference serviceReference, ComponentInstance instance) { @@ -491,9 +503,78 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. } } + final void updated(Reference reference, ComponentInstance instance, ServiceReference serviceReference) { + if (updated != null) { + synchronized (serviceReferences) { + Vector instances = (Vector) serviceReferences.get(serviceReference); + if (instances == null || !instances.contains(instance)) { + //this instance is not bound to the passed service reference + return; + } + } + // retrieve the method from cache + if (!updatedCached) { + updatedMethod = getMethod((ComponentInstanceImpl) instance, reference, updated, serviceReference); + // updatedMethod can be null in case of circularity + if (updatedMethod != null) { + updatedCached = true; + } + } + // invoke the method + if (updatedMethod != null) { + Object methodParam = null; + Class[] paramTypes = updatedMethod.getParameterTypes(); + if (paramTypes.length == 1 && paramTypes[0].equals(ServiceReference.class)) { + methodParam = serviceReference; + } else { + // bindedServices is filled by the getMethod function + methodParam = ((ComponentInstanceImpl) instance).bindedServices.get(serviceReference); + if (methodParam == null) { + methodParam = InstanceProcess.staticRef.getService(reference, serviceReference); + if (methodParam != null) { + ((ComponentInstanceImpl) instance).bindedServices.put(serviceReference, methodParam); + } + } + if (methodParam == null) { + // cannot get serviceObject because of circularity + Activator.log(null, LogService.LOG_WARNING, NLS.bind(Messages.UPDATED_METHOD_NOT_CALLED, name, component.name), null); + return; + } + } + + Object[] params = null; + if (paramTypes.length == 1) { + params = SCRUtil.getObjectArray(); + params[0] = methodParam; + } else { + //this is the case where we have 2 parameters: a service object and a Map, holding the service properties + HashMap map = new HashMap(); + String[] keys = serviceReference.getPropertyKeys(); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], serviceReference.getProperty(keys[i])); + } + params = new Object[] {methodParam, map}; + } + + try { + updatedMethod.invoke(instance.getInstance(), params); + } catch (Throwable t) { + logError(NLS.bind(Messages.ERROR_UPDATING_REFERENCE, this, instance.getInstance()), t, reference); + } finally { + if (params.length == 1) { + SCRUtil.release(params); + } + } + } else { + // could be also circularity break + logWarning(NLS.bind(Messages.UPDATED_METHOD_NOT_FOUND_OR_NOT_ACCESSIBLE, updated), null, reference); + } + } + } + public final void dispose() { - bindCached = unbindCached = false; - bindMethod = unbindMethod = null; + bindCached = unbindCached = updatedCached = false; + bindMethod = unbindMethod = updatedMethod = null; serviceReferences = null; } @@ -510,6 +591,16 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. case POLICY_STATIC : buffer.append("static"); //$NON-NLS-1$ } + if (component.isNamespaceAtLeast12()) { + buffer.append(", policy-option = "); //$NON-NLS-1$ + switch (policy_option) { + case POLICY_OPTION_RELUCTANT : + buffer.append("reluctant"); //$NON-NLS-1$ + break; + case POLICY_OPTION_GREEDY : + buffer.append("greedy"); //$NON-NLS-1$ + } + } buffer.append(", cardinality = "); //$NON-NLS-1$ switch (cardinality) { @@ -528,6 +619,9 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. buffer.append(", target = ").append(target); //$NON-NLS-1$ buffer.append(", bind = ").append(bind); //$NON-NLS-1$ buffer.append(", unbind = ").append(unbind); //$NON-NLS-1$ + if (component.isNamespaceAtLeast12()) { + buffer.append(", updated = ").append(updated); //$NON-NLS-1$ + } buffer.append("]"); //$NON-NLS-1$ return buffer.toString(); } @@ -565,8 +659,20 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. out.writeBoolean(flag); if (flag) out.writeUTF(unbind); + + // DS 1.2 support + out.writeBoolean(component.isNamespaceAtLeast12()); + if (component.isNamespaceAtLeast12()) { + flag = updated != null; + out.writeBoolean(flag); + if (flag) + out.writeUTF(updated); + + out.writeInt(policy_option); + } } catch (Exception e) { Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_WRITING_OBJECT, e); + throw e; } } @@ -599,8 +705,19 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. flag = in.readBoolean(); if (flag) unbind = in.readUTF(); + + // DS 1.2 support + flag = in.readBoolean(); + if (flag) { + //This is a DS 1.2 component + flag = in.readBoolean(); + if (flag) + updated = in.readUTF(); + policy_option = in.readInt(); + } } catch (Exception e) { Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_READING_OBJECT, e); + throw e; } } @@ -674,7 +791,9 @@ public class ComponentReference implements Externalizable, org.apache.felix.scr. * @see org.apache.felix.scr.Reference#getUpdatedMethodName() */ public String getUpdatedMethodName() { - // DS specification does not specify this method yet + if (component.isNamespaceAtLeast12()) { + return updated; + } return null; } 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 86444a868..8f4f2952d 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 @@ -35,6 +35,7 @@ public class DeclarationParser implements ExTagListener { private static final String XMLNS_1_0 = "http://www.osgi.org/xmlns/scr/v1.0.0"; //$NON-NLS-1$ private static final String XMLNS_1_1 = "http://www.osgi.org/xmlns/scr/v1.1.0"; //$NON-NLS-1$ + private static final String XMLNS_1_2 = "http://www.osgi.org/xmlns/scr/v1.2.0"; //$NON-NLS-1$ private static final String ATTR_XMLNS = "xmlns"; //$NON-NLS-1$ private static final String COMPONENT_TAG_NAME = "component"; //$NON-NLS-1$ @@ -49,6 +50,8 @@ public class DeclarationParser implements ExTagListener { 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_MODIFIED = "modified"; //$NON-NLS-1$ + //component attributes according to schema v1.2 + private static final String ATTR_CONFIGURATION_PID = "configuration-pid"; //$NON-NLS-1$ private static final String TAG_IMPLEMENTATION = "implementation"; //$NON-NLS-1$ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ @@ -71,6 +74,9 @@ public class DeclarationParser implements ExTagListener { private static final String ATTR_TARGET = "target"; //$NON-NLS-1$ private static final String ATTR_BIND = "bind"; //$NON-NLS-1$ private static final String ATTR_UNBIND = "unbind"; //$NON-NLS-1$ + //reference attributes according to schema v1.2 + private static final String ATTR_UPDATED = "updated"; //$NON-NLS-1$ + private static final String ATTR_POLICY_OPTION = "policy-option"; //$NON-NLS-1$ /** Constant for String property type */ public static final int STRING = 1; @@ -202,7 +208,7 @@ public class DeclarationParser implements ExTagListener { // if component factory then immediate by default is false currentComponent.setImmediate(currentComponent.serviceInterfaces == null); } - currentComponent.validate(tag.getLine(), isNamespace11(tag.getName())); + currentComponent.validate(tag.getLine(), getNamespace(tag.getName())); if (components == null) { components = new Vector(1, 1); } @@ -268,11 +274,6 @@ public class DeclarationParser implements ExTagListener { private void doReference(Tag tag) throws InvalidSyntaxException { String name = tag.getAttribute(ATTR_NAME); - // if (name == null) { - // IllegalArgumentException e = new IllegalArgumentException("The 'reference' tag must have 'name' attribute, at line " + tag.getLine()); - // throw e; - // } - String iface = tag.getAttribute(ATTR_INTERFACE); if (iface == null) { IllegalArgumentException e = new IllegalArgumentException(NLS.bind(Messages.NO_INTERFACE_ATTR_IN_REFERENCE_TAG, Integer.toString(tag.getLine()))); @@ -294,10 +295,10 @@ public class DeclarationParser implements ExTagListener { int policy = ComponentReference.POLICY_STATIC; // default if (policyS != null) { // verify the policy attribute values - if (policyS.equals("static")) { //$NON-NLS-1$ - policy = ComponentReference.POLICY_STATIC; - } else if (policyS.equals("dynamic")) { //$NON-NLS-1$ + if (policyS.equals("dynamic")) { //$NON-NLS-1$ policy = ComponentReference.POLICY_DYNAMIC; + } else if (policyS.equals("static")) { //$NON-NLS-1$ + policy = ComponentReference.POLICY_STATIC; } else { IllegalArgumentException e = new IllegalArgumentException(NLS.bind(Messages.INVALID_POLICY_ATTR, policyS, Integer.toString(tag.getLine()))); throw e; @@ -321,6 +322,35 @@ public class DeclarationParser implements ExTagListener { throw e; } + String updated = tag.getAttribute(ATTR_UPDATED); + if (updated != null && updated.equals("")) { //$NON-NLS-1$ + IllegalArgumentException e = new IllegalArgumentException(NLS.bind(Messages.INVALID_REFERENCE_TAG__UPDATED_ATTR_EMPTY, Integer.toString(tag.getLine()))); + throw e; + } + + String policyOption = tag.getAttribute(ATTR_POLICY_OPTION); + int policyOptionProcessed = ComponentReference.POLICY_OPTION_RELUCTANT; //default + if (policyOption != null) { + if (policyOption.equals("greedy")) { //$NON-NLS-1$ + policyOptionProcessed = ComponentReference.POLICY_OPTION_GREEDY; + } else if (policyOption.equals("reluctant")) { //$NON-NLS-1$ + policyOptionProcessed = ComponentReference.POLICY_OPTION_RELUCTANT; + } else { + IllegalArgumentException e = new IllegalArgumentException(NLS.bind(Messages.INVALID_POLICY_OPTION_ATTR, policyOption, Integer.toString(tag.getLine()))); + throw e; + } + } + + //check if the current component namespace is suitable for the latest reference attributes + if (!isNamespaceAtLeast12(closeTag)) { + if (updated != null) { + throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_2, ATTR_UPDATED, Integer.toString(tag.getLine()))); + } + if (policyOption != null) { + throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_2, ATTR_POLICY_OPTION, Integer.toString(tag.getLine()))); + } + } + // the reference is autoadded in the ServiceComponent's list of // references // in its constructor @@ -330,8 +360,9 @@ public class DeclarationParser implements ExTagListener { ref.cardinality = cardinality; ref.policy = policy; ref.bind = bind; - ref.unbind = unbind; + ref.updated = updated; + ref.policy_option = policyOptionProcessed; ref.target = tag.getAttribute(ATTR_TARGET); // validate the target filter if (ref.target != null) { @@ -537,7 +568,7 @@ public class DeclarationParser implements ExTagListener { currentComponent.immediate = Boolean.valueOf(tmp).booleanValue(); immediateSet = true; } - if (isNamespace11(tagName)) { + if (isNamespaceAtLeast11(tagName)) { //processing attribute configuration-policy tmp = tag.getAttribute(ATTR_CONF_POLICY); if (tmp != null && tmp.length() == 0) { @@ -586,6 +617,22 @@ public class DeclarationParser implements ExTagListener { throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_0, ATTR_MODIFIED, Integer.toString(tag.getLine()))); } } + + if (isNamespaceAtLeast12(tagName)) { + //processing attribute configuration-policy + tmp = tag.getAttribute(ATTR_CONFIGURATION_PID); + if (tmp != null && tmp.length() == 0) { + tmp = null; + } + if (tmp != null) { + currentComponent.configurationPID = tmp; + } + } else { + if (tag.getAttribute(ATTR_CONFIGURATION_PID) != null) { + throw new IllegalArgumentException(NLS.bind(Messages.INVALID_TAG_ACCORDING_TO_NAMESPACE1_2, ATTR_CONFIGURATION_PID, Integer.toString(tag.getLine()))); + } + } + } private boolean isCorrectComponentTag(String tagName) { @@ -596,10 +643,10 @@ public class DeclarationParser implements ExTagListener { } String namespace = getCurrentNamespace(qualifier); if (!rootPassed) { // this is the root element - return namespace.length() == 0 || namespace.equals(XMLNS_1_0) || namespace.equals(XMLNS_1_1); - } else { // not a root element - return namespace.equals(XMLNS_1_0) || namespace.equals(XMLNS_1_1); + return namespace.length() == 0 || namespace.equals(XMLNS_1_1) || namespace.equals(XMLNS_1_2) || namespace.equals(XMLNS_1_0); } + // not a root element + return namespace.equals(XMLNS_1_1) || namespace.equals(XMLNS_1_2) || namespace.equals(XMLNS_1_0); } /** @@ -736,14 +783,35 @@ public class DeclarationParser implements ExTagListener { } } - private boolean isNamespace11(String tagName) { + private int getNamespace(String tagName) { String qualifier = getNamespaceQualifier(tagName); String namespace = getCurrentNamespace(qualifier); if (!rootPassed) { // this is the root element - return namespace.length() != 0 && namespace.equals(XMLNS_1_1); - } else { // not a root element - return namespace.equals(XMLNS_1_1); + if (namespace.length() == 0) { + return ServiceComponent.NAMESPACE_1_0; + } } + // not a root element + if (namespace.equals(XMLNS_1_0)) { + return ServiceComponent.NAMESPACE_1_0; + } else if (namespace.equals(XMLNS_1_1)) { + return ServiceComponent.NAMESPACE_1_1; + } else if (namespace.equals(XMLNS_1_2)) { + return ServiceComponent.NAMESPACE_1_2; + } + + //namespace is not known + return -1; + } + + private boolean isNamespaceAtLeast11(String tagName) { + int namespace = getNamespace(tagName); + return (namespace >= ServiceComponent.NAMESPACE_1_1); + } + + private boolean isNamespaceAtLeast12(String tagName) { + int namespace = getNamespace(tagName); + return (namespace >= ServiceComponent.NAMESPACE_1_2); } private void processNamespacesEnter(Tag tag) { 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 f05961727..1cd041cc9 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 @@ -38,9 +38,14 @@ import org.osgi.service.log.LogService; */ public class ServiceComponent implements Externalizable, Component { - public static String CONF_POLICY_OPTIONAL = "optional"; //$NON-NLS-1$ - public static String CONF_POLICY_REQUIRE = "require"; //$NON-NLS-1$ - public static String CONF_POLICY_IGNORE = "ignore"; //$NON-NLS-1$ + //constants defining possible SCR namespaces XML schemas + public static final int NAMESPACE_1_0 = 0; + public static final int NAMESPACE_1_1 = 1; + public static final int NAMESPACE_1_2 = 2; + + public static final String CONF_POLICY_OPTIONAL = "optional"; //$NON-NLS-1$ + public static final String CONF_POLICY_REQUIRE = "require"; //$NON-NLS-1$ + public static final String CONF_POLICY_IGNORE = "ignore"; //$NON-NLS-1$ public Vector componentProps = null; @@ -54,6 +59,9 @@ public class ServiceComponent implements Externalizable, Component { String deactivateMethodName = "deactivate"; //$NON-NLS-1$ public String modifyMethodName = ""; //$NON-NLS-1$ + //Since DS 1.2 + public String configurationPID; + // service public Vector serviceInterfaces; // all strings public String[] provides; // the same as above, but as String[] @@ -63,7 +71,7 @@ public class ServiceComponent implements Externalizable, Component { public boolean autoenable = true; public boolean immediate = false; - public boolean namespace11 = false; + public int namespace = NAMESPACE_1_0; // --- end: XML def // --- begin: cache @@ -114,7 +122,7 @@ public class ServiceComponent implements Externalizable, Component { Class clazz = instance != null ? instance.getClass() : null; while (method == null && clazz != null) { - if (namespace11) { + if (isNamespaceAtLeast11()) { Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(methodName)) { @@ -199,7 +207,7 @@ public class ServiceComponent implements Externalizable, Component { void activate(Object instance, ComponentContext context) throws ComponentException { try { - if (namespace11) { + if (isNamespaceAtLeast11()) { if (!activateCached) { activateCached = true; activateMethod = getMethod(instance, activateMethodName, true); @@ -272,7 +280,7 @@ public class ServiceComponent implements Externalizable, Component { void modified(Object instance, ComponentContext context) throws ComponentException { try { - if (namespace11) { + if (isNamespaceAtLeast11()) { if (!modifyCached) { modifyCached = true; if (modifyMethodName != "") { //$NON-NLS-1$ @@ -323,7 +331,7 @@ public class ServiceComponent implements Externalizable, Component { void deactivate(Object instance, ComponentContext context, int deactivateReason) { try { - if (namespace11) { + if (isNamespaceAtLeast11()) { if (!deactivateCached) { deactivateCached = true; deactivateMethod = getMethod(instance, deactivateMethodName, false); @@ -388,28 +396,35 @@ public class ServiceComponent implements Externalizable, Component { } /** - * this method is called from the xml parser to validate the component once + * This method is called from the XML parser to validate the component once * it is fully loaded! * * @param line * the line at which the the component definition ends - * @param namespace11 specify whether the namespace of the component is according to XML SCR schema v1.1 + * @param _namespace specify the namespace of the component according to XML SCR schema */ - void validate(int line, boolean namespace11) { + void validate(int line, int _namespace) { // System.out.println("Validating component " + name + " with namespace " + (namespace11 ? "1.1" : "1.0")); + this.namespace = _namespace; if (name == null) { - if (namespace11) { + if (isNamespaceAtLeast11()) { name = implementation; } else { throw new IllegalArgumentException(NLS.bind(Messages.NO_NAME_ATTRIBUTE, Integer.toString(line))); } } - if (namespace11) { + if (isNamespaceAtLeast11()) { if (!(configurationPolicy == CONF_POLICY_OPTIONAL || configurationPolicy == CONF_POLICY_REQUIRE || configurationPolicy == CONF_POLICY_IGNORE)) { throw new IllegalArgumentException(NLS.bind(Messages.INCORRECT_ACTIVATION_POLICY, name, Integer.toString(line))); } } + if (isNamespaceAtLeast12()) { + if (configurationPID == null) { + configurationPID = name; + } + } + if (implementation == null) { throw new IllegalArgumentException(NLS.bind(Messages.NO_IMPLEMENTATION_ATTRIBUTE, name, Integer.toString(line))); } @@ -435,13 +450,13 @@ public class ServiceComponent implements Externalizable, Component { for (int i = 0; i < references.size(); i++) { ComponentReference r = (ComponentReference) references.elementAt(i); if (r.name == null) { - if (namespace11) { + if (isNamespaceAtLeast11()) { r.name = r.interfaceName; } else { throw new IllegalArgumentException(NLS.bind(Messages.COMPONENT_HAS_ILLEGAL_REFERENCE, new Object[] {name, Integer.toString(line), r})); } } - if (r.interfaceName == null || r.name.equals("") || r.interfaceName.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (r.interfaceName == null || r.name.length() == 0 || r.interfaceName.length() == 0) { throw new IllegalArgumentException(NLS.bind(Messages.COMPONENT_HAS_ILLEGAL_REFERENCE, new Object[] {name, Integer.toString(line), r})); } for (int j = i + 1; j < references.size(); j++) { @@ -459,8 +474,6 @@ public class ServiceComponent implements Externalizable, Component { serviceInterfaces.copyInto(provides); } - this.namespace11 = namespace11; - // make sure that the component will get automatically enabled! enabled = autoenable; } @@ -520,6 +533,13 @@ public class ServiceComponent implements Externalizable, Component { return serviceInterfaces != null && serviceInterfaces.contains(interfaceName); } + public String getConfigurationPID() { + if (isNamespaceAtLeast12()) { + return configurationPID; + } + return name; + } + /* * (non-Javadoc) * @@ -529,12 +549,15 @@ public class ServiceComponent implements Externalizable, Component { StringBuffer buffer = new StringBuffer(); buffer.append("Component["); //$NON-NLS-1$ buffer.append("\n\tname = ").append(name); //$NON-NLS-1$ - if (namespace11) { + if (isNamespaceAtLeast11()) { buffer.append("\n\tactivate = ").append(activateMethodName); //$NON-NLS-1$ buffer.append("\n\tdeactivate = ").append(deactivateMethodName); //$NON-NLS-1$ buffer.append("\n\tmodified = ").append(modifyMethodName); //$NON-NLS-1$ buffer.append("\n\tconfiguration-policy = ").append(configurationPolicy); //$NON-NLS-1$ } + if (isNamespaceAtLeast12()) { + buffer.append("\n\tconfiguration-pid = ").append(configurationPID); //$NON-NLS-1$ + } buffer.append("\n\tfactory = ").append(factory); //$NON-NLS-1$ buffer.append("\n\tautoenable = ").append(autoenable); //$NON-NLS-1$ buffer.append("\n\timmediate = ").append(immediate); //$NON-NLS-1$ @@ -617,8 +640,8 @@ public class ServiceComponent implements Externalizable, Component { dictionary.writeObject(out); } - out.writeBoolean(namespace11); - if (namespace11) { + out.writeInt(namespace); + if (isNamespaceAtLeast11()) { if (configurationPolicy == CONF_POLICY_OPTIONAL) { //this is the default value. Do not write it. Just add a mark out.writeBoolean(false); @@ -648,8 +671,17 @@ public class ServiceComponent implements Externalizable, Component { out.writeUTF(modifyMethodName); } } + if (isNamespaceAtLeast12()) { + if (configurationPID == name) { + out.writeBoolean(false); + } else { + out.writeBoolean(true); + out.writeUTF(configurationPID); + } + } } catch (Exception e) { Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_WRITING_OBJECT, e); + throw e; } } @@ -713,8 +745,8 @@ public class ServiceComponent implements Externalizable, Component { } properties = props; } - namespace11 = in.readBoolean(); - if (namespace11) { + namespace = in.readInt(); + if (isNamespaceAtLeast11()) { flag = in.readBoolean(); if (flag) { configurationPolicy = in.readUTF(); @@ -738,8 +770,17 @@ public class ServiceComponent implements Externalizable, Component { if (flag) modifyMethodName = in.readUTF(); } + if (isNamespaceAtLeast12()) { + flag = in.readBoolean(); + if (flag) { + configurationPID = in.readUTF(); + } else { + configurationPID = name; + } + } } catch (Exception e) { Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_READING_OBJECT, e); + throw e; } } @@ -780,6 +821,14 @@ public class ServiceComponent implements Externalizable, Component { return null; } + public boolean isNamespaceAtLeast11() { + return namespace >= NAMESPACE_1_1; + } + + public boolean isNamespaceAtLeast12() { + return namespace >= NAMESPACE_1_2; + } + public boolean isImmediate() { return immediate; } @@ -850,7 +899,7 @@ public class ServiceComponent implements Externalizable, Component { } public String getModified() { - if (!namespace11) { + if (!isNamespaceAtLeast11()) { return null; } return modifyMethodName; @@ -895,14 +944,14 @@ public class ServiceComponent implements Externalizable, Component { } public boolean isActivateDeclared() { - if (!namespace11) { + if (!isNamespaceAtLeast11()) { return false; } return activateMethodDeclared; } public boolean isDeactivateDeclared() { - if (!namespace11) { + if (!isNamespaceAtLeast11()) { return false; } return deactivateMethodDeclared; 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 d6d444acb..49509e1bf 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 @@ -223,6 +223,7 @@ public class ServiceComponentProp implements Component, PrivilegedExceptionActio if (ref.reference.bindMethod == null || ccError != 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) { + Activator.log(null, LogService.LOG_WARNING, "Could not bind a reference of component " + name + ". The reference is: " + ref.reference, null); //$NON-NLS-1$ //$NON-NLS-2$ //unbind the already bound references for (int j = i - 1; j >= 0; j--) { ref = (Reference) references.elementAt(i); @@ -427,9 +428,13 @@ public class ServiceComponentProp implements Component, PrivilegedExceptionActio case ComponentReference.CARDINALITY_1_1 : case ComponentReference.CARDINALITY_0_1 : for (int i = 0; i < serviceReferences.length; i++) { - reference.reference.bind(reference, componentInstance, serviceReferences[i]); - if (reference.reference.bindMethod != null) { - //bind method for this reference was found + ServiceReference oldBoundService = (reference.reference.policy_option == ComponentReference.POLICY_OPTION_GREEDY && reference.reference.serviceReferences.size() > 0 ? (ServiceReference) reference.reference.serviceReferences.keys().nextElement() : null); + boolean bound = reference.reference.bind(reference, componentInstance, serviceReferences[i]); + if (bound) { + if (oldBoundService != null) { + //unbind the previous bound service reference in case we are handling service reference update due to greedy policy option + reference.reference.unbind(reference, componentInstance, oldBoundService); + } break; } } @@ -638,6 +643,20 @@ public class ServiceComponentProp implements Component, PrivilegedExceptionActio ref.reference.unbind(ref, instance, serviceReference); } + /** + * Call the updated method for this Reference + * + * @param ref the reference + * @param instance the component instance + * @param serviceReference the service reference which properties have changed + */ + public void updatedReference(Reference ref, ComponentInstance instance, ServiceReference serviceReference) { + if (Activator.DEBUG) { + Activator.log.debug("ServiceComponentProp.updatedReference(): component = " + name + ", reference = " + ref.reference.name, null); //$NON-NLS-1$ //$NON-NLS-2$ + } + ref.reference.updated(ref, instance, serviceReference); + } + // -- begin helper methods /** * Initialize Properties for this Component @@ -850,7 +869,7 @@ public class ServiceComponentProp implements Component, PrivilegedExceptionActio } public String getModified() { - if (!serviceComponent.namespace11) { + if (!serviceComponent.isNamespaceAtLeast11()) { return null; } return serviceComponent.modifyMethodName; @@ -874,14 +893,14 @@ public class ServiceComponentProp implements Component, PrivilegedExceptionActio } public boolean isActivateDeclared() { - if (!serviceComponent.namespace11) { + if (!serviceComponent.isNamespaceAtLeast11()) { return false; } return serviceComponent.activateMethodDeclared; } public boolean isDeactivateDeclared() { - if (!serviceComponent.namespace11) { + if (!serviceComponent.isNamespaceAtLeast11()) { return false; } return serviceComponent.deactivateMethodDeclared; diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java index dbad5fa89..2886c0b0f 100644 --- a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java +++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java @@ -89,23 +89,19 @@ public class FileStorage extends ComponentStorage { String lastModifiedValue = (String) data.get(getPath(dbBundlePath)); if (lastModifiedValue == null) { - components = parseXMLDeclaration(bundle, dsHeader); - if (components != null && components.size() != 0) { - data.put(getPath(dbBundlePath), "" + lastModified); //$NON-NLS-1$ - saveComponentDefinitions(components, bundle.getBundleId()); - } - + components = processXMLDeclarations(bundle, dsHeader, dbBundlePath, lastModified); } else { long dbLastModified = Long.parseLong(lastModifiedValue); if (lastModified != dbLastModified) { - components = parseXMLDeclaration(bundle, dsHeader); - if (components != null && components.size() != 0) { - data.put(getPath(dbBundlePath), "" + lastModified); //$NON-NLS-1$ - saveComponentDefinitions(components, bundle.getBundleId()); - } - + components = processXMLDeclarations(bundle, dsHeader, dbBundlePath, lastModified); } else { - components = loadComponentsFromDB(bundle); + try { + components = loadComponentsFromDB(bundle); + } catch (Throwable t) { + Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_LOADING_COMPONENTS, t); + //backup plan - parse the bundle's component XML declarations + components = processXMLDeclarations(bundle, dsHeader, dbBundlePath, lastModified); + } } } return components; @@ -115,30 +111,34 @@ public class FileStorage extends ComponentStorage { } } + private Vector processXMLDeclarations(Bundle bundle, String dsHeader, String[] dbBundlePath, long lastModified) throws Exception { + Vector components = parseXMLDeclaration(bundle, dsHeader); + if (components != null && components.size() != 0) { + data.put(getPath(dbBundlePath), "" + lastModified); //$NON-NLS-1$ + saveComponentDefinitions(components, bundle.getBundleId()); + } + return components; + } + private Vector loadComponentsFromDB(Bundle bundle) throws Exception { - try { - String[] dbCompPath = new String[] {null, "COMPONENTS"}; //$NON-NLS-1$ - ServiceComponent currentComponent = null; - long bundleId = bundle.getBundleId(); - dbCompPath[0] = String.valueOf(bundleId); - DBObject value = new DBObject(); - byte[] byteArr = (byte[]) data.get(getPath(dbCompPath)); - ByteArrayInputStream tmpIn = new ByteArrayInputStream(byteArr); - value.readObject(tmpIn); - Vector components = value.components; - if (components == null) { - return null; - } - for (int i = 0; i < components.size(); i++) { - currentComponent = (ServiceComponent) components.elementAt(i); - currentComponent.bundle = bundle; - currentComponent.bc = bundle.getBundleContext(); - } - return components; - } catch (Throwable t) { - Activator.log(null, LogService.LOG_ERROR, Messages.ERROR_LOADING_COMPONENTS, t); + String[] dbCompPath = new String[] {null, "COMPONENTS"}; //$NON-NLS-1$ + ServiceComponent currentComponent = null; + long bundleId = bundle.getBundleId(); + dbCompPath[0] = String.valueOf(bundleId); + DBObject value = new DBObject(); + byte[] byteArr = (byte[]) data.get(getPath(dbCompPath)); + ByteArrayInputStream tmpIn = new ByteArrayInputStream(byteArr); + value.readObject(tmpIn); + Vector components = value.components; + if (components == null) { + return null; + } + for (int i = 0; i < components.size(); i++) { + currentComponent = (ServiceComponent) components.elementAt(i); + currentComponent.bundle = bundle; + currentComponent.bc = bundle.getBundleContext(); } - return null; + return components; } public void deleteComponentDefinitions(long bundleID) { |