FELIX-4631 : [DS][R6/RFC212] Implement field injection. WiP
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1637751 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index 05ec96b..d5df715 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -28,16 +28,13 @@
import java.util.Map;
import org.apache.felix.scr.impl.metadata.DSVersion;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.component.ComponentContext;
import org.osgi.service.log.LogService;
/**
* Component method to be invoked on service (un)binding.
*/
-abstract class BaseMethod<P>
+public abstract class BaseMethod<P>
{
// class references to simplify parameter checking
@@ -163,7 +160,7 @@
final String targetPackage = getPackageName( targetClass );
Class<?> theClass = targetClass;
- while (true)
+ while (true)
{
if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
@@ -402,7 +399,7 @@
* @param allowReturnValue whether the method can return a value (to update service registration properties)
* @return whether the method is acceptable
*/
- static boolean accept( final Method method, boolean acceptPrivate, boolean acceptPackage, boolean allowReturnValue )
+ protected static boolean accept( final Method method, boolean acceptPrivate, boolean acceptPackage, boolean allowReturnValue )
{
if (!(Void.TYPE == method.getReturnType() || (MAP_CLASS == method.getReturnType() && allowReturnValue)))
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
index 201b2ac..af0a336 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
@@ -44,13 +44,14 @@
* Component method to be invoked on service (un)binding.
*/
public class BindMethod extends BaseMethod<BindParameters>
+implements org.apache.felix.scr.impl.helper.ReferenceMethod
{
private static final Class<?> OBJECT_CLASS = Object.class;
-
+
protected static final Class<?> SERVICE_REFERENCE_CLASS = ServiceReference.class;
private static final Class<?> SERVICE_OBJECTS_CLASS;
-
+
static {
Class<?> serviceObjectsClass = null;
try {
@@ -64,16 +65,16 @@
}
private final String m_referenceClassName;
-
+
private final ReferenceMetadata.ReferenceScope m_referenceScope;
- private enum ParamType {
+ private enum ParamType {
serviceReference,
serviceObjects,
serviceType,
map
}
-
+
//initialized for cases where there is no method.
private volatile List<ParamType> m_paramTypes = Collections.emptyList();
@@ -105,6 +106,7 @@
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested method.
*/
+ @Override
protected Method doFindMethod( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
throws SuitableMethodNotAccessibleException, InvocationTargetException
{
@@ -712,6 +714,7 @@
return true;
}
+ @Override
protected Object[] getParameters( Method method, BindParameters bp )
{
ComponentContextImpl key = bp.getComponentContext();
@@ -720,30 +723,31 @@
int i = 0;
for ( ParamType pt: m_paramTypes ) {
switch (pt) {
- case serviceReference:
+ case serviceReference:
result[i++] = refPair.getRef();
break;
-
+
case serviceObjects:
result[i++] = refPair.getServiceObjects();
break;
-
+
case map:
result[i++] = new ReadOnlyDictionary<String, Object>( refPair.getRef() );
break;
-
+
case serviceType:
result[i++] = refPair.getServiceObject(key);
break;
-
+
default: throw new IllegalStateException("unexpected ParamType: " + pt);
-
+
}
}
return result;
}
+ @Override
protected String getMethodNamePrefix()
{
return "bind";
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethods.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethods.java
index af94e57..26a497d 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethods.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethods.java
@@ -25,31 +25,31 @@
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
/**
- * @version $Rev:$ $Date:$
+ * @version $Rev$ $Date$
*/
-public class BindMethods
+public class BindMethods implements ReferenceMethods
{
- private final BindMethod m_bind;
- private final UpdatedMethod m_updated;
- private final UnbindMethod m_unbind;
+ private final ReferenceMethod m_bind;
+ private final ReferenceMethod m_updated;
+ private final ReferenceMethod m_unbind;
- BindMethods( ReferenceMetadata m_dependencyMetadata, Class<?> instanceClass,
+ public BindMethods( ReferenceMetadata m_dependencyMetadata, Class<?> instanceClass,
final DSVersion dsVersion, final boolean configurableServiceProperties )
{
ReferenceMetadata.ReferenceScope referenceScope = m_dependencyMetadata.getScope();
- m_bind = new BindMethod(
+ m_bind = new org.apache.felix.scr.impl.helper.BindMethod(
m_dependencyMetadata.getBind(),
instanceClass,
m_dependencyMetadata.getInterface(),
dsVersion, configurableServiceProperties, referenceScope
);
- m_updated = new UpdatedMethod(
+ m_updated = new org.apache.felix.scr.impl.helper.UpdatedMethod(
m_dependencyMetadata.getUpdated(),
instanceClass,
m_dependencyMetadata.getInterface(),
dsVersion, configurableServiceProperties, referenceScope
);
- m_unbind = new UnbindMethod(
+ m_unbind = new org.apache.felix.scr.impl.helper.UnbindMethod(
m_dependencyMetadata.getUnbind(),
instanceClass,
m_dependencyMetadata.getInterface(),
@@ -57,17 +57,17 @@
);
}
- public BindMethod getBind()
+ public ReferenceMethod getBind()
{
return m_bind;
}
- public UnbindMethod getUnbind()
+ public ReferenceMethod getUnbind()
{
return m_unbind;
}
- public UpdatedMethod getUpdated()
+ public ReferenceMethod getUpdated()
{
return m_updated;
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java
index c97e43c..09d10cf 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java
@@ -27,9 +27,8 @@
import org.apache.felix.scr.impl.metadata.DSVersion;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
-
/**
- * @version $Rev:$ $Date:$
+ * @version $Rev$ $Date$
*/
public class ComponentMethods
{
@@ -37,7 +36,7 @@
private ModifiedMethod m_modifiedMethod;
private DeactivateMethod m_deactivateMethod;
- private final Map<String, BindMethods> bindMethodMap = new HashMap<String, BindMethods>();
+ private final Map<String, ReferenceMethods> bindMethodMap = new HashMap<String, ReferenceMethods>();
public synchronized void initComponentMethods( ComponentMetadata componentMetadata, Class<?> implementationObjectClass )
{
@@ -57,9 +56,17 @@
for ( ReferenceMetadata referenceMetadata: componentMetadata.getDependencies() )
{
- String refName = referenceMetadata.getName();
- BindMethods bindMethods = new BindMethods( referenceMetadata, implementationObjectClass, dsVersion, configurableServiceProperties);
- bindMethodMap.put( refName, bindMethods );
+ final String refName = referenceMetadata.getName();
+ final ReferenceMethods methods;
+ if ( referenceMetadata.getField() != null )
+ {
+ methods = new FieldMethods( referenceMetadata, implementationObjectClass, dsVersion, configurableServiceProperties);
+ }
+ else
+ {
+ methods = new BindMethods( referenceMetadata, implementationObjectClass, dsVersion, configurableServiceProperties);
+ }
+ bindMethodMap.put( refName, methods );
}
}
@@ -78,9 +85,9 @@
return m_modifiedMethod;
}
- public BindMethods getBindMethods(String refName )
+ public ReferenceMethods getBindMethods(String refName )
{
- return ( BindMethods ) bindMethodMap.get( refName );
+ return bindMethodMap.get( refName );
}
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java
new file mode 100644
index 0000000..c5e0a86
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java
@@ -0,0 +1,571 @@
+/*
+ * 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 java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.manager.ComponentContextImpl;
+import org.apache.felix.scr.impl.manager.RefPair;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata.ReferenceScope;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * Component method to be invoked on service (un)binding.
+ */
+public class FieldHandler
+{
+
+ // class references to simplify parameter checking
+ protected static final Class<?> MAP_CLASS = Map.class;
+
+ private final String fieldName;
+ private final Class<?> componentClass;
+
+ private volatile Field field;
+
+ private volatile State state;
+
+ public FieldHandler( final String fieldName, final Class<?> componentClass,
+ final String referenceClassName, final ReferenceScope referenceScope)
+ {
+ this.fieldName = fieldName;
+ this.componentClass = componentClass;
+ this.state = NotResolved.INSTANCE;
+ }
+
+ protected final String getFieldName()
+ {
+ return this.fieldName;
+ }
+
+ final Field getField()
+ {
+ return this.field;
+ }
+
+ protected final Class<?> getComponentClass()
+ {
+ return this.componentClass;
+ }
+
+
+ void setField( final Field f, final SimpleLogger logger )
+ {
+ this.field = f;
+
+ if ( f != null )
+ {
+ state = Resolved.INSTANCE;
+ logger.log( LogService.LOG_DEBUG, "Found field: {0}", new Object[]
+ { field }, null );
+ }
+ else
+ {
+ state = NotFound.INSTANCE;
+ logger.log(LogService.LOG_ERROR, "Field [{0}] not found; Component will fail",
+ new Object[]
+ { getFieldName() }, null);
+ }
+ }
+
+
+ State getState()
+ {
+ return state;
+ }
+
+
+ /**
+ * Finds the field named in the {@link #fieldName} field in the given
+ * <code>targetClass</code>. If the target class has no acceptable method
+ * the class hierarchy is traversed until a field is found or the root
+ * of the class hierarchy is reached without finding a field.
+ *
+ * @return The requested field or <code>null</code> if no acceptable field
+ * can be found in the target class or any super class.
+ * @throws InvocationTargetException If an unexpected Throwable is caught
+ * trying to find the requested field.
+ * @param logger
+ */
+ private Field findField( final SimpleLogger logger ) throws InvocationTargetException
+ {
+ final Class<?> targetClass = getComponentClass();
+ final ClassLoader targetClasslLoader = targetClass.getClassLoader();
+ final String targetPackage = getPackageName( targetClass );
+ Class<?> theClass = targetClass;
+ boolean acceptPrivate = true;
+ boolean acceptPackage = true;
+ while (true)
+ {
+
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "Locating field " + getFieldName() + " in class " + theClass.getName(), null );
+ }
+
+ try
+ {
+ final Field field = doFindField( theClass, acceptPrivate, acceptPackage, logger );
+ if ( field != null )
+ {
+ return field;
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException ex )
+ {
+ // log and return null
+ logger.log( LogService.LOG_ERROR,
+ "findField: Suitable but non-accessible field {0} found in class {1}, subclass of {2}", new Object[]
+ { getFieldName(), theClass.getName(), targetClass.getName() }, null );
+ break;
+ }
+
+ // if we get here, we have no field, so check the super class
+ theClass = theClass.getSuperclass();
+ if ( theClass == null )
+ {
+ break;
+ }
+
+ // super class field check ignores private fields and accepts
+ // package fields only if in the same package and package
+ // fields are (still) allowed
+ acceptPackage &= targetClasslLoader == theClass.getClassLoader()
+ && targetPackage.equals( getPackageName( theClass ) );
+
+ // private fields will not be accepted any more in super classes
+ acceptPrivate = false;
+ }
+
+ // nothing found after all these years ...
+ return null;
+ }
+
+
+ /**
+ * Finds the method named in the {@link #m_methodName} field in the given
+ * <code>targetClass</code>. If the target class has no acceptable method
+ * the class hierarchy is traversed until a method is found or the root
+ * of the class hierarchy is reached without finding a method.
+ *
+ *
+ * @param targetClass The class in which to look for the method
+ * @param acceptPrivate <code>true</code> if private methods should be
+ * considered.
+ * @param acceptPackage <code>true</code> if package private methods should
+ * be considered.
+ * @param logger
+ * @return The requested method or <code>null</code> if no acceptable method
+ * can be found in the target class or any super class.
+ * @throws InvocationTargetException If an unexpected Throwable is caught
+ * trying to find the requested method.
+ */
+ private Field doFindField( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
+ throws SuitableMethodNotAccessibleException, InvocationTargetException
+ {
+ // TODO - check field type(!)
+ return getField( targetClass, this.getFieldName(), acceptPrivate, acceptPackage, logger);
+ }
+
+ private Field getField( final Class<?> clazz, final String name, final boolean acceptPrivate,
+ final boolean acceptPackage, final SimpleLogger logger )
+ throws SuitableMethodNotAccessibleException, InvocationTargetException
+ {
+ try
+ {
+ // find the declared field in this class
+ final Field field = clazz.getDeclaredField( name );
+
+ // accept public and protected fields only and ensure accessibility
+ if ( accept( field, acceptPrivate, acceptPackage ) )
+ {
+ return field;
+ }
+
+ // the method would fit the requirements but is not acceptable
+ throw new SuitableMethodNotAccessibleException();
+ }
+ catch ( NoSuchFieldException nsfe )
+ {
+ // thrown if no field is declared with the given name and
+ // parameters
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG, "Declared Field {0}.{1} not found", new Object[]
+ { clazz.getName(), name }, null );
+ }
+ }
+ catch ( NoClassDefFoundError cdfe )
+ {
+ // may be thrown if a method would be found but the signature
+ // contains throws declaration for an exception which cannot
+ // be loaded
+ if ( logger.isLogEnabled( LogService.LOG_WARNING ) )
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append( "Failure loooking up field " ).append( name );
+ buf.append( " in class class " ).append( clazz.getName() ).append( ". Assuming no such field." );
+ logger.log( LogService.LOG_WARNING, buf.toString(), cdfe );
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException e)
+ {
+ throw e;
+ }
+ catch ( Throwable throwable )
+ {
+ // unexpected problem accessing the field, don't let everything
+ // blow up in this situation, just throw a declared exception
+ throw new InvocationTargetException( throwable, "Unexpected problem trying to get field " + name );
+ }
+
+ // caught and ignored exception, assume no field and continue search
+ return null;
+ }
+/*
+ @Override
+ protected Object[] getParameters( Method method, BindParameters bp )
+ {
+ ComponentContextImpl key = bp.getComponentContext();
+ Object[] result = new Object[ m_paramTypes.size()];
+ RefPair<?, ?> refPair = bp.getRefPair();
+ int i = 0;
+ for ( ParamType pt: m_paramTypes ) {
+ switch (pt) {
+ case serviceReference:
+ result[i++] = refPair.getRef();
+ break;
+
+ case serviceObjects:
+ result[i++] = refPair.getServiceObjects();
+ break;
+
+ case map:
+ result[i++] = new ReadOnlyDictionary<String, Object>( refPair.getRef() );
+ break;
+
+ case serviceType:
+ result[i++] = refPair.getServiceObject(key);
+ break;
+
+ default: throw new IllegalStateException("unexpected ParamType: " + pt);
+
+ }
+ }
+ return result;
+ }
+*/
+ private enum METHOD_TYPE {
+ BIND,
+ UNBIND,
+ UPDATED
+ };
+
+ private MethodResult invokeMethod( final METHOD_TYPE mType,
+ final Object componentInstance,
+ final BindParameters bp,
+ final SimpleLogger logger )
+ throws InvocationTargetException
+ {
+ final ComponentContextImpl key = bp.getComponentContext();
+ final RefPair<?, ?> refPair = bp.getRefPair();
+
+ final Object serviceObject = refPair.getServiceObject(key);
+
+ try {
+ if ( mType == METHOD_TYPE.BIND ) {
+ field.set(componentInstance, serviceObject);
+ } else if ( mType == METHOD_TYPE.UNBIND ) {
+ field.set(componentInstance, null);
+ }
+ } catch ( final IllegalArgumentException iae ) {
+ iae.printStackTrace();
+ } catch ( final IllegalAccessException iae ) {
+ iae.printStackTrace();
+
+ }
+ return MethodResult.VOID;
+ }
+
+ /**
+ * Returns <code>true</code> if the field is acceptable to be returned from the
+ * {@link #getField(Class, String, boolean, boolean, SimpleLogger)} and also
+ * makes the field accessible.
+ * <p>
+ * This method returns <code>true</code> if the field:
+ * <ul>
+ * <li>Is not static</li>
+ * <li>Is public or protected</li>
+ * <li>Is private and <code>acceptPrivate</code> is <code>true</code></li>
+ * <li>Is package private and <code>acceptPackage</code> is <code>true</code></li>
+ * </ul>
+ * <p>
+ *
+ * @param field The field to check
+ * @param acceptPrivate Whether a private field is acceptable
+ * @param acceptPackage Whether a package private field is acceptable
+ * @return whether the field is acceptable
+ */
+ private static boolean accept( final Field field, boolean acceptPrivate, boolean acceptPackage )
+ {
+ // check modifiers now
+ int mod = field.getModifiers();
+
+ // no static fields
+ if ( Modifier.isStatic( mod ) )
+ {
+ return false;
+ }
+
+ // accept public and protected fields
+ if ( Modifier.isPublic( mod ) || Modifier.isProtected( mod ) )
+ {
+ setAccessible( field );
+ return true;
+ }
+
+ // accept private if accepted
+ if ( Modifier.isPrivate( mod ) )
+ {
+ if ( acceptPrivate )
+ {
+ setAccessible( field );
+ return true;
+ }
+
+ return false;
+ }
+
+ // accept default (package)
+ if ( acceptPackage )
+ {
+ setAccessible( field );
+ return true;
+ }
+
+ // else don't accept
+ return false;
+ }
+
+ private static void setAccessible(final Field field)
+ {
+ AccessController.doPrivileged( new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ field.setAccessible( true );
+ return null;
+ }
+ } );
+ }
+
+
+ /**
+ * Returns the name of the package to which the class belongs or an
+ * empty string if the class is in the default package.
+ */
+ public static String getPackageName( Class<?> clazz )
+ {
+ String name = clazz.getName();
+ int dot = name.lastIndexOf( '.' );
+ return ( dot > 0 ) ? name.substring( 0, dot ) : "";
+ }
+
+ private static interface State
+ {
+
+ MethodResult invoke( final FieldHandler baseMethod,
+ final METHOD_TYPE mType,
+ final Object componentInstance,
+ final BindParameters rawParameter,
+ final SimpleLogger logger )
+ throws InvocationTargetException;
+ }
+
+ private static class NotResolved implements State
+ {
+ private static final State INSTANCE = new NotResolved();
+
+ private synchronized void resolve( final FieldHandler baseMethod, SimpleLogger logger )
+ {
+ logger.log( LogService.LOG_DEBUG, "getting field: {0}", new Object[]
+ {baseMethod.getFieldName()}, null );
+
+ // resolve the field
+ Field field = null;
+ try
+ {
+ field = baseMethod.findField( logger );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ logger.log( LogService.LOG_WARNING, "{0} cannot be found", new Object[]
+ {baseMethod.getFieldName()}, ex.getTargetException() );
+ }
+
+ baseMethod.setField( field, logger );
+ }
+
+
+ public MethodResult invoke( final FieldHandler baseMethod,
+ final METHOD_TYPE mType,
+ final Object componentInstance,
+ final BindParameters rawParameter,
+ SimpleLogger logger )
+ throws InvocationTargetException
+ {
+ resolve( baseMethod, logger );
+ return baseMethod.getState().invoke( baseMethod, mType, componentInstance, rawParameter, logger );
+ }
+ }
+
+ private static class NotFound implements State
+ {
+ private static final State INSTANCE = new NotFound();
+
+
+ public MethodResult invoke( final FieldHandler baseMethod,
+ final METHOD_TYPE mType,
+ final Object componentInstance,
+ final BindParameters rawParameter,
+ final SimpleLogger logger )
+ {
+ logger.log( LogService.LOG_ERROR, "Field [{1}] not found", new Object[]
+ { baseMethod.getFieldName() }, null );
+ return null;
+ }
+ }
+
+ private static class Resolved implements State
+ {
+ private static final State INSTANCE = new Resolved();
+
+
+ public MethodResult invoke( final FieldHandler baseMethod,
+ final METHOD_TYPE mType,
+ final Object componentInstance,
+ final BindParameters rawParameter,
+ final SimpleLogger logger )
+ throws InvocationTargetException
+ {
+ return baseMethod.invokeMethod( mType, componentInstance, rawParameter, logger );
+ }
+ }
+
+ public ReferenceMethod getBind() {
+ return new ReferenceMethod() {
+
+ public MethodResult invoke(Object componentInstance,
+ BindParameters rawParameter,
+ MethodResult methodCallFailureResult, SimpleLogger logger) {
+ try
+ {
+ return state.invoke( FieldHandler.this, METHOD_TYPE.BIND, componentInstance, rawParameter, logger );
+ }
+ catch ( InvocationTargetException ite )
+ {
+ logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
+ { getFieldName() }, ite.getCause() );
+ }
+
+ return methodCallFailureResult;
+ }
+
+ public <S, T> boolean getServiceObject(ComponentContextImpl<S> key,
+ RefPair<S, T> refPair, BundleContext context,
+ SimpleLogger logger) {
+ //??? this resolves which we need.... better way?
+ if ( refPair.getServiceObject(key) == null )
+ {
+ return refPair.getServiceObject(key, context, logger);
+ }
+ return true;
+ }
+ };
+ }
+
+ public ReferenceMethod getUnbind() {
+ return new ReferenceMethod() {
+
+ public MethodResult invoke(Object componentInstance,
+ BindParameters rawParameter,
+ MethodResult methodCallFailureResult, SimpleLogger logger) {
+ try
+ {
+ return state.invoke( FieldHandler.this, METHOD_TYPE.UNBIND, componentInstance, rawParameter, logger );
+ }
+ catch ( InvocationTargetException ite )
+ {
+ logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
+ { getFieldName() }, ite.getCause() );
+ }
+
+ return methodCallFailureResult;
+ }
+
+ public <S, T> boolean getServiceObject(ComponentContextImpl<S> key,
+ RefPair<S, T> refPair, BundleContext context,
+ SimpleLogger logger) {
+ // TODO ?!?
+ return true;
+ }
+ };
+ }
+
+ public ReferenceMethod getUpdated() {
+ return new ReferenceMethod() {
+
+ public MethodResult invoke(Object componentInstance,
+ BindParameters rawParameter,
+ MethodResult methodCallFailureResult, SimpleLogger logger) {
+ try
+ {
+ return state.invoke( FieldHandler.this, METHOD_TYPE.UPDATED, componentInstance, rawParameter, logger );
+ }
+ catch ( InvocationTargetException ite )
+ {
+ logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
+ { getFieldName() }, ite.getCause() );
+ }
+
+ return methodCallFailureResult;
+ }
+
+ public <S, T> boolean getServiceObject(ComponentContextImpl<S> key,
+ RefPair<S, T> refPair, BundleContext context,
+ SimpleLogger logger) {
+ //??? this resolves which we need.... better way?
+ if ( refPair.getServiceObject(key) == null )
+ {
+ return refPair.getServiceObject(key, context, logger);
+ }
+ return true;
+ }
+ };
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldMethods.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldMethods.java
new file mode 100644
index 0000000..f4d693e
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldMethods.java
@@ -0,0 +1,61 @@
+/*
+ * 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.metadata.DSVersion;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class FieldMethods implements ReferenceMethods
+{
+ private final FieldHandler handler;
+
+ public FieldMethods( final ReferenceMetadata m_dependencyMetadata,
+ final Class<?> instanceClass,
+ final DSVersion dsVersion,
+ final boolean configurableServiceProperties )
+ {
+ handler = new FieldHandler(
+ m_dependencyMetadata.getField(),
+ instanceClass,
+ m_dependencyMetadata.getInterface(),
+ m_dependencyMetadata.getScope()
+ );
+ }
+
+ public ReferenceMethod getBind()
+ {
+ return handler.getBind();
+ }
+
+ public ReferenceMethod getUnbind()
+ {
+ return handler.getUnbind();
+ }
+
+ public ReferenceMethod getUpdated()
+ {
+ return handler.getUpdated();
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethod.java
new file mode 100644
index 0000000..359f5a8
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethod.java
@@ -0,0 +1,37 @@
+/*
+ * 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.ComponentContextImpl;
+import org.apache.felix.scr.impl.manager.RefPair;
+import org.osgi.framework.BundleContext;
+
+
+
+
+/**
+ * Component method to be invoked on service (un)binding.
+ */
+public interface ReferenceMethod
+{
+ MethodResult invoke( final Object componentInstance, final BindParameters rawParameter,
+ final MethodResult methodCallFailureResult, SimpleLogger logger );
+
+ <S, T> boolean getServiceObject( ComponentContextImpl<S> key, RefPair<S, T> refPair, BundleContext context, SimpleLogger logger );
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethods.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethods.java
new file mode 100644
index 0000000..63677d5
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReferenceMethods.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface ReferenceMethods
+{
+
+ ReferenceMethod getBind();
+
+ ReferenceMethod getUnbind();
+
+ ReferenceMethod getUpdated();
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
index ebc12da..7d6b73b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
@@ -26,6 +26,7 @@
* Component method to be invoked on service unbinding.
*/
public class UnbindMethod extends BindMethod
+implements org.apache.felix.scr.impl.helper.ReferenceMethod
{
public UnbindMethod( final String methodName,
@@ -35,6 +36,7 @@
}
+ @Override
protected String getMethodNamePrefix()
{
return "unbind";
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
index 1f6c921..61dcd53 100644
--- 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
@@ -26,6 +26,7 @@
* Component method to be invoked on service property update of a bound service.
*/
public class UpdatedMethod extends BindMethod
+implements org.apache.felix.scr.impl.helper.ReferenceMethod
{
public UpdatedMethod( final String methodName,
@@ -35,6 +36,7 @@
}
+ @Override
protected String getMethodNamePrefix()
{
return "update";
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 6c5d9f3..c172c6a 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
@@ -33,11 +33,11 @@
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.config.ReferenceManager;
-import org.apache.felix.scr.impl.helper.BindMethod;
-import org.apache.felix.scr.impl.helper.BindMethods;
import org.apache.felix.scr.impl.helper.BindParameters;
import org.apache.felix.scr.impl.helper.Coercions;
import org.apache.felix.scr.impl.helper.MethodResult;
+import org.apache.felix.scr.impl.helper.ReferenceMethod;
+import org.apache.felix.scr.impl.helper.ReferenceMethods;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata.ReferenceScope;
import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
@@ -57,7 +57,7 @@
* declared by a single <code><reference></code element in component
* descriptor.
*/
-public class DependencyManager<S, T> implements ReferenceManager<S, T>
+public class DependencyManager<S, T> implements ReferenceManager<S, T>
{
// the component to which this dependency belongs
@@ -65,13 +65,13 @@
// Reference to the metadata
private final ReferenceMetadata m_dependencyMetadata;
-
+
private final int m_index;
private final Customizer<S, T> m_customizer;
//only set once, but it's not clear there is enough other synchronization to get the correct object before it's used.
- private volatile BindMethods m_bindMethods;
+ private volatile ReferenceMethods m_bindMethods;
//reset on filter change
private volatile ServiceTracker<T, RefPair<S, T>> m_tracker;
@@ -95,7 +95,7 @@
m_dependencyMetadata = dependency;
m_index = index;
m_customizer = newCustomizer();
-
+
m_minCardinality = defaultMinimumCardinality( dependency );
// dump the reference information if DEBUG is enabled
@@ -104,10 +104,8 @@
m_componentManager
.log(
LogService.LOG_DEBUG,
- "Dependency Manager {0} created: interface={1}, filter={2}, policy={3}, cardinality={4}, bind={5}, unbind={6}",
- new Object[]
- { getName(), dependency.getInterface(), dependency.getTarget(), dependency.getPolicy(),
- dependency.getCardinality(), dependency.getBind(), dependency.getUnbind() }, null );
+ "Dependency Manager created " + dependency.getDebugInfo(),
+ null );
}
}
@@ -115,16 +113,16 @@
{
return dependency.isOptional()? 0: 1;
}
-
- int getIndex()
+
+ int getIndex()
{
return m_index;
- }
+ }
/**
* Initialize binding methods.
*/
- void initBindingMethods(BindMethods bindMethods)
+ void initBindingMethods(ReferenceMethods bindMethods)
{
m_bindMethods = bindMethods;
}
@@ -144,7 +142,7 @@
Collection<RefPair<S, T>> getRefs( AtomicInteger trackingCount );
boolean isSatisfied();
-
+
void setTracker( ServiceTracker<T, RefPair<S, T>> tracker );
void setTrackerOpened();
@@ -334,9 +332,9 @@
tracked = true;
m_componentManager.activateInternal( trackingCount );
}
- else
+ else
{
- m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleDynamic, inactive, doing nothing: tracker opened: {2}, optional: {3}", new Object[] {getName(), trackingCount, isTrackerOpened(), isOptional()}, null );
+ m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleDynamic, inactive, doing nothing: tracker opened: {2}, optional: {3}", new Object[] {getName(), trackingCount, isTrackerOpened(), isOptional()}, null );
}
}
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleDynamic added {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );
@@ -420,7 +418,7 @@
ServiceTracker<T, RefPair<S, T>> tracker = getTracker();
if (tracker == null) {
trackingCount.set( lastRefPairTrackingCount );
- return Collections.emptyList();
+ return Collections.emptyList();
}
return getTracker().getTracked( null, trackingCount ).values();
}
@@ -492,7 +490,7 @@
m_componentManager.log( LogService.LOG_DEBUG,
"Dependency Manager: Static dependency on {0}/{1} is broken", new Object[]
{getName(), m_dependencyMetadata.getInterface()}, null );
- m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
}
//This is unlikely
ungetService( refPair );
@@ -534,8 +532,8 @@
{
ServiceTracker<T, RefPair<S, T>> tracker = getTracker();
if (tracker == null) {
- return Collections.emptyList();
- }
+ return Collections.emptyList();
+ }
return tracker.getTracked( null, trackingCount ).values();
}
}
@@ -567,7 +565,7 @@
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleStaticReluctant modified {2} (enter)", new Object[] {getName(), trackingCount, serviceReference}, null );
Collection<RefPair<S, T>> refs = this.refs.get();
if (isActive() && refs.contains( refPair ))
- {
+ {
m_componentManager.invokeUpdatedMethod( DependencyManager.this, refPair, trackingCount );
}
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleStaticReluctant modified {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );
@@ -600,7 +598,7 @@
m_componentManager.log( LogService.LOG_DEBUG,
"Dependency Manager: Static dependency on {0}/{1} is broken", new Object[]
{getName(), m_dependencyMetadata.getInterface()}, null );
- m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
}
ungetService( refPair );
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleStaticReluctant removed {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );
@@ -635,13 +633,13 @@
if ( this.refs.compareAndSet( null, refs ) )
{
this.trackingCount = trackingCount.get();
- }
- else
+ }
+ else
{
//some other thread got done first. If we have more refPairs, we might need to unget some services.
Collection<RefPair<S, T>> actualRefs = this.refs.get();
refs.removeAll( actualRefs );
- for (RefPair<S, T> ref: refs)
+ for (RefPair<S, T> ref: refs)
{
ungetService( ref );
}
@@ -770,14 +768,14 @@
trackingCount2 );
nextRefPair = tracked.values().iterator().next();
}
-
+
//n.b. we cannot use cardinalitySatisfied( serviceCount ) here as the call may come from an old tracker during target change.
if ( isEffectivelyOptional() || nextRefPair != null )
{
oldRefPair = this.refPair;
this.refPair = null;
}
- else
+ else
{
deactivate = true; //required and no replacement service, deactivate
}
@@ -840,7 +838,7 @@
}
}
}
- if (refPair != null)
+ if (refPair != null)
{
success |= getServiceObject( key, m_bindMethods.getBind(), refPair );
if ( refPair.isFailed() )
@@ -914,18 +912,18 @@
m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
m_componentManager.activateInternal( trackingCount );
}
- else
+ else
{
- m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic active but new {2} is worse match than old {3}", new Object[] {getName(), trackingCount, refPair, this.refPair, }, null );
+ m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic active but new {2} is worse match than old {3}", new Object[] {getName(), trackingCount, refPair, this.refPair, }, null );
}
}
else if (isTrackerOpened() && cardinalityJustSatisfied( serviceCount ) )
{
m_componentManager.activateInternal( trackingCount );
}
- else
+ else
{
- m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic active: {2} trackerOpened: {3} optional: {4}", new Object[] {getName(), trackingCount, isActive(), isTrackerOpened(), isOptional()}, null );
+ m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic active: {2} trackerOpened: {3} optional: {4}", new Object[] {getName(), trackingCount, isActive(), isTrackerOpened(), isOptional()}, null );
}
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic added {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );
}
@@ -1113,13 +1111,13 @@
private boolean cardinalitySatisfied(int serviceCount)
{
return m_minCardinality <= serviceCount;
- }
-
+ }
+
private boolean cardinalityJustSatisfied(int serviceCount)
{
return m_minCardinality == serviceCount;
}
-
+
private boolean isMultiple()
{
return m_dependencyMetadata.isMultiple();
@@ -1704,7 +1702,7 @@
"DependencyManager : Component not set, no need to call unbind method", null );
}
}
-
+
//------------- Service target filter support -----------------------------
/**
@@ -1733,7 +1731,7 @@
final String newTarget = ( String ) properties.get( m_dependencyMetadata.getTargetPropertyName() );
final String currentTarget = getTarget();
int newMinimumCardinality = getMinimumCardinality( properties );
- if ( m_minCardinality == newMinimumCardinality &&
+ if ( m_minCardinality == newMinimumCardinality &&
( ( currentTarget == null && newTarget == null )
|| ( currentTarget != null && currentTarget.equals( newTarget ) ) ) )
{
@@ -1806,7 +1804,7 @@
m_componentManager.log( LogService.LOG_WARNING, "Invalid minimum cardinality property for dependency {0}: {1}", new Object[]
{getName(), e.getMessage()}, null );
}
- if (minimumCardinality != null &&
+ if (minimumCardinality != null &&
(minimumCardinality < defaultMinimumCardinality( m_dependencyMetadata ) ||
(!m_dependencyMetadata.isMultiple() && minimumCardinality > 1 )))
{
@@ -1876,7 +1874,7 @@
{
m_componentManager.log( LogService.LOG_ERROR, "Invalid syntax in target property for dependency {0} to {1}", new Object[]
{getName(), target}, null );
-
+
//create a filter that will never be satisfied
filterString = "(component.id=-1)";
try
@@ -1895,7 +1893,7 @@
{
m_componentManager.log( LogService.LOG_ERROR, "Bundle is shut down for dependency {0} to {1}", new Object[]
{getName(), target}, null );
- return;
+ return;
}
m_customizer.setPreviousRefMap( refMap );
@@ -1906,7 +1904,7 @@
m_customizer.setTracker( tracker );
//set minimum cardinality
m_minCardinality = minimumCardinality;
-
+
tracker.open( m_componentManager.getTrackingCount() );
m_customizer.setTrackerOpened();
if ( oldTracker != null )
@@ -1994,19 +1992,20 @@
}
+ @Override
public String toString()
{
return "DependencyManager: Component [" + m_componentManager + "] reference [" + getName() + "]";
}
- boolean getServiceObject(ComponentContextImpl<S> key, BindMethod bindMethod, RefPair<S, T> refPair)
+ boolean getServiceObject(ComponentContextImpl<S> key, ReferenceMethod bindMethod, RefPair<S, T> refPair)
{
BundleContext bundleContext = m_componentManager.getBundleContext();
if ( bundleContext != null )
{
return bindMethod.getServiceObject( key, refPair, bundleContext, m_componentManager );
}
- else
+ else
{
refPair.setFailed();
return false;
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 e482025..a486bc6 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
@@ -22,11 +22,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -36,7 +33,6 @@
import org.apache.felix.scr.impl.helper.Logger;
import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
import org.osgi.service.component.ComponentException;
-import org.osgi.service.log.LogService;
/**
@@ -117,7 +113,7 @@
// List of service references, (required services 0..*)
private List<ReferenceMetadata> m_references = new ArrayList<ReferenceMetadata>();
-
+
private boolean m_configurableServiceProperties;
private boolean m_persistentFactoryComponent;
private boolean m_deleteCallsModify;
@@ -411,7 +407,7 @@
this.m_delayedKeepInstances = delayedKeepInstances;
}
-
+
/////////////////////////////////////////// GETTERS //////////////////////////////////////
@@ -425,7 +421,7 @@
return m_dsVersion;
}
-
+
/**
* Returns the name of the component
*
@@ -461,7 +457,7 @@
}
return m_configurationPid;
}
-
+
public int getPidIndex(TargetedPID pid)
{
if ( !m_validated )
@@ -631,10 +627,10 @@
{
return m_service;
}
-
+
public Scope getServiceScope()
{
- if (m_service == null)
+ if (m_service == null)
{
return Scope.singleton;
}
@@ -841,7 +837,7 @@
{
if (!m_dsVersion.isDS13())
{
- throw validationFailure( "Use of '$' configuration-pid wildcard requires DS 1.3 or later namespace " );
+ throw validationFailure( "Use of '$' configuration-pid wildcard requires DS 1.3 or later namespace " );
}
m_configurationPid.set( i, getName() );
}
@@ -915,8 +911,8 @@
throw validationFailure( "factory or immediate must be scope singleton not " + m_service.getScope());
}
}
-
- if (m_dsVersion == DSVersion.DS12Felix)
+
+ if (m_dsVersion == DSVersion.DS12Felix)
{
m_configurableServiceProperties = true;
}
@@ -940,7 +936,7 @@
{
throw validationFailure("Only a factory component can be a persistent factory component");
}
-
+
m_validated = true;
}
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 2903998..c1e746a 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
@@ -30,7 +30,7 @@
public class ReferenceMetadata
{
public enum ReferenceScope {bundle, prototype}
-
+
// constant for option single reference - 0..1
public static final String CARDINALITY_0_1 = "0..1";
@@ -64,6 +64,33 @@
// set of valid policy option settings
private static final Set<String> POLICY_OPTION_VALID;
+ // constant for update field strategy
+ public static final String FIELD_STRATEGY_UPDATE = "update";
+
+ // constant for replace field strategy
+ public static final String FIELD_STRATEGY_REPLACE = "replace";
+
+ // set of valid field strategy settings
+ private static final Set<String> FIELD_STRATEGY_VALID;
+
+ // constant for field value type service
+ public static final String FIELD_VALUE_TYPE_SERVICE = "service";
+
+ // constant for field value type properties
+ public static final String FIELD_VALUE_TYPE_PROPERTIES = "properties";
+
+ // constant for field value type reference
+ public static final String FIELD_VALUE_TYPE_REFERENCE = "reference";
+
+ // constant for field value type serviceobjects
+ public static final String FIELD_VALUE_TYPE_SERVICEOBJECTS = "serviceobjects";
+
+ // constant for field value type tuple
+ public static final String FIELD_VALUE_TYPE_TUPLE = "tuple";
+
+ // set of valid field value type settings
+ private static final Set<String> FIELD_VALUE_TYPE_VALID;
+
// Name for the reference (required)
private String m_name = null;
@@ -85,12 +112,21 @@
// Name of the unbind method (optional)
private String m_unbind = null;
+ // Name of the field (optional, since DS 1.3)
+ private String m_field;
+
+ // Name of the strategy for the field (optional, since DS 1.3)
+ private String m_field_strategy;
+
+ // Name of the value type for the field (optional, since DS 1.3)
+ private String m_field_value_type;
+
// Policy attribute (optional, default = static)
private String m_policy = null;
// Policy option attribute (optional, default = reluctant)
private String m_policy_option = null;
-
+
private String m_scopeName;
private ReferenceScope m_scope = ReferenceScope.bundle;
@@ -103,6 +139,9 @@
// Flag that is set once the component is verified (its properties cannot be changed)
private boolean m_validated = false;
+ // flag indicating this is a field reference
+ private final boolean m_fieldReference;
+
static
{
CARDINALITY_VALID = new TreeSet<String>();
@@ -118,8 +157,26 @@
POLICY_OPTION_VALID = new TreeSet<String>();
POLICY_OPTION_VALID.add( POLICY_OPTION_RELUCTANT );
POLICY_OPTION_VALID.add( POLICY_OPTION_GREEDY );
+
+ FIELD_STRATEGY_VALID = new TreeSet<String>();
+ FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_REPLACE );
+ FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_UPDATE );
+
+ FIELD_VALUE_TYPE_VALID = new TreeSet<String>();
+ FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_PROPERTIES );
+ FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_REFERENCE );
+ FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICE );
+ FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICEOBJECTS );
+ FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_TUPLE );
}
+ public ReferenceMetadata() {
+ this(false);
+ }
+
+ public ReferenceMetadata(final boolean flag) {
+ this.m_fieldReference = flag;
+ }
/////////////////////////////////////////////// setters ///////////////////////////////////
@@ -277,7 +334,53 @@
m_unbind = unbind;
}
- public void setScope(String scopeName) {
+
+ /**
+ * Setter for the field attribute
+ *
+ * @param field the field name
+ */
+ public void setField( final String field )
+ {
+ if ( m_validated )
+ {
+ return;
+ }
+
+ m_field = field;
+ }
+
+ /**
+ * Setter for the field strategy attribute
+ *
+ * @param strategy the field strategy
+ */
+ public void setFieldStrategy( final String strategy )
+ {
+ if ( m_validated )
+ {
+ return;
+ }
+
+ m_field_strategy = strategy;
+ }
+
+ /**
+ * Setter for the field value type attribute
+ *
+ * @param valuetype the field value type
+ */
+ public void setFieldValueType( final String valuetype )
+ {
+ if ( m_validated )
+ {
+ return;
+ }
+
+ m_field_value_type = valuetype;
+ }
+
+ public void setScope(String scopeName) {
if ( m_validated )
{
return;
@@ -390,6 +493,40 @@
}
+ /**
+ * Get the name of a field in the component implementation class that is used to hold
+ * the reference
+ *
+ * @return a String with the name of the field
+ */
+ public String getField()
+ {
+ return m_field;
+ }
+
+
+ /**
+ * Get the strategy of a field in the component implementation class that is used to hold
+ * the reference
+ *
+ * @return a String with the strategy name for the field
+ */
+ public String getFieldStrategy()
+ {
+ return m_field_strategy;
+ }
+
+ /**
+ * Get the value type of a field in the component implementation class that is used to hold
+ * the reference
+ *
+ * @return a String with the value type for the field
+ */
+ public String getFieldValueType()
+ {
+ return m_field_value_type;
+ }
+
// Getters for boolean values that determine both policy and cardinality
/**
@@ -447,7 +584,7 @@
{
return getName() + ".target";
}
-
+
public String getMinCardinalityName()
{
return getName() + ".cardinality.minimum";
@@ -464,7 +601,8 @@
*/
void validate( final ComponentMetadata componentMetadata, final Logger logger )
{
- DSVersion dsVersion = componentMetadata.getDSVersion();
+ final DSVersion dsVersion = componentMetadata.getDSVersion();
+
if ( m_name == null )
{
// 112.10 name attribute is optional, defaults to interface since DS 1.1
@@ -512,30 +650,103 @@
throw componentMetadata.validationFailure( "Policy option must be reluctant for DS < 1.2" );
}
-
- // updated method is only supported in namespace xxx and later
- if ( m_updated != null && !(dsVersion.isDS12() || dsVersion == DSVersion.DS11Felix) )
- {
- // FELIX-3648 validation must fail (instead of just ignore)
- throw componentMetadata.validationFailure( "updated method declaration requires DS 1.2 or later namespace " );
- }
-
if (m_scopeName != null) {
if ( !dsVersion.isDS13() )
{
throw componentMetadata.validationFailure( "reference scope can be set only for DS >= 1.3");
}
- try
+ try
{
m_scope = ReferenceScope.valueOf(m_scopeName);
}
catch (IllegalArgumentException e)
{
throw componentMetadata.validationFailure( "reference scope must be 'bundle' or 'prototype' not " + m_scopeName);
-
+
}
}
+
+ // checks for event based injection
+ if ( !m_fieldReference )
+ {
+ // updated method is only supported in namespace xxx and later
+ if ( m_updated != null && !(dsVersion.isDS12() || dsVersion == DSVersion.DS11Felix) )
+ {
+ // FELIX-3648 validation must fail (instead of just ignore)
+ throw componentMetadata.validationFailure( "updated method declaration requires DS 1.2 or later namespace " );
+ }
+ }
+
+ // checks for field injection
+ if ( m_fieldReference )
+ {
+ // field reference requires DS 1.3
+ if ( !dsVersion.isDS13() )
+ {
+ throw componentMetadata.validationFailure( "Field reference requires DS >= 1.3" );
+ }
+
+ // field strategy
+ if ( m_field_strategy == null )
+ {
+ setFieldStrategy( FIELD_STRATEGY_REPLACE );
+ }
+ else if ( !FIELD_STRATEGY_VALID.contains( m_field_strategy ) )
+ {
+ throw componentMetadata.validationFailure( "Field strategy must be one of " + FIELD_STRATEGY_VALID );
+ }
+ if ( m_cardinality.equals(CARDINALITY_1_1) || m_cardinality.equals(CARDINALITY_0_1) )
+ {
+ // update is not allowed for unary references
+ if ( m_field_strategy.equals(FIELD_STRATEGY_UPDATE) )
+ {
+ throw componentMetadata.validationFailure( "Field strategy update not allowed for unary field references." );
+ }
+ }
+
+ // field value type
+ if ( m_cardinality.equals(CARDINALITY_1_1) || m_cardinality.equals(CARDINALITY_0_1) )
+ {
+ // value type must not be specified for unary references
+ if ( m_field_value_type != null )
+ {
+ throw componentMetadata.validationFailure( "Field value type must not be set for unary field references." );
+ }
+ }
+ else
+ {
+ if ( m_field_value_type == null )
+ {
+ setFieldValueType( FIELD_VALUE_TYPE_SERVICE );
+ }
+ else if ( !FIELD_VALUE_TYPE_VALID.contains( m_field_value_type ) )
+ {
+ throw componentMetadata.validationFailure( "Field value type must be one of " + FIELD_VALUE_TYPE_VALID );
+ }
+ }
+
+ }
+
+
m_validated = true;
}
+ public String getDebugInfo()
+ {
+ if ( this.m_fieldReference )
+ {
+ return getField() +
+ "interface=" + this.getInterface() +
+ ", filter=" + this.getTarget() +
+ ", policy=" + this.getPolicy() +
+ ", cardinality=" + this.getCardinality();
+ }
+ return getName() +
+ "interface=" + this.getInterface() +
+ ", filter=" + this.getTarget() +
+ ", policy=" + this.getPolicy() +
+ ", cardinality=" + this.getCardinality() +
+ ", bind=" + this.getBind() +
+ ", unbind=" + this.getUnbind();
+ }
}
\ 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 c058923..631ec01 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
@@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
+
import org.apache.felix.scr.impl.helper.Logger;
import org.apache.felix.scr.impl.parser.KXml2SAXHandler;
import org.apache.felix.scr.impl.parser.KXml2SAXParser.Attributes;
@@ -63,18 +64,18 @@
// Namespace URI of DS 1.3
public static final String NAMESPACE_URI_1_3 = "http://www.osgi.org/xmlns/scr/v1.3.0";
- // Namespace URI of felis DS extensions 1.0
+ // Namespace URI of Felix DS extensions 1.0
public static final String NAMESPACE_URI_1_0_FELIX_EXTENSIONS = "http://felix.apache.org/xmlns/scr/extensions/v1.0.0";
-
+
//extension features
public static final String CONFIGURABLE_SERVICE_PROPERTIES = "configurableServiceProperties";
public static final String PERSISTENT_FACTORY_COMPONENT = "persistentFactoryComponent";
-
+
public static final String DELETE_CALLS_MODIFY = "deleteCallsModify";
-
+
public static final String OBSOLETE_FACTORY_COMPONENT_FACTORY = "obsoleteFactoryComponentFactory";
-
+
public static final String CONFIGURE_WITH_INTERFACES = "configureWithInterfaces";
public static final String DELAYED_KEEP_INSTANCES = "delayedKeepInstances";
@@ -108,9 +109,9 @@
// logger for any messages
private final Logger m_logger;
-
+
private final boolean m_globalObsoleteFactoryComponentFactory;
-
+
private final boolean m_globalDelayedKeepInstances;
// A reference to the current component
@@ -275,7 +276,7 @@
String[] configurationPid = configurationPidString.split( " " );
m_currentComponent.setConfigurationPid( configurationPid );
}
-
+
m_currentComponent.setConfigurableServiceProperties("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURABLE_SERVICE_PROPERTIES)));
m_currentComponent.setPersistentFactoryComponent("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, PERSISTENT_FACTORY_COMPONENT)));
m_currentComponent.setDeleteCallsModify("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELETE_CALLS_MODIFY)));
@@ -343,7 +344,7 @@
{
m_currentService.setServiceFactory( attributes.getAttribute( "servicefactory" ).equals( "true" ) );
}
-
+
if ( attributes.getAttribute( "scope" ) != null )
{
m_currentService.setScope( attributes.getAttribute( "scope" ) );
@@ -397,7 +398,7 @@
prop.setName( (ref.getName() == null? ref.getInterface(): ref.getName()) + ".target");
prop.setValue( attributes.getAttribute( "target" ) );
m_currentComponent.addProperty( prop );
-
+
}
ref.setBind( attributes.getAttribute( "bind" ) );
ref.setUpdated( attributes.getAttribute( "updated" ) );
@@ -405,6 +406,50 @@
m_currentComponent.addDependency( ref );
}
+ // 112.x.x Field Reference element
+ else if ( localName.equals( "field-reference" ) )
+ {
+ ReferenceMetadata ref = new ReferenceMetadata(true);
+
+ ref.setInterface( attributes.getAttribute( "interface" ) );
+
+ // Cardinality
+ if ( attributes.getAttribute( "cardinality" ) != null )
+ {
+ ref.setCardinality( attributes.getAttribute( "cardinality" ) );
+ }
+
+ if ( attributes.getAttribute( "policy" ) != null )
+ {
+ ref.setPolicy( attributes.getAttribute( "policy" ) );
+ }
+
+ if ( attributes.getAttribute( "policy-option" ) != null )
+ {
+ ref.setPolicyOption( attributes.getAttribute( "policy-option" ) );
+ }
+
+ if ( attributes.getAttribute( "scope" ) != null )
+ {
+ ref.setScope( attributes.getAttribute( "scope" ) );
+ }
+
+ if ( attributes.getAttribute( "target" ) != null)
+ {
+ ref.setTarget( attributes.getAttribute( "target" ) );
+ PropertyMetadata prop = new PropertyMetadata();
+ prop.setName( (ref.getName() == null? ref.getInterface(): ref.getName()) + ".target");
+ prop.setValue( attributes.getAttribute( "target" ) );
+ m_currentComponent.addProperty( prop );
+
+ }
+
+ ref.setField( attributes.getAttribute( "field" ) );
+ ref.setFieldStrategy( attributes.getAttribute( "strategy" ) );
+ ref.setFieldValueType( attributes.getAttribute( "valuetype" ) );
+
+ m_currentComponent.addDependency( ref );
+ }
// unexpected element (except the root element "components"
// used by the Maven SCR Plugin, which is just silently ignored)
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
index 39a4c2e..3c4031c 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
@@ -29,6 +29,9 @@
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.helper.ActivateMethod;
+import org.apache.felix.scr.impl.helper.ActivatorParameter;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
import org.apache.felix.scr.impl.manager.SingleComponentManager;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.apache.felix.scr.impl.metadata.DSVersion;