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>&lt;reference&gt;</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;