FELIX-4631 : [DS][R6/RFC212] Implement field injection. Move common class handling in utility class
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1637759 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
index 474e359..5108a1c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
@@ -46,8 +46,8 @@
public ActivateMethod( final String methodName,
final boolean methodRequired,
final Class<?> componentClass,
- final DSVersion dsVersion,
- final boolean configurableServiceProperties,
+ final DSVersion dsVersion,
+ final boolean configurableServiceProperties,
boolean supportsInterfaces )
{
super( methodName, methodRequired, componentClass, dsVersion, configurableServiceProperties );
@@ -55,6 +55,7 @@
}
+ @Override
protected Method doFindMethod( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
throws SuitableMethodNotAccessibleException, InvocationTargetException
{
@@ -92,7 +93,7 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
if (getDSVersion().isDS13() && isAnnotation(type))
{
@@ -100,15 +101,15 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
- if (type == MAP_CLASS)
+ if (type == ClassUtils.MAP_CLASS)
{
if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
if (type == int.class)
{
@@ -116,7 +117,7 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
if (type == Integer.class)
{
@@ -124,9 +125,9 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
-
+
}
else if (parameterTypes.length > 1)
{
@@ -135,14 +136,14 @@
{
accept = type == COMPONENT_CONTEXT_CLASS
|| type == BUNDLE_CONTEXT_CLASS
- || type == MAP_CLASS
+ || type == ClassUtils.MAP_CLASS
|| ( isDeactivate() && ( type == int.class || type == Integer.class))
|| ( getDSVersion().isDS13() && isAnnotation(type));
- if ( !accept )
+ if ( !accept )
{
break;
}
-
+
}
if (accept)
{
@@ -150,9 +151,9 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
-
+
}
else //no parameters
{
@@ -160,12 +161,12 @@
{
return m;
}
- suitableMethodNotAccessible = true;
+ suitableMethodNotAccessible = true;
}
-
+
}
}
-
+
if ( suitableMethodNotAccessible )
{
throw new SuitableMethodNotAccessibleException();
@@ -222,8 +223,8 @@
if (t2 == BUNDLE_CONTEXT_CLASS) return 1;
if (isAnnotation(t1)) return isAnnotation(t2)? 0: -1;
if (isAnnotation(t2)) return 1;
- if (t1 == MAP_CLASS) return -1;
- if (t2 == MAP_CLASS) return 1;
+ if (t1 == ClassUtils.MAP_CLASS) return -1;
+ if (t2 == ClassUtils.MAP_CLASS) return 1;
if (t1 == int.class) return -1;
if (t2 == int.class) return 1;
if (t1 == Integer.class) return -1;
@@ -239,14 +240,15 @@
private boolean isAnnotation(final Class<?> t1)
{
- return t1.isAnnotation() || (m_supportsInterfaces && t1.isInterface() && !(t1 == MAP_CLASS));
+ return t1.isAnnotation() || (m_supportsInterfaces && t1.isInterface() && !(t1 == ClassUtils.MAP_CLASS));
}
-
+
+ @Override
protected Object[] getParameters( Method method, ActivatorParameter rawParameter )
{
final Class<?>[] parameterTypes = method.getParameterTypes();
- final ActivatorParameter ap = ( ActivatorParameter ) rawParameter;
+ final ActivatorParameter ap = rawParameter;
final Object[] param = new Object[parameterTypes.length];
for ( int i = 0; i < param.length; i++ )
{
@@ -258,7 +260,7 @@
{
param[i] = ap.getComponentContext().getBundleContext();
}
- else if ( parameterTypes[i] == MAP_CLASS )
+ else if ( parameterTypes[i] == ClassUtils.MAP_CLASS )
{
// note: getProperties() returns a ReadOnlyDictionary which is a Map
param[i] = ap.getComponentContext().getProperties();
@@ -266,10 +268,10 @@
else if ( parameterTypes[i] == INTEGER_CLASS || parameterTypes[i] == Integer.TYPE )
{
param[i] = ap.getReason();
- }
+ }
else
{
- param[i] = Annotations.toObject(parameterTypes[i],
+ param[i] = Annotations.toObject(parameterTypes[i],
(Map<String, Object>) ap.getComponentContext().getProperties(),
ap.getComponentContext().getBundleContext().getBundle(), m_supportsInterfaces);
}
@@ -279,11 +281,13 @@
}
+ @Override
protected String getMethodNamePrefix()
{
return "activate";
}
+ @Override
public MethodResult invoke( Object componentInstance, ActivatorParameter rawParameter, final MethodResult methodCallFailureResult, SimpleLogger logger )
{
if (methodExists( logger ))
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 d5df715..7fb7f38 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
@@ -37,9 +37,6 @@
public abstract class BaseMethod<P>
{
- // class references to simplify parameter checking
- protected static final Class<?> MAP_CLASS = Map.class;
-
private final DSVersion dsVersion;
private final boolean configurableServiceProperties;
@@ -401,7 +398,7 @@
*/
protected static boolean accept( final Method method, boolean acceptPrivate, boolean acceptPackage, boolean allowReturnValue )
{
- if (!(Void.TYPE == method.getReturnType() || (MAP_CLASS == method.getReturnType() && allowReturnValue)))
+ if (!(Void.TYPE == method.getReturnType() || (ClassUtils.MAP_CLASS == method.getReturnType() && allowReturnValue)))
{
return false;
}
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 af0a336..d543060 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
@@ -26,18 +26,13 @@
import java.util.List;
import java.util.Map;
-import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.manager.ComponentContextImpl;
import org.apache.felix.scr.impl.manager.RefPair;
import org.apache.felix.scr.impl.metadata.DSVersion;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata.ReferenceScope;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceObjects;
-import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
-import org.osgi.service.packageadmin.ExportedPackage;
-import org.osgi.service.packageadmin.PackageAdmin;
/**
@@ -46,24 +41,6 @@
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 {
- serviceObjectsClass = ServiceObjects.class;
- }
- catch (Throwable t)
- {
- //can't load class
- }
- SERVICE_OBJECTS_CLASS = serviceObjectsClass;
- }
-
private final String m_referenceClassName;
private final ReferenceMetadata.ReferenceScope m_referenceScope;
@@ -168,7 +145,7 @@
}
// for further methods we need the class of the service object
- final Class<?> parameterClass = getParameterClass( targetClass, logger );
+ final Class<?> parameterClass = ClassUtils.getClassFromComponentClassLoader( targetClass, m_referenceClassName, logger );
if ( parameterClass != null )
{
@@ -262,9 +239,9 @@
boolean specialMatch = true;
List<ParamType> paramTypes = new ArrayList<ParamType>(parameterTypes.length);
for (Class<?> paramType: parameterTypes) {
- if (paramType == SERVICE_REFERENCE_CLASS)
+ if (paramType == ClassUtils.SERVICE_REFERENCE_CLASS)
{
- if (specialMatch && parameterClass == SERVICE_REFERENCE_CLASS)
+ if (specialMatch && parameterClass == ClassUtils.SERVICE_REFERENCE_CLASS)
{
specialMatch = false;
paramTypes.add(ParamType.serviceType);
@@ -274,9 +251,9 @@
paramTypes.add(ParamType.serviceReference);
}
}
- else if (paramType == SERVICE_OBJECTS_CLASS)
+ else if (paramType == ClassUtils.SERVICE_OBJECTS_CLASS)
{
- if (specialMatch && parameterClass == SERVICE_OBJECTS_CLASS)
+ if (specialMatch && parameterClass == ClassUtils.SERVICE_OBJECTS_CLASS)
{
specialMatch = false;
paramTypes.add(ParamType.serviceType);
@@ -343,118 +320,6 @@
return null;
}
-
- /**
- * Returns the class object representing the class of the service reference
- * named by the {@link #m_referenceClassName} field. The class loader of
- * the <code>targetClass</code> is used to load the service class.
- * <p>
- * It may well be possible, that the classloader of the target class cannot
- * see the service object class, for example if the service reference is
- * inherited from a component class of another bundle.
- *
- * @return The class object for the referred to service or <code>null</code>
- * if the class loader of the <code>targetClass</code> cannot see that
- * class.
- */
- private Class<?> getParameterClass( final Class<?> targetClass, SimpleLogger logger )
- {
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log(
- LogService.LOG_DEBUG,
- "getParameterClass: Looking for interface class {0} through loader of {1}",
- new Object[] {m_referenceClassName, targetClass.getName()}, null );
- }
-
- try
- {
- // need the class loader of the target class, which may be the
- // system classloader, which case getClassLoader may retur null
- ClassLoader loader = targetClass.getClassLoader();
- if ( loader == null )
- {
- loader = ClassLoader.getSystemClassLoader();
- }
-
- final Class<?> referenceClass = loader.loadClass( m_referenceClassName );
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: Found class {0}", new Object[] {referenceClass.getName()}, null );
- }
- return referenceClass;
- }
- catch ( ClassNotFoundException cnfe )
- {
- // if we can't load the class, perhaps the method is declared in a
- // super class so we try this class next
- }
-
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: Not found through component class, using PackageAdmin service", null );
- }
-
- // try to load the class with the help of the PackageAdmin service
- PackageAdmin pa = ( PackageAdmin ) Activator.getPackageAdmin();
- if ( pa != null )
- {
- final String referenceClassPackage = m_referenceClassName.substring( 0, m_referenceClassName
- .lastIndexOf( '.' ) );
- ExportedPackage[] pkg = pa.getExportedPackages( referenceClassPackage );
- if ( pkg != null )
- {
- for ( int i = 0; i < pkg.length; i++ )
- {
- try
- {
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log(
- LogService.LOG_DEBUG,
- "getParameterClass: Checking Bundle {0}/{1}",
- new Object[] {pkg[i].getExportingBundle().getSymbolicName(), pkg[i].getExportingBundle().getBundleId()}, null );
- }
-
- Class<?> referenceClass = pkg[i].getExportingBundle().loadClass( m_referenceClassName );
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: Found class {0}", new Object[] {referenceClass.getName()}, null );
- }
- return referenceClass;
- }
- catch ( ClassNotFoundException cnfe )
- {
- // exported package does not provide the interface !!!!
- }
- }
- }
- else if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: No bundles exporting package {0} found", new Object[] {referenceClassPackage}, null );
- }
- }
- else if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: PackageAdmin service not available, cannot find class", null );
- }
-
- // class cannot be found, neither through the component nor from an
- // export, so we fall back to assuming Object
- if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
- {
- logger.log( LogService.LOG_DEBUG,
- "getParameterClass: No class found, falling back to class Object", null );
- }
- return OBJECT_CLASS;
- }
-
-
/**
* Returns a method taking a single <code>ServiceReference</code> object
* as a parameter or <code>null</code> if no such method exists.
@@ -478,7 +343,7 @@
throws SuitableMethodNotAccessibleException, InvocationTargetException
{
return getMethod( targetClass, getMethodName(), new Class[]
- { SERVICE_REFERENCE_CLASS }, acceptPrivate, acceptPackage, logger );
+ { ClassUtils.SERVICE_REFERENCE_CLASS }, acceptPrivate, acceptPackage, logger );
}
private Method getServiceObjectsMethod( final Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
@@ -487,7 +352,7 @@
if ( m_referenceScope == ReferenceMetadata.ReferenceScope.prototype )
{
return getMethod(targetClass, getMethodName(),
- new Class[] { SERVICE_OBJECTS_CLASS }, acceptPrivate, acceptPackage,
+ new Class[] { ClassUtils.SERVICE_OBJECTS_CLASS }, acceptPrivate, acceptPackage,
logger);
}
return null;
@@ -641,7 +506,7 @@
InvocationTargetException
{
return getMethod( targetClass, getMethodName(), new Class[]
- { parameterClass, MAP_CLASS }, acceptPrivate, acceptPackage, logger );
+ { parameterClass, ClassUtils.MAP_CLASS }, acceptPrivate, acceptPackage, logger );
}
@@ -678,7 +543,7 @@
{
// parameters must be refclass,map
- if ( parameters[0].isAssignableFrom( parameterClass ) && parameters[1] == MAP_CLASS )
+ if ( parameters[0].isAssignableFrom( parameterClass ) && parameters[1] == ClassUtils.MAP_CLASS )
{
if ( accept( method, acceptPrivate, acceptPackage, false ) )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ClassUtils.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ClassUtils.java
new file mode 100644
index 0000000..0b90999
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ClassUtils.java
@@ -0,0 +1,170 @@
+/*
+ * 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.util.Map;
+
+import org.apache.felix.scr.impl.Activator;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+
+/**
+ * Utility methods for class handling used by method and field references.
+ */
+public class ClassUtils
+{
+
+ private static final Class<?> OBJECT_CLASS = Object.class;
+
+ public static final Class<?> SERVICE_REFERENCE_CLASS = ServiceReference.class;
+ public static final Class<?> SERVICE_OBJECTS_CLASS;
+
+ public static final Class<?> MAP_CLASS = Map.class;
+ public static final Class<?> MAP_ENTRY_CLASS = Map.Entry.class;
+
+
+ static {
+ Class<?> serviceObjectsClass = null;
+ try {
+ serviceObjectsClass = ServiceObjects.class;
+ }
+ catch (Throwable t)
+ {
+ //can't load class
+ }
+ SERVICE_OBJECTS_CLASS = serviceObjectsClass;
+ }
+
+ /**
+ * Returns the class object representing the class of the field reference
+ * The class loader of the component class is used to load the service class.
+ * <p>
+ * It may well be possible, that the class loader of the target class cannot
+ * see the service object class, for example if the service reference is
+ * inherited from a component class of another bundle.
+ *
+ * @return The class object for the referred to service or <code>null</code>
+ * if the class loader of the <code>targetClass</code> cannot see that
+ * class.
+ */
+ public static Class<?> getClassFromComponentClassLoader(
+ final Class<?> componentClass,
+ final String className,
+ final SimpleLogger logger )
+ {
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log(
+ LogService.LOG_DEBUG,
+ "getReferenceClass: Looking for interface class {0} through loader of {1}",
+ new Object[] {className, componentClass.getName()}, null );
+ }
+
+ try
+ {
+ // need the class loader of the target class, which may be the
+ // system classloader, which case getClassLoader may retur null
+ ClassLoader loader = componentClass.getClassLoader();
+ if ( loader == null )
+ {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+
+ final Class<?> referenceClass = loader.loadClass( className );
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: Found class {0}", new Object[] {referenceClass.getName()}, null );
+ }
+ return referenceClass;
+ }
+ catch ( final ClassNotFoundException cnfe )
+ {
+ // if we can't load the class, perhaps the method is declared in a
+ // super class so we try this class next
+ }
+
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: Not found through component class, using PackageAdmin service", null );
+ }
+
+ // try to load the class with the help of the PackageAdmin service
+ PackageAdmin pa = ( PackageAdmin ) Activator.getPackageAdmin();
+ if ( pa != null )
+ {
+ final String referenceClassPackage = className.substring( 0, className
+ .lastIndexOf( '.' ) );
+ ExportedPackage[] pkg = pa.getExportedPackages( referenceClassPackage );
+ if ( pkg != null )
+ {
+ for ( int i = 0; i < pkg.length; i++ )
+ {
+ try
+ {
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log(
+ LogService.LOG_DEBUG,
+ "getParameterClass: Checking Bundle {0}/{1}",
+ new Object[] {pkg[i].getExportingBundle().getSymbolicName(), pkg[i].getExportingBundle().getBundleId()}, null );
+ }
+
+ Class<?> referenceClass = pkg[i].getExportingBundle().loadClass( className );
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: Found class {0}", new Object[] {referenceClass.getName()}, null );
+ }
+ return referenceClass;
+ }
+ catch ( ClassNotFoundException cnfe )
+ {
+ // exported package does not provide the interface !!!!
+ }
+ }
+ }
+ else if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: No bundles exporting package {0} found", new Object[] {referenceClassPackage}, null );
+ }
+ }
+ else if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: PackageAdmin service not available, cannot find class", null );
+ }
+
+ // class cannot be found, neither through the component nor from an
+ // export, so we fall back to assuming Object
+ if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+ {
+ logger.log( LogService.LOG_DEBUG,
+ "getParameterClass: No class found, falling back to class Object", null );
+ }
+ return OBJECT_CLASS;
+ }
+}
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
index be1ece5..3bb61fcb 100644
--- 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
@@ -27,6 +27,7 @@
import org.apache.felix.scr.impl.manager.ComponentContextImpl;
import org.apache.felix.scr.impl.manager.RefPair;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
@@ -35,8 +36,8 @@
*/
public class FieldHandler
{
- /** The name of the field. */
- private final String fieldName;
+ /** The reference metadata. */
+ private final ReferenceMetadata metadata;
/** The component class. */
private final Class<?> componentClass;
@@ -53,14 +54,21 @@
* @param componentClass component class
* @param referenceClassName service class name
*/
- public FieldHandler( final String fieldName, final Class<?> componentClass,
- final String referenceClassName)
+ public FieldHandler( final ReferenceMetadata metadata,
+ final Class<?> componentClass)
{
- this.fieldName = fieldName;
+ this.metadata = metadata;
this.componentClass = componentClass;
this.state = NotResolved.INSTANCE;
}
+ /**
+ * Set the field.
+ * If the field is found, the state transitions to resolved, if the field is
+ * {@code null} the state transitions to not found.
+ * @param f The field or {@code null}.
+ * @param logger The logger
+ */
private void setField( final Field f, final SimpleLogger logger )
{
this.field = f;
@@ -75,7 +83,7 @@
{
state = NotFound.INSTANCE;
logger.log(LogService.LOG_ERROR, "Field [{0}] not found; Component will fail",
- new Object[] { this.fieldName }, null);
+ new Object[] { this.metadata.getField() }, null);
}
}
@@ -91,7 +99,8 @@
* trying to find the requested field.
* @param logger
*/
- private Field findField( final SimpleLogger logger ) throws InvocationTargetException
+ private Field findField( final SimpleLogger logger )
+ throws InvocationTargetException
{
final Class<?> targetClass = this.componentClass;
final ClassLoader targetClasslLoader = targetClass.getClassLoader();
@@ -105,7 +114,7 @@
if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
{
logger.log( LogService.LOG_DEBUG,
- "Locating field " + this.fieldName + " in class " + theClass.getName(), null );
+ "Locating field " + this.metadata.getField() + " in class " + theClass.getName(), null );
}
try
@@ -121,7 +130,7 @@
// 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[]
- { this.fieldName, theClass.getName(), targetClass.getName() }, null );
+ { this.metadata.getField(), theClass.getName(), targetClass.getName() }, null );
break;
}
@@ -164,14 +173,16 @@
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested field.
*/
- private Field getField( final Class<?> clazz, final boolean acceptPrivate,
- final boolean acceptPackage, final SimpleLogger logger )
+ private Field getField( final Class<?> clazz,
+ 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( this.fieldName );
+ final Field field = clazz.getDeclaredField( this.metadata.getField() );
// accept public and protected fields only and ensure accessibility
if ( accept( field, acceptPrivate, acceptPackage ) )
@@ -189,7 +200,7 @@
if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
{
logger.log( LogService.LOG_DEBUG, "Declared Field {0}.{1} not found", new Object[]
- { clazz.getName(), this.fieldName }, null );
+ { clazz.getName(), this.metadata.getField() }, null );
}
}
catch ( NoClassDefFoundError cdfe )
@@ -200,7 +211,7 @@
if ( logger.isLogEnabled( LogService.LOG_WARNING ) )
{
StringBuffer buf = new StringBuffer();
- buf.append( "Failure loooking up field " ).append( this.fieldName );
+ buf.append( "Failure loooking up field " ).append( this.metadata.getField() );
buf.append( " in class class " ).append( clazz.getName() ).append( ". Assuming no such field." );
logger.log( LogService.LOG_WARNING, buf.toString(), cdfe );
}
@@ -213,13 +224,58 @@
{
// 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 " + this.fieldName );
+ throw new InvocationTargetException( throwable, "Unexpected problem trying to get field " + this.metadata.getField() );
}
// caught and ignored exception, assume no field and continue search
return null;
}
+ /**
+ * Validate the field, type etc.
+ * @param f The field
+ * @param logger The logger
+ * @return The field if it's valid, {@code null} otherwise.
+ */
+ private Field validateField( final Field f, final SimpleLogger logger )
+ {
+ final Class<?> fieldType = f.getType();
+ final Class<?> referenceType = ClassUtils.getClassFromComponentClassLoader(
+ this.componentClass, metadata.getInterface(), logger);
+
+ // unary reference
+ if ( !metadata.isMultiple() )
+ {
+ if ( fieldType.isAssignableFrom(referenceType) )
+ {
+ // service
+ }
+ else if ( fieldType == ClassUtils.SERVICE_REFERENCE_CLASS )
+ {
+ // service reference
+ }
+ else if ( fieldType == ClassUtils.SERVICE_OBJECTS_CLASS )
+ {
+ // service objects
+ }
+ else if ( fieldType == ClassUtils.MAP_CLASS )
+ {
+ // map
+ }
+ else if ( fieldType == ClassUtils.MAP_ENTRY_CLASS )
+ {
+ // map entry
+ }
+ else
+ {
+ logger.log( LogService.LOG_WARNING, "Field {0} in component {1} has unsupported type {2}", new Object[]
+ {metadata.getField(), this.componentClass, fieldType.getName()}, null );
+ return null;
+ }
+ }
+ return f;
+ }
+
private enum METHOD_TYPE {
BIND,
UNBIND,
@@ -244,11 +300,11 @@
field.set(componentInstance, null);
}
} catch ( final IllegalArgumentException iae ) {
- iae.printStackTrace();
+ throw new InvocationTargetException(iae);
} catch ( final IllegalAccessException iae ) {
- iae.printStackTrace();
-
+ throw new InvocationTargetException(iae);
}
+
return MethodResult.VOID;
}
@@ -336,6 +392,9 @@
return ( dot > 0 ) ? name.substring( 0, dot ) : "";
}
+ /**
+ * Internal state interface.
+ */
private static interface State
{
@@ -347,31 +406,34 @@
throws InvocationTargetException;
}
+ /**
+ * Initial state.
+ */
private static class NotResolved implements State
{
private static final State INSTANCE = new NotResolved();
- private synchronized void resolve( final FieldHandler baseMethod, SimpleLogger logger )
+ private synchronized void resolve( final FieldHandler baseMethod, final SimpleLogger logger )
{
logger.log( LogService.LOG_DEBUG, "getting field: {0}", new Object[]
- {baseMethod.fieldName}, null );
+ {baseMethod.metadata.getField()}, null );
// resolve the field
Field field = null;
try
{
field = baseMethod.findField( logger );
+ field = baseMethod.validateField( field, logger );
}
- catch ( InvocationTargetException ex )
+ catch ( final InvocationTargetException ex )
{
logger.log( LogService.LOG_WARNING, "{0} cannot be found", new Object[]
- {baseMethod.fieldName}, ex.getTargetException() );
+ {baseMethod.metadata.getField()}, ex.getTargetException() );
}
baseMethod.setField( field, logger );
}
-
public MethodResult invoke( final FieldHandler baseMethod,
final METHOD_TYPE mType,
final Object componentInstance,
@@ -384,6 +446,9 @@
}
}
+ /**
+ * Final state of field couldn't be found or errors occured.
+ */
private static class NotFound implements State
{
private static final State INSTANCE = new NotFound();
@@ -395,17 +460,19 @@
final BindParameters rawParameter,
final SimpleLogger logger )
{
- logger.log( LogService.LOG_ERROR, "Field [{1}] not found", new Object[]
- { baseMethod.fieldName }, null );
+ logger.log( LogService.LOG_ERROR, "Field [{0}] not found", new Object[]
+ { baseMethod.metadata.getField() }, null );
return null;
}
}
+ /**
+ * Final state of field could be found and is valid.
+ */
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,
@@ -430,7 +497,7 @@
catch ( InvocationTargetException ite )
{
logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
- { fieldName }, ite.getCause() );
+ { metadata.getField() }, ite.getCause() );
}
return methodCallFailureResult;
@@ -462,7 +529,7 @@
catch ( InvocationTargetException ite )
{
logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
- { fieldName }, ite.getCause() );
+ { metadata.getField() }, ite.getCause() );
}
return methodCallFailureResult;
@@ -490,7 +557,7 @@
catch ( InvocationTargetException ite )
{
logger.log( LogService.LOG_ERROR, "The {0} field has thrown an exception", new Object[]
- { fieldName }, ite.getCause() );
+ { metadata.getField() }, ite.getCause() );
}
return methodCallFailureResult;
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
index 30c57ea..1f40dc0 100644
--- 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
@@ -37,9 +37,8 @@
final boolean configurableServiceProperties )
{
handler = new FieldHandler(
- m_dependencyMetadata.getField(),
- instanceClass,
- m_dependencyMetadata.getInterface()
+ m_dependencyMetadata,
+ instanceClass
);
}
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 c1e746a..5f42710 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
@@ -695,7 +695,7 @@
{
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) )
+ if ( !m_isMultiple )
{
// update is not allowed for unary references
if ( m_field_strategy.equals(FIELD_STRATEGY_UPDATE) )
@@ -705,7 +705,7 @@
}
// field value type
- if ( m_cardinality.equals(CARDINALITY_1_1) || m_cardinality.equals(CARDINALITY_0_1) )
+ if ( !m_isMultiple )
{
// value type must not be specified for unary references
if ( m_field_value_type != null )