FELIX-1893 Add support for a configurable "updated" method
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@887877 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java
new file mode 100644
index 0000000..2283888
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.helper;
+
+
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+
+
+/**
+ * Component method to be invoked on service property update of a bound service.
+ */
+public class UpdatedMethod extends BindMethod
+{
+
+ public UpdatedMethod( final AbstractComponentManager componentManager, final String methodName,
+ final Class componentClass, final String referenceName, final String referenceClassName )
+ {
+ super( componentManager, methodName, componentClass, referenceName, referenceClassName );
+ }
+
+
+ protected String getMethodNamePrefix()
+ {
+ return "update";
+ }
+
+}
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
index 04bd06b..61f6591 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
@@ -30,6 +30,7 @@
import org.apache.felix.scr.Reference;
import org.apache.felix.scr.impl.helper.BindMethod;
import org.apache.felix.scr.impl.helper.UnbindMethod;
+import org.apache.felix.scr.impl.helper.UpdatedMethod;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -76,6 +77,9 @@
// the bind method
private BindMethod m_bind;
+ // the updated method
+ private UpdatedMethod m_updated;
+
// the unbind method
private UnbindMethod m_unbind;
@@ -124,6 +128,12 @@
m_dependencyMetadata.getName(),
m_dependencyMetadata.getInterface()
);
+ m_updated = new UpdatedMethod( m_componentManager,
+ m_dependencyMetadata.getUpdated(),
+ m_componentInstance.getClass(),
+ m_dependencyMetadata.getName(),
+ m_dependencyMetadata.getInterface()
+ );
m_unbind = new UnbindMethod( m_componentManager,
m_dependencyMetadata.getUnbind(),
m_componentInstance.getClass(),
@@ -922,24 +932,18 @@
/**
* Handles an update in the service reference properties of a bound service.
* <p>
- * For now this just calls the bind method with the service again if
- * the <code>ds.rebind.enabled</code> configuration property is set to
- * <code>true</code>. If the property is not set to <code>true</code> this
- * method does nothing.
+ * This just calls the {@link #invokeUpdatedMethod(ServiceReference)}
+ * method if the method has been configured in the component metadata. If
+ * the method is not configured, this method does nothing.
*
* @param ref The <code>ServiceReference</code> representing the updated
* service.
*/
private void update( final ServiceReference ref )
{
- if ( m_componentManager.getActivator().getConfiguration().isRebindEnabled() )
+ if ( m_dependencyMetadata.getUpdated() != null )
{
- // The updated method is only invoked if the implementation object is not
- // null. This is valid for both immediate and delayed components
- if ( m_dependencyMetadata.getBind() != null )
- {
- invokeBindMethod( ref );
- }
+ invokeUpdatedMethod( ref );
}
}
@@ -1045,6 +1049,43 @@
/**
+ * Calls the updated method.
+ *
+ * @param ref A service reference corresponding to the service whose service
+ * registration properties have been updated
+ */
+ private void invokeUpdatedMethod( final ServiceReference ref )
+ {
+ // The updated method is only invoked if the implementation object is not
+ // null. This is valid for both immediate and delayed components
+ if ( m_componentInstance != null )
+ {
+ m_updated.invoke( m_componentInstance, new BindMethod.Service()
+ {
+ public ServiceReference getReference()
+ {
+ return ref;
+ }
+
+
+ public Object getInstance()
+ {
+ return getService( ref );
+ }
+ } );
+ }
+ else
+ {
+ // don't care whether we can or cannot call the unbind method
+ // if the component instance has already been cleared by the
+ // close() method
+ m_componentManager.log( LogService.LOG_DEBUG,
+ "DependencyManager : Component not set, no need to call updated method", null );
+ }
+ }
+
+
+ /**
* Calls the unbind method.
* <p>
* If the reference is singular and the given service is not the one bound
@@ -1053,7 +1094,6 @@
*
* @param ref A service reference corresponding to the service that will be
* unbound
- * @return true if the call was successful, false otherwise
*/
private void invokeUnbindMethod( final ServiceReference ref )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
index d55bcf3..8216b1d 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
@@ -363,6 +363,18 @@
/**
+ * Returns <code>true</code> if the metadata declaration has used the
+ * Declarative Services version 1.1-felixnamespace or a later namespace.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/FELIX-1893">FELIX-1893</a>
+ */
+ public boolean isDS11Felix()
+ {
+ return getNamespaceCode() >= XmlHandler.DS_VERSION_1_1_FELIX;
+ }
+
+
+ /**
* Returns the name of the component
*
* @return A string containing the name of the component
@@ -707,7 +719,7 @@
while ( referenceIterator.hasNext() )
{
ReferenceMetadata refMeta = ( ReferenceMetadata ) referenceIterator.next();
- refMeta.validate( this );
+ refMeta.validate( this, logger );
// flag duplicates
if ( !refs.add( refMeta.getName() ) )
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
index 471c099..aeb4c16 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
@@ -21,6 +21,9 @@
import java.util.Set;
import java.util.TreeSet;
+import org.apache.felix.scr.impl.helper.Logger;
+import org.osgi.service.log.LogService;
+
/**
* Information associated to a dependency
*
@@ -66,6 +69,9 @@
// Name of the bind method (optional)
private String m_bind = null;
+ // Name of the updated method (optional, since DS 1.1-felix)
+ private String m_updated = null;
+
// Name of the unbind method (optional)
private String m_unbind = null;
@@ -201,6 +207,22 @@
/**
+ * Setter for the updated method attribute
+ *
+ * @param updated
+ */
+ public void setUpdated( String updated )
+ {
+ if ( m_validated )
+ {
+ return;
+ }
+
+ m_updated = updated;
+ }
+
+
+ /**
* Setter for the unbind method attribute
*
* @param unbind
@@ -287,6 +309,18 @@
/**
* Get the name of a method in the component implementation class that is used to notify that
+ * the service properties of a bound service have been updated
+ *
+ * @return a String with the name of the updated method
+ **/
+ public String getUpdated()
+ {
+ return m_updated;
+ }
+
+
+ /**
+ * Get the name of a method in the component implementation class that is used to notify that
* a service is unbound from the component configuration
*
* @return a String with the name of the unbind method
@@ -349,7 +383,7 @@
* Method used to verify if the semantics of this metadata are correct
*
*/
- void validate( ComponentMetadata componentMetadata )
+ void validate( final ComponentMetadata componentMetadata, final Logger logger )
{
if ( m_name == null )
{
@@ -384,6 +418,16 @@
{
throw componentMetadata.validationFailure( "Policy must be one of " + POLICY_VALID );
}
+
+ // updated method is only supported in namespace xxx and later
+ if ( m_updated != null && !componentMetadata.isDS11Felix() )
+ {
+ logger
+ .log( LogService.LOG_WARNING,
+ "Ignoring updated method definition, DS 1.1-felix or later namespace required", componentMetadata,
+ null );
+ m_updated = null;
+ }
}
}
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
index 3100c7f..bbdc988 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
@@ -52,15 +52,21 @@
// Namespace URI of DS 1.1
public static final String NAMESPACE_URI_1_1 = "http://www.osgi.org/xmlns/scr/v1.1.0";
+ // Namespace URI of DS 1.1-felix (see FELIX-1893)
+ public static final String NAMESPACE_URI_1_1_FELIX = "http://felix.apache.org/xmlns/scr/v1.1.0-felix";
+
// namespace code for non-DS namespace
public static final int DS_VERSION_NONE = -1;
// namespace code for the DS 1.0 specification
public static final int DS_VERSION_1_0 = 0;
- // namespace code for the DS 1.0 specification
+ // namespace code for the DS 1.1 specification
public static final int DS_VERSION_1_1 = 1;
+ // namespace code for the DS 1.1-felix specification
+ public static final int DS_VERSION_1_1_FELIX = 2;
+
// mapping of namespace URI to namespace code
private static final Map NAMESPACE_CODE_MAP;
@@ -97,6 +103,7 @@
NAMESPACE_CODE_MAP.put( NAMESPACE_URI_EMPTY, new Integer( DS_VERSION_1_0 ) );
NAMESPACE_CODE_MAP.put( NAMESPACE_URI, new Integer( DS_VERSION_1_0 ) );
NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_1, new Integer( DS_VERSION_1_1 ) );
+ NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_1_FELIX, new Integer( DS_VERSION_1_1_FELIX ) );
}
@@ -306,6 +313,7 @@
//if
ref.setTarget( attrib.getProperty( "target" ) );
ref.setBind( attrib.getProperty( "bind" ) );
+ ref.setUpdated( attrib.getProperty( "updated" ) );
ref.setUnbind( attrib.getProperty( "unbind" ) );
m_currentComponent.addDependency( ref );
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
index 1c51f68..6bd1645 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
@@ -482,6 +482,55 @@
}
+ public void test_reference_updated_ds10()
+ {
+ // updated method ignored for DS 1.0
+ final ReferenceMetadata rm3 = createReferenceMetadata( "test" );
+ rm3.setUpdated( "my_updated_method" );
+ final ComponentMetadata cm3 = createComponentMetadata( Boolean.TRUE, null );
+ cm3.addDependency( rm3 );
+
+ // validates fine (though logging a warning) and sets field to null
+ cm3.validate( logger );
+
+ assertTrue( "Expected warning for unsupported updated method name", logger
+ .messageContains( "Ignoring updated method definition" ) );
+ assertNull( rm3.getUpdated() );
+ }
+
+
+ public void test_reference_updated_ds11()
+ {
+ // updated method ignored for DS 1.1
+ final ReferenceMetadata rm3 = createReferenceMetadata( "test" );
+ rm3.setUpdated( "my_updated_method" );
+ final ComponentMetadata cm3 = createComponentMetadata11( Boolean.TRUE, null );
+ cm3.addDependency( rm3 );
+
+ // validates fine (though logging a warning) and sets field to null
+ cm3.validate( logger );
+
+ assertTrue( "Expected warning for unsupported updated method name", logger
+ .messageContains( "Ignoring updated method definition" ) );
+ assertNull( rm3.getUpdated() );
+ }
+
+
+ public void test_reference_updated_ds11_felix()
+ {
+ // updated method accepted for DS 1.1-felix
+ final ReferenceMetadata rm3 = createReferenceMetadata( "test" );
+ rm3.setUpdated( "my_updated_method" );
+ final ComponentMetadata cm3 = createComponentMetadata( XmlHandler.DS_VERSION_1_1_FELIX, Boolean.TRUE, null );
+ cm3.addDependency( rm3 );
+
+ // validates fine and logs no message
+ cm3.validate( logger );
+
+ assertEquals( "my_updated_method", rm3.getUpdated() );
+ }
+
+
public void test_duplicate_implementation_ds10()
{
final ComponentMetadata cm = createComponentMetadata( Boolean.TRUE, null );
@@ -636,10 +685,10 @@
//---------- Helper methods
- // Creates DS 1.0 Component Metadata
- private ComponentMetadata createComponentMetadata( Boolean immediate, String factory )
+ // Creates Component Metadata for the given namespace
+ private ComponentMetadata createComponentMetadata( int nameSpaceCode, Boolean immediate, String factory )
{
- ComponentMetadata meta = new ComponentMetadata( XmlHandler.DS_VERSION_1_0 );
+ ComponentMetadata meta = new ComponentMetadata( nameSpaceCode );
meta.setName( "place.holder" );
meta.setImplementationClassName( "place.holder.implementation" );
if ( immediate != null )
@@ -653,22 +702,17 @@
return meta;
}
+ // Creates DS 1.0 Component Metadata
+ private ComponentMetadata createComponentMetadata( Boolean immediate, String factory )
+ {
+ return createComponentMetadata( XmlHandler.DS_VERSION_1_0, immediate, factory );
+ }
+
// Creates DS 1.1 Component Metadata
private ComponentMetadata createComponentMetadata11( Boolean immediate, String factory )
{
- ComponentMetadata meta = new ComponentMetadata( XmlHandler.DS_VERSION_1_1 );
- meta.setName( "place.holder" );
- meta.setImplementationClassName( "place.holder.implementation" );
- if ( immediate != null )
- {
- meta.setImmediate( immediate.booleanValue() );
- }
- if ( factory != null )
- {
- meta.setFactoryIdentifier( factory );
- }
- return meta;
+ return createComponentMetadata( XmlHandler.DS_VERSION_1_1, immediate, factory );
}