Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id A22D6200BF4 for ; Fri, 6 Jan 2017 16:24:46 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id A0A9B160B37; Fri, 6 Jan 2017 15:24:46 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 06184160B1F for ; Fri, 6 Jan 2017 16:24:44 +0100 (CET) Received: (qmail 42370 invoked by uid 500); 6 Jan 2017 15:24:44 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 42361 invoked by uid 99); 6 Jan 2017 15:24:44 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 06 Jan 2017 15:24:44 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 7546B3A03A7 for ; Fri, 6 Jan 2017 15:24:43 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1777628 - in /felix/trunk/scr/src/main/java/org/apache/felix/scr/impl: helper/ inject/ manager/ metadata/ xml/ Date: Fri, 06 Jan 2017 15:24:42 -0000 To: commits@felix.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20170106152443.7546B3A03A7@svn01-us-west.apache.org> archived-at: Fri, 06 Jan 2017 15:24:46 -0000 Author: cziegeler Date: Fri Jan 6 15:24:42 2017 New Revision: 1777628 URL: http://svn.apache.org/viewvc?rev=1777628&view=rev Log: FELIX-5456 : [R7] Field injection of component activation objects Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java (with props) felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java (with props) felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java (with props) Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ActivateMethod.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ClassUtils.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ComponentMethodsImpl.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldHandler.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/xml/XmlHandler.java Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentMethods.java Fri Jan 6 15:24:42 2017 @@ -35,4 +35,6 @@ public interface ComponentMethods ReferenceMethods getBindMethods(String refName ); + ConstructorMethod getConstructor(); + } Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java?rev=1777628&view=auto ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java (added) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java Fri Jan 6 15:24:42 2017 @@ -0,0 +1,54 @@ +/* + * 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.osgi.service.component.ComponentContext; + +/** + * This object describes a constructor for a component. + * The name ConstructorMethod has been chosen to avoid a clash with the + * existing Constructor class. + */ +public interface ConstructorMethod { + + /** + * Create a new instance + * @param componentClass The implementation class of the component + * @param componentContext The component context + * @param logger A logger + * @return The instance + */ + T newInstance(Class componentClass, + ComponentContext componentContext, + SimpleLogger logger ) + throws Exception; + + public ConstructorMethod DEFAULT = new ConstructorMethod() { + + @Override + public T newInstance(Class componentClass, ComponentContext componentContext, SimpleLogger logger) + throws Exception + { + // 112.4.4 The class must be public and have a public constructor without arguments so component instances + // may be created by the SCR with the newInstance method on Class + return componentClass.newInstance(); + } + }; + +} Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ConstructorMethod.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ActivateMethod.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ActivateMethod.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ActivateMethod.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ActivateMethod.java Fri Jan 6 15:24:42 2017 @@ -31,7 +31,6 @@ import org.apache.felix.scr.impl.helper. import org.apache.felix.scr.impl.helper.MethodResult; import org.apache.felix.scr.impl.helper.SimpleLogger; import org.apache.felix.scr.impl.metadata.DSVersion; -import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.osgi.service.log.LogService; @@ -39,19 +38,14 @@ import org.osgi.service.log.LogService; public class ActivateMethod extends BaseMethod implements ComponentMethod { - protected static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class; - protected static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class; - protected static final Class INTEGER_CLASS = Integer.class; - protected final boolean m_supportsInterfaces; - - + public ActivateMethod( final String methodName, final boolean methodRequired, final Class componentClass, final DSVersion dsVersion, final boolean configurableServiceProperties, - boolean supportsInterfaces ) + final boolean supportsInterfaces) { super( methodName, methodRequired, componentClass, dsVersion, configurableServiceProperties ); m_supportsInterfaces = supportsInterfaces; @@ -69,7 +63,7 @@ public class ActivateMethod extends Base { // find the declared method in this class final Method method = getMethod( targetClass, getMethodName(), new Class[] - { COMPONENT_CONTEXT_CLASS }, acceptPrivate, acceptPackage, logger ); + { ClassUtils.COMPONENT_CONTEXT_CLASS }, acceptPrivate, acceptPackage, logger ); if ( method != null ) { return method; @@ -90,7 +84,7 @@ public class ActivateMethod extends Base { Class type = parameterTypes[0]; //single parameter method with parameter ComponentContext will already have been found. - if (type == BUNDLE_CONTEXT_CLASS) + if (type == ClassUtils.BUNDLE_CONTEXT_CLASS) { if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) ) { @@ -137,8 +131,8 @@ public class ActivateMethod extends Base boolean accept = true; for (Class type: parameterTypes) { - accept = type == COMPONENT_CONTEXT_CLASS - || type == BUNDLE_CONTEXT_CLASS + accept = type == ClassUtils.COMPONENT_CONTEXT_CLASS + || type == ClassUtils.BUNDLE_CONTEXT_CLASS || type == ClassUtils.MAP_CLASS || ( isDeactivate() && ( type == int.class || type == Integer.class)) || ( getDSVersion().isDS13() && isAnnotation(type)); @@ -220,10 +214,10 @@ public class ActivateMethod extends Base final Class t1 = m1.getParameterTypes()[0]; final Class t2 = m2.getParameterTypes()[0]; //t1, t2 can't be equal - if (t1 == COMPONENT_CONTEXT_CLASS) return -1; - if (t2 == COMPONENT_CONTEXT_CLASS) return 1; - if (t1 == BUNDLE_CONTEXT_CLASS) return -1; - if (t2 == BUNDLE_CONTEXT_CLASS) return 1; + if (t1 == ClassUtils.COMPONENT_CONTEXT_CLASS) return -1; + if (t2 == ClassUtils.COMPONENT_CONTEXT_CLASS) return 1; + if (t1 == ClassUtils.BUNDLE_CONTEXT_CLASS) return -1; + if (t2 == ClassUtils.BUNDLE_CONTEXT_CLASS) return 1; if (isAnnotation(t1)) return isAnnotation(t2)? 0: -1; if (isAnnotation(t2)) return 1; if (t1 == ClassUtils.MAP_CLASS) return -1; @@ -255,11 +249,11 @@ public class ActivateMethod extends Base final Object[] param = new Object[parameterTypes.length]; for ( int i = 0; i < param.length; i++ ) { - if ( parameterTypes[i] == COMPONENT_CONTEXT_CLASS ) + if ( parameterTypes[i] == ClassUtils.COMPONENT_CONTEXT_CLASS ) { param[i] = ap.getComponentContext(); } - else if ( parameterTypes[i] == BUNDLE_CONTEXT_CLASS ) + else if ( parameterTypes[i] == ClassUtils.BUNDLE_CONTEXT_CLASS ) { param[i] = ap.getComponentContext().getBundleContext(); } @@ -268,7 +262,7 @@ public class ActivateMethod extends Base // note: getProperties() returns a ReadOnlyDictionary which is a Map param[i] = ap.getComponentContext().getProperties(); } - else if ( parameterTypes[i] == INTEGER_CLASS || parameterTypes[i] == Integer.TYPE ) + else if ( parameterTypes[i] == ClassUtils.INTEGER_CLASS || parameterTypes[i] == Integer.TYPE ) { param[i] = ap.getReason(); } @@ -290,12 +284,22 @@ public class ActivateMethod extends Base return "activate"; } - public MethodResult invoke(Object componentInstance, ComponentContext componentContext, int reason, MethodResult methodCallFailureResult, SimpleLogger logger) { + /** + * @see org.apache.felix.scr.impl.helper.ComponentMethod#invoke(java.lang.Object, org.osgi.service.component.ComponentContext, int, org.apache.felix.scr.impl.helper.MethodResult, org.apache.felix.scr.impl.helper.SimpleLogger) + */ + public MethodResult invoke(final Object componentInstance, + final ComponentContext componentContext, + final int reason, + final MethodResult methodCallFailureResult, + final SimpleLogger logger) { return invoke(componentInstance, new ActivatorParameter(componentContext, reason), methodCallFailureResult, logger); } @Override - public MethodResult invoke( Object componentInstance, ActivatorParameter rawParameter, final MethodResult methodCallFailureResult, SimpleLogger logger ) + public MethodResult invoke(final Object componentInstance, + final ActivatorParameter rawParameter, + final MethodResult methodCallFailureResult, + final SimpleLogger logger ) { if (methodExists( logger )) { Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ClassUtils.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ClassUtils.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ClassUtils.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ClassUtils.java Fri Jan 6 15:24:42 2017 @@ -26,6 +26,7 @@ import java.util.Map; import org.apache.felix.scr.impl.helper.SimpleLogger; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentServiceObjects; import org.osgi.service.log.LogService; import org.osgi.service.packageadmin.ExportedPackage; @@ -54,6 +55,11 @@ public class ClassUtils public static final Class COLLECTION_CLASS = Collection.class; public static final Class LIST_CLASS = List.class; + public static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class; + public static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class; + public static final Class INTEGER_CLASS = Integer.class; + + // this bundle's context private static BundleContext m_context; // the package admin service (see BindMethod.getParameterClass) @@ -206,4 +212,16 @@ public class ClassUtils // remove the reference to the component context m_context = 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 ) : ""; + } + } Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ComponentMethodsImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ComponentMethodsImpl.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ComponentMethodsImpl.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ComponentMethodsImpl.java Fri Jan 6 15:24:42 2017 @@ -25,13 +25,8 @@ import java.util.Map; import org.apache.felix.scr.impl.helper.ComponentMethod; import org.apache.felix.scr.impl.helper.ComponentMethods; +import org.apache.felix.scr.impl.helper.ConstructorMethod; import org.apache.felix.scr.impl.helper.ReferenceMethods; -import org.apache.felix.scr.impl.inject.ActivateMethod; -import org.apache.felix.scr.impl.inject.BindMethods; -import org.apache.felix.scr.impl.inject.DeactivateMethod; -import org.apache.felix.scr.impl.inject.DuplexReferenceMethods; -import org.apache.felix.scr.impl.inject.FieldMethods; -import org.apache.felix.scr.impl.inject.ModifiedMethod; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.metadata.DSVersion; import org.apache.felix.scr.impl.metadata.ReferenceMetadata; @@ -41,9 +36,10 @@ import org.apache.felix.scr.impl.metadat */ public class ComponentMethodsImpl implements ComponentMethods { - private ActivateMethod m_activateMethod; - private ModifiedMethod m_modifiedMethod; - private DeactivateMethod m_deactivateMethod; + private ComponentMethod m_activateMethod; + private ComponentMethod m_modifiedMethod; + private ComponentMethod m_deactivateMethod; + private ConstructorMethod m_constructor; private final Map bindMethodMap = new HashMap(); @@ -56,8 +52,12 @@ public class ComponentMethodsImpl implem DSVersion dsVersion = componentMetadata.getDSVersion(); boolean configurableServiceProperties = componentMetadata.isConfigurableServiceProperties(); boolean supportsInterfaces = componentMetadata.isConfigureWithInterfaces(); - m_activateMethod = new ActivateMethod( componentMetadata.getActivate(), componentMetadata - .isActivateDeclared(), implementationObjectClass, dsVersion, configurableServiceProperties, supportsInterfaces ); + m_activateMethod = new ActivateMethod( componentMetadata.getActivate(), + componentMetadata.isActivateDeclared(), + implementationObjectClass, + dsVersion, + configurableServiceProperties, + supportsInterfaces); m_deactivateMethod = new DeactivateMethod( componentMetadata.getDeactivate(), componentMetadata.isDeactivateDeclared(), implementationObjectClass, dsVersion, configurableServiceProperties, supportsInterfaces ); @@ -83,26 +83,44 @@ public class ComponentMethodsImpl implem } bindMethodMap.put( refName, methods ); } + + if ( componentMetadata.getActivationFields() != null ) + { + + } + else + { + m_constructor = ConstructorMethod.DEFAULT; + } } - public ComponentMethod getActivateMethod() + @Override + public ComponentMethod getActivateMethod() { return m_activateMethod; } + @Override public ComponentMethod getDeactivateMethod() { return m_deactivateMethod; } + @Override public ComponentMethod getModifiedMethod() { return m_modifiedMethod; } + @Override public ReferenceMethods getBindMethods(String refName ) { return bindMethodMap.get( refName ); } + @Override + public ConstructorMethod getConstructor() + { + return m_constructor; + } } Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java?rev=1777628&view=auto ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java (added) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java Fri Jan 6 15:24:42 2017 @@ -0,0 +1,119 @@ +/* + * 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.inject; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; + +import org.apache.felix.scr.impl.helper.ConstructorMethod; +import org.apache.felix.scr.impl.helper.SimpleLogger; +import org.apache.felix.scr.impl.metadata.ComponentMetadata; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.log.LogService; + +public class ConstructorMethodImpl implements ConstructorMethod +{ + + private final ComponentMetadata m_metadata; + + public ConstructorMethodImpl( final ComponentMetadata metadata) + { + m_metadata = metadata; + } + + @Override + public T newInstance(Class componentClass, ComponentContext componentContext, SimpleLogger logger) + throws Exception + { + final T component = ConstructorMethod.DEFAULT.newInstance(componentClass, componentContext, logger); + + if ( m_metadata.getActivationFields() != null ) + { + for(final String fieldName : m_metadata.getActivationFields() ) + { + Field field = FieldUtils.findField(componentClass, fieldName, logger); + if ( field != null ) + { + setField(componentClass, field, component, componentContext, logger); + } + } + } + + return component; + } + + /** + * Validate and set the field, type etc. + * @param f The field + * @param logger The logger + */ + private void setField( final Class componentClass, + final Field f, + final T component, + final ComponentContext componentContext, + final SimpleLogger logger ) + { + + // ignore static fields + if ( Modifier.isStatic(f.getModifiers())) + { + logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must not be static", new Object[] + {f.getName(), componentClass}, null ); + } + else + { + final Class fieldType = f.getType(); + final Object value; + if ( fieldType == ClassUtils.COMPONENT_CONTEXT_CLASS ) + { + value = componentContext; + } + else if ( fieldType == ClassUtils.BUNDLE_CONTEXT_CLASS ) + { + value = componentContext.getBundleContext(); + } + else if ( fieldType == ClassUtils.MAP_CLASS ) + { + // note: getProperties() returns a ReadOnlyDictionary which is a Map + value = componentContext.getProperties(); + } + else + { + value = Annotations.toObject(fieldType, + (Map) componentContext.getProperties(), + componentContext.getBundleContext().getBundle(), m_metadata.isConfigureWithInterfaces()); + } + try + { + f.set(component, value); + } + catch ( final IllegalArgumentException iae ) + { + logger.log( LogService.LOG_ERROR, "Field {0} in component {1} can't be set", new Object[] + {f.getName(), componentClass}, iae ); + } + catch ( final IllegalAccessException iae ) + { + logger.log( LogService.LOG_ERROR, "Field {0} in component {1} can't be set", new Object[] + {f.getName(), componentClass}, iae ); + } + } + } +} Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/ConstructorMethodImpl.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldHandler.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldHandler.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldHandler.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldHandler.java Fri Jan 6 15:24:42 2017 @@ -22,8 +22,6 @@ package org.apache.felix.scr.impl.inject 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.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -124,149 +122,7 @@ public class FieldHandler } } - /** - * Finds the field named in the {@link #fieldName} field in the given - * targetClass. 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 null 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 = this.componentClass; - 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 " + this.metadata.getField() + " in class " + theClass.getName(), null ); - } - - try - { - final Field field = getField( 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[] - { this.metadata.getField(), 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 field named in the {@link #fieldName} field in the given - * targetClass. If the target class has no acceptable field - * the class hierarchy is traversed until a field is found or the root - * of the class hierarchy is reached without finding a field. - * - * - * @param targetClass The class in which to look for the method - * @param acceptPrivate true if private fields should be - * considered. - * @param acceptPackage true if package private fields should - * be considered. - * @param logger - * @return The requested field or null 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. - */ - 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.metadata.getField() ); - - // 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(), this.metadata.getField() }, 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( this.metadata.getField() ); - 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 " + this.metadata.getField() ); - } - // caught and ignored exception, assume no field and continue search - return null; - } /** * Validate the field, type etc. @@ -717,91 +573,8 @@ public class FieldHandler } } - /** - * Returns true if the field is acceptable to be returned from the - * {@link #getField(Class, String, boolean, boolean, SimpleLogger)} and also - * makes the field accessible. - *

- * This method returns true if the field: - *

    - *
  • Is not static
  • - *
  • Is public or protected
  • - *
  • Is private and acceptPrivate is true
  • - *
  • Is package private and acceptPackage is true
  • - *
- *

- * - * @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, - final boolean acceptPrivate, - final boolean acceptPackage ) - { - // check modifiers now - final int mod = field.getModifiers(); - - // no static fields - if ( Modifier.isStatic( mod ) ) - { - return true; - } - - // 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() - { - 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 ) : ""; - } /** * Internal state interface. @@ -835,7 +608,7 @@ public class FieldHandler Field field = null; try { - field = handler.findField( logger ); + field = FieldUtils.findField( handler.componentClass, handler.metadata.getField(), logger ); field = handler.validateField( field, logger ); } catch ( final InvocationTargetException ex ) Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java?rev=1777628&view=auto ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java (added) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java Fri Jan 6 15:24:42 2017 @@ -0,0 +1,251 @@ +/* + * 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.inject; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.felix.scr.impl.helper.SimpleLogger; +import org.osgi.service.log.LogService; + +public class FieldUtils { + + /** + * Finds the field named in the {@link #fieldName} field in the given + * targetClass. 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 null 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 + */ + public static Field findField( final Class targetClass, + final String fieldName, + final SimpleLogger logger ) + throws InvocationTargetException + { + final ClassLoader targetClasslLoader = targetClass.getClassLoader(); + final String targetPackage = ClassUtils.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 " + fieldName + " in class " + theClass.getName(), null ); + } + + try + { + final Field field = getField( theClass, fieldName, 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[] + { fieldName, 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( ClassUtils.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 field named in the {@link #fieldName} field in the given + * targetClass. If the target class has no acceptable field + * the class hierarchy is traversed until a field is found or the root + * of the class hierarchy is reached without finding a field. + * + * + * @param targetClass The class in which to look for the method + * @param acceptPrivate true if private fields should be + * considered. + * @param acceptPackage true if package private fields should + * be considered. + * @param logger + * @return The requested field or null 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. + */ + private static Field getField( final Class clazz, + final String fieldName, + 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( fieldName ); + + // 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(), fieldName }, 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( fieldName ); + 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 " + fieldName ); + } + + // caught and ignored exception, assume no field and continue search + return null; + } + + /** + * Returns true if the field is acceptable to be returned from the + * {@link #getField(Class, String, boolean, boolean, SimpleLogger)} and also + * makes the field accessible. + *

+ * This method returns true if the field: + *

    + *
  • Is not static
  • + *
  • Is public or protected
  • + *
  • Is private and acceptPrivate is true
  • + *
  • Is package private and acceptPackage is true
  • + *
+ *

+ * + * @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, + final boolean acceptPrivate, + final boolean acceptPackage ) + { + // check modifiers now + final int mod = field.getModifiers(); + + // no static fields + if ( Modifier.isStatic( mod ) ) + { + return true; + } + + // 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() + { + public Object run() + { + field.setAccessible( true ); + return null; + } + } ); + } +} Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/inject/FieldUtils.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java Fri Jan 6 15:24:42 2017 @@ -232,9 +232,10 @@ public class SingleComponentManager e implementationObjectClass = (Class) bundle.loadClass( getComponentMetadata().getImplementationClassName() ) ; - // 112.4.4 The class must be public and have a public constructor without arguments so component instances - // may be created by the SCR with the newInstance method on Class - implementationObject = implementationObjectClass.newInstance(); + implementationObject = getComponentMethods().getConstructor().newInstance(implementationObjectClass, + componentContext, + this); + } catch ( Throwable t ) { Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java Fri Jan 6 15:24:42 2017 @@ -96,6 +96,9 @@ public class ComponentMetadata // 112.4.4 configuration-pid (since DS 1.2) private List m_configurationPid; + // activation fields (since DS 1.4) + private List m_activationFields; + // Associated properties (0..*) private final Map m_properties = new HashMap(); @@ -433,6 +436,15 @@ public class ComponentMetadata + public void setActivationFields( final String[] fields ) + { + if ( m_validated ) + { + return; + } + this.m_activationFields = new ArrayList( Arrays.asList( fields ) ); + } + /////////////////////////////////////////// GETTERS ////////////////////////////////////// /** @@ -605,6 +617,18 @@ public class ComponentMetadata /** + * Returns the names of the activation fields + * + * @return the list of activation fields or {@code null} + * @since 2.1.0 (DS 1.4) + */ + public List getActivationFields() + { + return m_activationFields; + } + + + /** * Returns the name of the deactivate method * * @return the name of the deactivate method @@ -975,6 +999,12 @@ public class ComponentMetadata } } + // activation fields require DS 1.4 + if ( m_activationFields != null && !m_dsVersion.isDS14() ) + { + throw validationFailure( "Activation fields require version 1.4 or later"); + } + if (m_dsVersion == DSVersion.DS12Felix) { m_configurableServiceProperties = true; Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/xml/XmlHandler.java URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/xml/XmlHandler.java?rev=1777628&r1=1777627&r2=1777628&view=diff ============================================================================== --- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/xml/XmlHandler.java (original) +++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/xml/XmlHandler.java Fri Jan 6 15:24:42 2017 @@ -282,6 +282,14 @@ public class XmlHandler implements KXml2 m_currentComponent.setConfigureWithInterfaces("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURE_WITH_INTERFACES))); m_currentComponent.setDelayedKeepInstances(m_globalDelayedKeepInstances || "true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELAYED_KEEP_INSTANCES))); + // activation-fields is optional (since DS 1.4) + String activationFields = attributes.getAttribute( "activation-fields" ); + if ( activationFields != null ) + { + final String[] fields = activationFields.split(" "); + m_currentComponent.setActivationFields( fields ); + } + // Add this component to the list m_components.add( m_currentComponent ); }