You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2015/07/09 00:10:16 UTC

svn commit: r1689973 [19/25] - in /felix/sandbox/pderop/dependencymanager.ds: cnf/ext/ cnf/localrepo/ cnf/localrepo/org.apache.felix.framework/ cnf/releaserepo/ org.apache.felix.dependencymanager.ds.itest/ org.apache.felix.dependencymanager.ds.itest/.s...

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleComponentManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleComponentManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleComponentManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleComponentManager.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,916 @@
+/*
+ * 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.manager;
+
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.config.ReferenceManager;
+import org.apache.felix.scr.impl.helper.ActivatorParameter;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.apache.felix.scr.impl.helper.MethodResult;
+import org.apache.felix.scr.impl.helper.ModifiedMethod;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+
+
+/**
+ * The default ComponentManager. Objects of this class are responsible for managing
+ * implementation object's lifecycle.
+ */
+public class SingleComponentManager<S> extends AbstractComponentManager<S> implements ServiceFactory<S>
+{
+
+    // keep the using bundles as reference "counters" for instance deactivation
+    private final AtomicInteger m_useCount = new AtomicInteger( );
+
+    // The context that will be passed to the implementationObject
+    private volatile ComponentContextImpl<S> m_componentContext;
+
+    // Merged properties from xml descriptor and all configurations
+    private Map<String, Object> m_configurationProperties;
+
+    // optional properties provided in the ComponentFactory.newInstance method
+    private Map<String, Object> m_factoryProperties;
+
+    // the component properties, also used as service properties
+    private Map<String, Object> m_properties;
+
+    // properties supplied ot ExtComponentContext.updateProperties
+    // null if properties are not to be overwritten
+    private Dictionary<String, Object> m_serviceProperties;
+
+    private final ThreadLocal<Boolean> m_circularReferences = new ThreadLocal<Boolean>();
+
+   /**
+     * The constructor receives both the activator and the metadata
+     * @param componentMethods
+     */
+    public SingleComponentManager( ComponentContainer<S> container, ComponentMethods componentMethods )
+    {
+        this(container, componentMethods, false);
+    }
+
+    public SingleComponentManager( ComponentContainer<S> container, ComponentMethods componentMethods,
+            boolean factoryInstance )
+    {
+        super( container, componentMethods, factoryInstance );
+    }
+
+    @Override
+    void clear()
+    {
+        m_container.disposed( this );
+
+        super.clear();
+    }
+
+
+    // 1. Load the component implementation class
+    // 2. Create the component instance and component context
+    // 3. Bind the target services
+    // 4. Call the activate method, if present
+    // if this method is overwritten, the deleteComponent method should
+    // also be overwritten
+    private boolean createComponent(ComponentContextImpl<S> componentContext)
+    {
+        if ( !isStateLocked() )
+        {
+            throw new IllegalStateException( "need write lock (createComponent)" );
+        }
+        if ( m_componentContext == null )
+        {
+            S tmpComponent = createImplementationObject( null, new SetImplementationObject<S>()
+            {
+                public void presetComponentContext( ComponentContextImpl<S> componentContext )
+                {
+                    m_componentContext = componentContext;
+                }
+
+
+                public void resetImplementationObject( S implementationObject )
+                {
+                    m_componentContext = null;
+                }
+            }, componentContext );
+
+            // if something failed creating the component instance, return false
+            if ( tmpComponent == null )
+            {
+                return false;
+            }
+
+            // otherwise set the context and component instance and return true
+            log( LogService.LOG_DEBUG, "Set implementation object for component {0}", new Object[] { getName() },  null );
+
+            //notify that component was successfully created so any optional circular dependencies can be retried
+            BundleComponentActivator activator = getActivator();
+            if ( activator != null )
+            {
+                activator.missingServicePresent( getServiceReference() );
+            }
+        }
+        return true;
+    }
+
+
+    @Override
+    protected void deleteComponent( int reason )
+    {
+        if ( !isStateLocked() )
+        {
+            throw new IllegalStateException( "need write lock (deleteComponent)" );
+        }
+        if ( m_componentContext != null )
+        {
+            m_useCount.set( 0 );
+            disposeImplementationObject( m_componentContext, reason );
+            m_componentContext.cleanup();
+            m_componentContext = null;
+            log( LogService.LOG_DEBUG, "Unset and deconfigured implementation object for component {0} in deleteComponent for reason {1}", new Object[] { getName(), REASONS[ reason ] },  null );
+            clearServiceProperties();
+        }
+    }
+
+    void clearServiceProperties()
+    {
+        m_properties = null;
+        m_serviceProperties = null;
+    }
+
+
+    public ComponentInstance getComponentInstance()
+    {
+        return m_componentContext == null? null: m_componentContext.getComponentInstance();
+    }
+
+
+    //**********************************************************************************************************
+
+    /**
+     * Get the object that is implementing this descriptor
+     *
+     * @return the object that implements the services
+     */
+    private S getInstance()
+    {
+        return m_componentContext == null? null: m_componentContext.getImplementationObject( true );
+    }
+
+    /**
+     * The <code>SetImplementationObject</code> interface provides an
+     * API for component managers to setup the implementation object and
+     * potentially other parts as part of the {@link #createImplementationObject} method
+     * processing.
+     */
+    protected interface SetImplementationObject<S>
+    {
+
+        /**
+         * Presets the implementation object. This method is called before
+         * the component's activator method is called and is intended to
+         * temporarily set the implementation object during the activator
+         * call.
+         */
+        void presetComponentContext( ComponentContextImpl<S> componentContext );
+
+
+        /**
+         * Resets the implementation object. This method is called after
+         * the activator method terminates with an error and is intended to
+         * revert any temporary settings done in the {@link #presetComponentContext(ComponentContextImpl)}
+         * method.
+         */
+        void resetImplementationObject( S implementationObject );
+
+    }
+
+
+    protected S createImplementationObject( Bundle usingBundle, SetImplementationObject<S> setter, ComponentContextImpl<S> componentContext )
+    {
+        final Class<S> implementationObjectClass;
+        final S implementationObject;
+
+        // 1. Load the component implementation class
+        // 2. Create the component instance and component context
+        // If the component is not immediate, this is not done at this moment
+        Bundle bundle = getBundle();
+        if (bundle == null)
+        {
+            log( LogService.LOG_WARNING, "Bundle shut down during instantiation of the implementation object", null);
+            return null;
+        }
+        try
+        {
+            // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
+            implementationObjectClass = (Class<S>) 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();
+        }
+        catch ( Throwable t )
+        {
+            // failed to instantiate, return null
+            log( LogService.LOG_ERROR, "Error during instantiation of the implementation object", t );
+            return null;
+        }
+
+        componentContext.setImplementationObject(implementationObject);
+
+        // 3. set the implementation object prematurely
+        setter.presetComponentContext( componentContext );
+
+        // 4. Bind the target services
+
+        ReferenceManager<S, ?> failedDm = null;
+        for ( DependencyManager<S, ?> dm: getDependencyManagers())
+        {
+            if ( failedDm == null )
+            {
+                // if a dependency turned unresolved since the validation check,
+                // creating the instance fails here, so we deactivate and return
+                // null.
+                boolean open = dm.open( componentContext, componentContext.getEdgeInfo( dm ) );
+                if ( !open )
+                {
+                    log( LogService.LOG_ERROR, "Cannot create component instance due to failure to bind reference {0}",
+                            new Object[] { dm.getName() }, null );
+
+                    failedDm = dm;
+
+                }
+            }
+            else
+            {
+                componentContext.getEdgeInfo( dm ).ignore();
+            }
+        }
+        if (failedDm != null)
+        {
+            // make sure, we keep no bindings. Only close the dm's we opened.
+            boolean skip = true;
+            for ( DependencyManager<S, ?> md: getReversedDependencyManagers() )
+            {
+                if ( skip && failedDm == md )
+                {
+                    skip = false;
+                }
+                if ( !skip )
+                {
+                    md.close( componentContext, componentContext.getEdgeInfo( md ) );
+                }
+                md.deactivate();
+            }
+            setter.resetImplementationObject( implementationObject );
+            return null;
+
+        }
+
+        // 5. Call the activate method, if present
+        final MethodResult result = getComponentMethods().getActivateMethod().invoke( implementationObject, new ActivatorParameter(
+                componentContext, 1 ), null, this );
+        if ( result == null )
+        {
+            // 112.5.8 If the activate method throws an exception, SCR must log an error message
+            // containing the exception with the Log Service and activation fails
+            for ( DependencyManager<S, ?> md: getReversedDependencyManagers() )
+            {
+                md.close( componentContext, componentContext.getEdgeInfo( md ) );
+            }
+
+            // make sure the implementation object is not available
+            setter.resetImplementationObject( implementationObject );
+
+           return null;
+        }
+        else
+        {
+            componentContext.setImplementationAccessible( true );
+            m_circularReferences.remove();
+            //this may cause a getService as properties now match a filter.
+            setServiceProperties( result );
+        }
+
+        return implementationObject;
+    }
+
+
+    protected void disposeImplementationObject( ComponentContextImpl<S> componentContext,
+            int reason )
+    {
+        componentContext.setImplementationAccessible( false );
+        S implementationObject = componentContext.getImplementationObject( false );
+
+        if ( implementationObject != null )
+        {
+            // 1. Call the deactivate method, if present
+            // don't care for the result, the error (acccording to 112.5.12 If the deactivate
+            // method throws an exception, SCR must log an error message containing the
+            // exception with the Log Service and continue) has already been logged
+            final MethodResult result = getComponentMethods().getDeactivateMethod().invoke( implementationObject,
+                    new ActivatorParameter( componentContext, reason ), null, this );
+            if ( result != null )
+            {
+                setServiceProperties( result );
+            }
+            // 2. Unbind any bound services
+            for ( DependencyManager<S, ?> md: getReversedDependencyManagers() )
+            {
+                md.close( componentContext, componentContext.getEdgeInfo( md ) );
+            }
+        }
+
+    }
+
+    @Override
+    boolean hasInstance()
+    {
+        return m_componentContext != null;
+    }
+
+    @Override
+    <T> void invokeBindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    {
+        ComponentContextImpl<S> componentContext = m_componentContext;
+        if ( componentContext != null )
+        {
+            EdgeInfo info = componentContext.getEdgeInfo( dependencyManager );
+            dependencyManager.invokeBindMethod( componentContext, refPair, trackingCount, info );
+        }
+    }
+
+    @Override
+    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    {
+        ComponentContextImpl<S> componentContext = m_componentContext;
+        if ( componentContext != null )
+        {
+            EdgeInfo info = componentContext.getEdgeInfo( dependencyManager );
+            dependencyManager.invokeUpdatedMethod( componentContext, refPair, trackingCount, info );
+        }
+    }
+
+    @Override
+    <T> void invokeUnbindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> oldRefPair, int trackingCount )
+    {
+        ComponentContextImpl<S> componentContext = m_componentContext;
+        if ( componentContext != null )
+        {
+            EdgeInfo info = componentContext.getEdgeInfo( dependencyManager );
+            dependencyManager.invokeUnbindMethod( componentContext, oldRefPair, trackingCount, info );
+        }
+    }
+
+    protected void setFactoryProperties( Dictionary<String, ?> dictionary )
+    {
+        m_factoryProperties = copyToMap( dictionary, true );
+    }
+
+
+    @Override
+    void registerComponentId()
+    {
+        super.registerComponentId();
+        this.m_properties = null;
+    }
+
+
+    @Override
+    void unregisterComponentId()
+    {
+        super.unregisterComponentId();
+        this.m_properties = null;
+    }
+
+
+    /**
+     * Returns the (private copy) of the Component properties to be used
+     * for the ComponentContext as well as eventual service registration.
+     * <p/>
+     * Method implements the Component Properties provisioning as described
+     * in 112.6, Component Properties.
+     *
+     * @return a private map of component properties
+     */
+    @Override
+    public Map<String, Object> getProperties()
+    {
+
+        if ( m_properties == null )
+        {
+
+
+            // 1. Merge all the config properties
+            Map<String, Object> props = new HashMap<String, Object>();
+            if ( m_configurationProperties != null )
+            {
+                props.putAll(m_configurationProperties);
+            }
+            if ( m_factoryProperties != null)
+            {
+                props.putAll(m_factoryProperties);
+                if (getComponentMetadata().getDSVersion().isDS13() && m_factoryProperties.containsKey(Constants.SERVICE_PID))
+                {
+                	final List<String> servicePids = new ArrayList<String>();
+                	final Object configPropServicePids = m_configurationProperties.get(Constants.SERVICE_PID);
+                	if ( configPropServicePids instanceof List )
+                	{
+                		servicePids.addAll((List)configPropServicePids);
+                	}
+                	else 
+                	{
+                		servicePids.add(configPropServicePids.toString());
+                	}
+                    if (m_factoryProperties.get(Constants.SERVICE_PID) instanceof String)
+                    {
+                        servicePids.add((String)m_factoryProperties.get(Constants.SERVICE_PID));
+                    }
+                    
+                	if ( servicePids.size() == 1 )
+                	{
+                		props.put(Constants.SERVICE_PID, servicePids.get(0));
+                	}
+                	else
+                	{
+                		props.put(Constants.SERVICE_PID, servicePids);
+                	}
+                }
+            }
+
+            // 2. set component.name and component.id
+            props.put( ComponentConstants.COMPONENT_NAME, getComponentMetadata().getName() );
+            props.put( ComponentConstants.COMPONENT_ID, getId() );
+
+            m_properties = props;
+        }
+
+        return m_properties;
+    }
+
+    @Override
+    public void setServiceProperties( Dictionary<String, ?> serviceProperties )
+    {
+        if ( serviceProperties == null || serviceProperties.isEmpty() )
+        {
+            m_serviceProperties = null;
+        }
+        else
+        {
+            m_serviceProperties = copyToDictionary( serviceProperties, false );
+            // set component.name and component.id
+            m_serviceProperties.put( ComponentConstants.COMPONENT_NAME, getComponentMetadata().getName() );
+            m_serviceProperties.put( ComponentConstants.COMPONENT_ID, getId() );
+        }
+
+        updateServiceRegistration();
+    }
+
+    @Override
+    public Dictionary<String, Object> getServiceProperties()
+    {
+        if ( m_serviceProperties != null )
+        {
+            return m_serviceProperties;
+        }
+        return super.getServiceProperties();
+    }
+
+    private void updateServiceRegistration()
+    {
+        ServiceRegistration<S> sr = getServiceRegistration();
+        if ( sr != null )
+        {
+            try
+            {
+                // Don't propagate if service properties did not change.
+                final Dictionary<String, Object> regProps = getServiceProperties();
+                if ( !servicePropertiesMatches( sr, regProps ) )
+                {
+                    sr.setProperties( regProps );
+                }
+            }
+            catch ( IllegalStateException ise )
+            {
+                // service has been unregistered asynchronously, ignore
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                log( LogService.LOG_ERROR,
+                        "Unexpected configuration property problem when updating service registration", iae );
+            }
+            catch ( Throwable t )
+            {
+                log( LogService.LOG_ERROR, "Unexpected problem when updating service registration", t );
+            }
+        }
+    }
+
+    /**
+     * Called by the Configuration Admin Service to update the component with
+     * Configuration properties.
+     * <p/>
+     * This causes the component to be reactivated with the new configuration
+     * unless no configuration has ever been set on this component and the
+     * <code>configuration</code> parameter is <code>null</code>. In this case
+     * nothing is to be done. If a configuration has previously been set and
+     * now the configuration is deleted, the <code>configuration</code>
+     * parameter is <code>null</code> and the component has to be reactivated
+     * with the default configuration.
+     *
+     * @param configuration The configuration properties for the component from
+     *                      the Configuration Admin Service or <code>null</code> if there is
+     *                      no configuration or if the configuration has just been deleted.
+     * @param configurationDeleted TODO
+     * @param changeCount Change count for the configuration
+     * @param targetedPID TargetedPID for the configuration
+     */
+    @Override
+    public void reconfigure( Map<String, Object> configuration, boolean configurationDeleted )
+    {
+        // store the properties
+        m_configurationProperties = configuration;
+
+        reconfigure(configurationDeleted);
+    }
+
+    void reconfigure(boolean configurationDeleted)
+    {
+        Deferred<Void> enableLatch = enableLatchWait();
+        try
+        {
+            // clear the current properties to force using the configuration data
+            m_properties = null;
+
+
+            // reactivate the component to ensure it is provided with the
+            // configuration data
+            if ( m_disposed || !m_internalEnabled )
+            {
+                // nothing to do for inactive components, leave this method
+                log( LogService.LOG_DEBUG, "Component can not be activated since it is in state {0}", new Object[] { getState() }, null );
+                //enabling the component will set the target properties, do nothing now.
+                return;
+            }
+
+            // unsatisfied component and non-ignored configuration may change targets
+            // to satisfy references
+            obtainActivationWriteLock( "reconfigure" );
+            try
+            {
+                if ( !isSatisfied() && !getComponentMetadata().isConfigurationIgnored() )
+                {
+                    log( LogService.LOG_DEBUG, "Attempting to activate unsatisfied component", null );
+                    updateTargets( getProperties() );
+                    releaseActivationWriteeLock( "reconfigure.unsatisfied" );
+                    activateInternal( getTrackingCount().get() );
+                    return;
+                }
+
+                if ( !modify(configurationDeleted) )
+                {
+                    // SCR 112.7.1 - deactivate if configuration is deleted or no modified method declared
+                    log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure from configuration", null );
+                    int reason = configurationDeleted ? ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED
+                            : ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_MODIFIED;
+
+                    // FELIX-2368: cycle component immediately, reconfigure() is
+                    //     called through ConfigurationListener API which itself is
+                    //     called asynchronously by the Configuration Admin Service
+                    releaseActivationWriteeLock( "reconfigure.modified.1" );
+                    //we have already determined that modify cannot be called. Therefore factory instances must be disposed.
+                    boolean dispose = m_factoryInstance;
+                    deactivateInternal( reason, dispose, dispose );
+                    if ( !dispose )
+                    {
+                        obtainActivationWriteLock("reconfigure.deactivate.activate");
+                        try
+                        {
+                            updateTargets(getProperties());
+                        }
+                        finally
+                        {
+                            releaseActivationWriteeLock("reconfigure.deactivate.activate");
+                        }
+                        activateInternal(getTrackingCount().get());
+                    }
+                }
+            }
+            finally
+            {
+                //used if modify succeeds or if there's an exception.
+                releaseActivationWriteeLock( "reconfigure.end" );;
+            }
+        }
+        finally
+        {
+            enableLatch.resolve(null);
+        }
+    }
+
+    private boolean modify(boolean configurationDeleted)
+    {
+    	//0 SCR 112.7.1 If configuration is deleted, and version is < 1.3 and no flag set, then deactivate unconditionally.
+    	// For version 1.3 and later, or with a flag, more sensible behavior is allowed.
+    	if ( configurationDeleted && !getComponentMetadata().isDeleteCallsModify()){
+    		return false;
+    	}
+
+        // 1. no live update if there is no declared method
+        if ( getComponentMetadata().getModified() == null )
+        {
+            log( LogService.LOG_DEBUG, "No modified method, cannot update dynamically", null );
+            return false;
+        }
+        // invariant: we have a modified method name
+
+        // 2. get and check configured method
+        // invariant: modify method is configured and found
+
+        // 3. check whether we can dynamically apply the configuration if
+        // any target filters influence the bound services
+        final Map<String, Object> props = getProperties();
+        for ( DependencyManager<S, ?> dm: getDependencyManagers() )
+        {
+            if ( !dm.canUpdateDynamically( props ) )
+            {
+                log( LogService.LOG_DEBUG,
+                        "Cannot dynamically update the configuration due to dependency changes induced on dependency {0}",
+                        new Object[] {dm.getName()}, null );
+                return false;
+            }
+        }
+        // invariant: modify method existing and no static bound service changes
+
+        // 4. call method (nothing to do when failed, since it has already been logged)
+        //   (call with non-null default result to continue even if the
+        //    modify method call failed)
+        obtainStateLock( "ImmediateComponentManager.modify" );
+        try
+        {
+            //cf 112.5.12 where invoking modified method before updating target services is specified.
+            final MethodResult result = invokeModifiedMethod();
+            updateTargets( props );
+            if ( result == null )
+            {
+                // log an error if the declared method cannot be found
+                log( LogService.LOG_ERROR, "Declared modify method ''{0}'' cannot be found, configuring by reactivation",
+                        new Object[] {getComponentMetadata().getModified()}, null );
+                return false;
+            }
+
+            // 5. update the target filter on the services now, this may still
+            // result in unsatisfied dependencies, in which case we abort
+            // this dynamic update and have the component be deactivated
+            if ( !verifyDependencyManagers() )
+            {
+                log( LogService.LOG_ERROR,
+                        "Updating the service references caused at least on reference to become unsatisfied, deactivating component",
+                        null );
+                return false;
+            }
+
+            // 6. update service registration properties if we didn't just do it
+            if ( result.hasResult() )
+            {
+                setServiceProperties( result );
+            }
+            else
+            {
+                updateServiceRegistration();
+            }
+
+            // 7. everything set and done, the component has been updated
+            return true;
+        }
+        finally
+        {
+            releaseStateLock( "ImmediateComponentManager.modify" );
+        }
+    }
+
+    protected MethodResult invokeModifiedMethod()
+    {
+        ModifiedMethod modifiedMethod = getComponentMethods().getModifiedMethod();
+        if ( getInstance() != null )
+        {
+            return modifiedMethod.invoke( getInstance(), new ActivatorParameter( m_componentContext, -1 ),
+                    MethodResult.VOID, this );
+        }
+        return MethodResult.VOID;
+    }
+
+    /**
+     * Checks if the given service registration properties matches another set
+     * of properties.
+     *
+     * @param reg   the service registration whose service properties will be
+     *              compared to the props parameter
+     * @param props the properties to be compared with the registration
+     *              service properties.
+     * @return <code>true</code> if the registration service properties equals
+     *         the prop properties, false if not.
+     */
+    private boolean servicePropertiesMatches( ServiceRegistration<S> reg, Dictionary<String, Object> props )
+    {
+        Dictionary<String, Object> regProps = new Hashtable<String, Object>();
+        String[] keys = reg.getReference().getPropertyKeys();
+        for ( int i = 0; keys != null && i < keys.length; i++ )
+        {
+            if ( !keys[i].equals( org.osgi.framework.Constants.OBJECTCLASS )
+                    && !keys[i].equals( org.osgi.framework.Constants.SERVICE_ID ) )
+            {
+                regProps.put( keys[i], reg.getReference().getProperty( keys[i] ) );
+            }
+        }
+        return regProps.equals( props );
+    }
+
+    public S getService( Bundle bundle, ServiceRegistration<S> serviceRegistration )
+    {
+        boolean success = getServiceInternal();
+        if ( success )
+        {
+            m_useCount.incrementAndGet();
+            return m_componentContext.getImplementationObject( true );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    @Override
+    boolean getServiceInternal()
+    {
+        if (m_circularReferences.get() != null)
+        {
+            log( LogService.LOG_ERROR,  "Circular reference detected, getService returning null", null );
+            dumpThreads();
+            return false;
+        }
+        m_circularReferences.set( Boolean.TRUE );
+        try
+        {
+            boolean success = true;
+            if ( m_componentContext == null )
+            {
+                ComponentContextImpl<S> componentContext = new ComponentContextImpl<S>(this, this.getBundle());
+                if ( collectDependencies(componentContext))
+                {
+                        log(
+                                LogService.LOG_DEBUG,
+                                "getService (single component manager) dependencies collected.",
+                                null );
+                }
+                else
+                {
+                    log(
+                            LogService.LOG_INFO,
+                            "Could not obtain all required dependencies, getService returning null",
+                            null );
+                    success = false;
+                }
+                obtainStateLock( "ImmediateComponentManager.getService.1" );
+                try
+                {
+                    if ( m_componentContext == null )
+                    {
+                        //state should be "Registered"
+                        S result = getService(componentContext );
+                        if ( result == null )
+                        {
+                            success = false;;
+                        }
+                        else
+                        {
+                            m_activated = true;
+                        }
+                    }
+                }
+                finally
+                {
+                    releaseStateLock( "ImmediateComponentManager.getService.1" );
+                }
+            }
+            return success;
+        }
+        finally
+        {
+            //normally this will have been done after object becomes accessible.  This is double-checking.
+            m_circularReferences.remove();
+        }
+    }
+
+    private S getService(ComponentContextImpl<S> componentContext)
+    {
+        //should be write locked
+        if (!isInternalEnabled())
+        {
+            return null;
+        }
+
+        if ( createComponent(componentContext) )
+        {
+            return getInstance();
+        }
+
+        // log that the delayed component cannot be created (we don't
+        // know why at this moment; this should already have been logged)
+        log( LogService.LOG_ERROR, "Failed creating the component instance; see log for reason", null );
+
+        // component could not really be created. This may be temporary
+        // so we stay in the registered state but ensure the component
+        // instance is deleted
+        try
+        {
+            deleteComponent( ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED );
+        }
+        catch ( Throwable t )
+        {
+            log( LogService.LOG_DEBUG, "Cannot delete incomplete component instance. Ignoring.", t );
+        }
+
+        // no service can be returned (be prepared for more logging !!)
+        return null;
+
+    }
+
+    public void ungetService( Bundle bundle, ServiceRegistration<S> serviceRegistration, S o )
+    {
+        // the framework should not call ungetService more than it calls
+        // calls getService. Still, we want to be sure to not go below zero
+        if ( m_useCount.get() > 0 )
+        {
+            int useCount = m_useCount.decrementAndGet();
+
+            // unget the service instance if no bundle is using it
+            // any longer unless delayed component instances have to
+            // be kept (FELIX-3039)
+            if ( useCount == 0 && !isImmediate() && !keepInstances() )
+            {
+                obtainStateLock( "ImmediateComponentManager.ungetService.1" );
+                try
+                {
+                    if ( m_useCount.get() == 0 )
+                    {
+                        ungetService( );
+                    }
+                }
+                finally
+                {
+                    releaseStateLock( "ImmediateComponentManager.ungetService.1" );
+                }
+            }
+        }
+    }
+
+    void ungetService( )
+    {
+        deleteComponent( ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED );
+    }
+
+    private boolean keepInstances()
+    {
+        return getComponentMetadata().isDelayedKeepInstances();
+    }
+
+    @Override
+    public void getComponentManagers(List<AbstractComponentManager<S>> cms)
+    {
+        cms.add(this);
+    }
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,75 @@
+/*
+ * 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.manager;
+
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * @version $Rev: 1689302 $ $Date: 2015-07-06 03:31:39 +0200 (Mon, 06 Jul 2015) $
+ */
+public class SinglePrototypeRefPair<S, T> extends SingleRefPair<S, T>
+{
+    private final ServiceObjects<T> serviceObjects;
+
+    public SinglePrototypeRefPair( BundleContext context, ServiceReference<T> ref )
+    {
+        super(ref);
+        this.serviceObjects = context.getServiceObjects(ref);
+    }
+
+    @Override
+    public ServiceObjects<T> getServiceObjects()
+    {
+        return serviceObjects;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[SinglePrototypeRefPair: ref: [" + getRef() + "] service: [" + getServiceObject(null) + "]]";
+    }
+
+    @Override
+    public boolean getServiceObject(ComponentContextImpl<S> key, BundleContext context,
+        SimpleLogger logger)
+    {
+    	final T service = key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef(), serviceObjects);
+        if ( service == null )
+        {
+            setFailed();
+            logger.log(
+                 LogService.LOG_WARNING,
+                 "Could not get service from serviceobjects for ref {0}", new Object[] {getRef()}, null );
+            return false;
+        }
+        if (!setServiceObject(key, service))
+        {
+            // Another thread got the service before, so unget our
+            serviceObjects.ungetService( service );
+        }
+        return true;
+    }
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleRefPair.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleRefPair.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleRefPair.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/SingleRefPair.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,88 @@
+/*
+ * 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.manager;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * @version $Rev: 1615440 $ $Date: 2014-08-03 21:27:54 +0200 (Sun, 03 Aug 2014) $
+ */
+public class SingleRefPair<S, T> extends RefPair<S, T>
+{
+    private AtomicReference<T> serviceObjectRef = new AtomicReference<T>();
+
+    public SingleRefPair( ServiceReference<T> ref )
+    {
+        super(ref);
+    }
+
+    public T getServiceObject(ComponentContextImpl<S> key)
+    {
+        return serviceObjectRef.get();
+    }
+
+    public boolean setServiceObject( ComponentContextImpl<S> key, T serviceObject )
+    {
+        boolean set = serviceObjectRef.compareAndSet( null, serviceObject );
+        if ( serviceObject != null)
+        {
+            failed = false;
+        }
+        return set;
+    }
+    
+    public T unsetServiceObject(ComponentContextImpl<S> key)
+    {
+        return serviceObjectRef.getAndSet( null );
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[RefPair: ref: [" + getRef() + "] service: [" + serviceObjectRef.get() + "]]";
+    }
+
+    @Override
+    public boolean getServiceObject(ComponentContextImpl<S> key, BundleContext context,
+        SimpleLogger logger)
+    {
+        T service = context.getService( getRef() );
+        if ( service == null )
+        {
+            setFailed();
+            logger.log(
+                 LogService.LOG_WARNING,
+                 "Could not get service from ref {0}", new Object[] {getRef()}, null );
+            return false;
+        }
+        if (!setServiceObject(key, service))
+        {
+            // Another thread got the service before, so unget our
+            context.ungetService( getRef() );
+        }
+        return true;
+    }
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ThreadDump.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ThreadDump.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ThreadDump.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ThreadDump.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,51 @@
+/*
+ * 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.manager;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.concurrent.Callable;
+
+import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
+
+public class ThreadDump implements Callable<String>
+{
+
+    @IgnoreJRERequirement
+    public String call() throws Exception
+    {
+        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+        StringBuffer b = new StringBuffer( "Thread dump\n" );
+        ThreadInfo[] infos = threadMXBean.dumpAllThreads( threadMXBean.isObjectMonitorUsageSupported(), threadMXBean.isSynchronizerUsageSupported() );
+        for ( int i = 0; i < infos.length; i++ )
+        {
+            ThreadInfo ti = infos[i];
+            b.append( "\n\nThreadId: " ).append( ti.getThreadId() ).append( " : name: " ).append( ti.getThreadName() ).append( " State: " ).append( ti.getThreadState() );
+            b.append( "\n  LockInfo: " ).append( ti.getLockInfo() ).append( " LockOwnerId: " ).append( ti.getLockOwnerId() ).append( " LockOwnerName: ").append( ti.getLockOwnerName() );
+            StackTraceElement[] stackTrace = ti.getStackTrace();
+            for (int j = 0; j < stackTrace.length; j++ )
+            {
+                b.append( "\n  " ).append( stackTrace[j] );
+            }
+        }
+        return b.toString();
+    }
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ComponentMetadata.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ComponentMetadata.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ComponentMetadata.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,955 @@
+/*
+ * 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.metadata;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.felix.scr.impl.TargetedPID;
+import org.apache.felix.scr.impl.helper.Logger;
+import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
+import org.osgi.service.component.ComponentException;
+
+
+/**
+ * This class holds the information associated to a component in the descriptor *  */
+public class ComponentMetadata
+{
+    // Configuration required for component activation (since DS 1.1)
+    public static final String CONFIGURATION_POLICY_REQUIRE = "require";
+
+    // Configuration not provided to component (since DS 1.1)
+    public static final String CONFIGURATION_POLICY_IGNORE = "ignore";
+
+    // Configuration optional (default) (since DS 1.1)
+    public static final String CONFIGURATION_POLICY_OPTIONAL = "optional";
+
+    // set of valid configuration policy settings
+    private static final Set<String> CONFIGURATION_POLICY_VALID;
+
+    // marker value indicating duplicate implementation class setting
+    private static final String IMPLEMENTATION_CLASS_DUPLICATE = "icd";
+
+    // marker value indicating duplicate service setting
+    private static final ServiceMetadata SERVICE_DUPLICATE = new ServiceMetadata();
+
+    // the namespace code of the namespace declaring this component, this is
+    // one of the XmlHandler.DS_VERSION_* constants
+    private final DSVersion m_dsVersion;
+
+    // 112.4.3: A Globally unique component name (required)
+    private String m_name;
+
+    // 112.4.3: Controls whether the component is enabled when the bundle is started. (optional, default is true).
+    private boolean m_enabled = true;
+
+    // 112.4.3: Factory identified. If set to a non empty string, it indicates that the component is a factory component (optional).
+    private String m_factory = null;
+
+    // 112.4.3: Controls whether component configurations must be immediately activated after becoming
+    // satisfied or whether activation should be delayed. (optional, default value depends
+    // on whether the component has a service element or not).
+    private Boolean m_immediate = null;
+
+    // 112.4.4 Implementation Element (required)
+    private String m_implementationClassName = null;
+
+    // 112.5.8 activate can be specified (since DS 1.1)
+    private String m_activate = null;
+
+    // 112.5.8 whether activate has been specified
+    private boolean m_activateDeclared = false;
+
+    // 112.5.12 deactivate can be specified (since DS 1.1)
+    private String m_deactivate = null;
+
+    // 112.5.12 whether deactivate has been specified
+    private boolean m_deactivateDeclared = false;
+
+    // 112.??.?? modified method (configuration update, since DS 1.1)
+    private String m_modified = null;
+
+    // 112.4.3 configuration-policy (since DS 1.1)
+    private String m_configurationPolicy = null;
+
+    // 112.4.4 configuration-pid (since DS 1.2)
+    private List<String> m_configurationPid;
+
+    // Associated properties (0..*)
+    private Map<String, Object> m_properties = new HashMap<String, Object>();
+
+    // List of Property metadata - used while building the meta data
+    // while validating the properties contained in the PropertyMetadata
+    // instances are copied to the m_properties Dictionary while this
+    // list will be cleared
+    private List<PropertyMetadata> m_propertyMetaData = new ArrayList<PropertyMetadata>();
+
+    // Provided services (0..1)
+    private ServiceMetadata m_service = null;
+
+    // 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;
+    private Boolean m_obsoleteFactoryComponentFactory;
+    private boolean m_configureWithInterfaces;
+    private boolean m_delayedKeepInstances;
+
+    // Flag that is set once the component is verified (its properties cannot be changed)
+    private boolean m_validated = false;
+
+    static
+    {
+        CONFIGURATION_POLICY_VALID = new TreeSet<String>();
+        CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_IGNORE );
+        CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_OPTIONAL );
+        CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_REQUIRE );
+    }
+
+
+    public ComponentMetadata( DSVersion dsVersion )
+    {
+        this.m_dsVersion = dsVersion;
+    }
+
+    /////////////////////////////////////////// SETTERS //////////////////////////////////////
+
+    /**
+     * Setter for the configuration-pid component (since DS 1.2)
+     * @param configurationPid
+     */
+    public void setConfigurationPid( String[] configurationPid )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_configurationPid = new ArrayList<String>( Arrays.asList( configurationPid ) );
+    }
+
+    /**
+     * Setter for the name
+     *
+     * @param name
+     */
+    public void setName( String name )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_name = name;
+    }
+
+
+    /**
+     * Setter for the enabled property
+     *
+     * @param enabled
+     */
+    public void setEnabled( boolean enabled )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_enabled = enabled;
+    }
+
+
+    /**
+     *
+     * @param factoryIdentifier
+     */
+    public void setFactoryIdentifier( String factoryIdentifier )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_factory = factoryIdentifier;
+    }
+
+
+    /**
+     * Setter for the immediate property
+     *
+     * @param immediate
+     */
+    public void setImmediate( boolean immediate )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_immediate = immediate ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+
+    /**
+     * Sets the name of the implementation class
+     *
+     * @param implementationClassName a class name
+     */
+    public void setImplementationClassName( String implementationClassName )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+
+        // set special flag value if implementation class is already set
+        if ( m_implementationClassName != null )
+        {
+            m_implementationClassName = IMPLEMENTATION_CLASS_DUPLICATE;
+        }
+        else
+        {
+            m_implementationClassName = implementationClassName;
+        }
+    }
+
+
+    /**
+     * Sets the configuration policy
+     *
+     * @param configurationPolicy configuration policy
+     * @since 1.2.0 (DS 1.1)
+     */
+    public void setConfigurationPolicy( String configurationPolicy )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_configurationPolicy = configurationPolicy;
+    }
+
+
+    /**
+     * Sets the name of the activate method
+     *
+     * @param activate a method name
+     * @since 1.2.0 (DS 1.1)
+     */
+    public void setActivate( String activate )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_activate = activate;
+        m_activateDeclared = true;
+    }
+
+
+    /**
+     * Sets the name of the deactivate method
+     *
+     * @param deactivate a method name
+     * @since 1.2.0 (DS 1.1)
+     */
+    public void setDeactivate( String deactivate )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_deactivate = deactivate;
+        m_deactivateDeclared = true;
+    }
+
+
+    /**
+     * Sets the name of the modified method
+     *
+     * @param modified a method name
+     * @since 1.2.0 (DS 1.1)
+     */
+    public void setModified( String modified )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        m_modified = modified;
+    }
+
+
+    /**
+     * Used to add a property to the instance
+     *
+     * @param newProperty a property metadata object
+     */
+    public void addProperty( PropertyMetadata newProperty )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        if ( newProperty == null )
+        {
+            throw new IllegalArgumentException( "Cannot add a null property" );
+        }
+        m_propertyMetaData.add( newProperty );
+    }
+
+
+    /**
+     * Used to set a ServiceMetadata object.
+     *
+     * @param service a ServiceMetadata
+     */
+    public void setService( ServiceMetadata service )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+
+        // set special flag value if implementation class is already set
+        if ( m_service != null )
+        {
+            m_service = SERVICE_DUPLICATE;
+        }
+        else
+        {
+            m_service = service;
+        }
+    }
+
+
+    /**
+     * Used to add a reference metadata to the component
+     *
+     * @param newReference a new ReferenceMetadata to be added
+     */
+    public void addDependency( ReferenceMetadata newReference )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+        if ( newReference == null )
+        {
+            throw new IllegalArgumentException( "Cannot add a null ReferenceMetadata" );
+        }
+        m_references.add( newReference );
+    }
+
+    public void setConfigurableServiceProperties( boolean configurableServiceProperties) {
+        if ( m_validated )
+        {
+            return;
+        }
+		this.m_configurableServiceProperties = configurableServiceProperties;
+	}
+
+	public void setPersistentFactoryComponent(boolean persistentFactoryComponent) {
+        if ( m_validated )
+        {
+            return;
+        }
+		this.m_persistentFactoryComponent = persistentFactoryComponent;
+	}
+
+	public void setDeleteCallsModify(boolean deleteCallsModify) {
+        if ( m_validated )
+        {
+            return;
+        }
+		this.m_deleteCallsModify = deleteCallsModify;
+	}
+
+	public void setObsoleteFactoryComponentFactory( boolean obsoleteFactoryComponentFactory) {
+        if ( m_validated )
+        {
+            return;
+        }
+		this.m_obsoleteFactoryComponentFactory = obsoleteFactoryComponentFactory;
+	}
+
+	public void setConfigureWithInterfaces(boolean configureWithInterfaces) {
+		this.m_configureWithInterfaces = configureWithInterfaces;
+	}
+
+	public void setDelayedKeepInstances(boolean delayedKeepInstances) {
+        if ( m_validated )
+        {
+            return;
+        }
+		this.m_delayedKeepInstances = delayedKeepInstances;
+	}
+
+
+
+    /////////////////////////////////////////// GETTERS //////////////////////////////////////
+
+	/**
+     * Returns the namespace code of the namespace of the component element
+     * declaring this component. This is one of the XmlHandler.DS_VERSION_*
+     * constants.
+     */
+    public DSVersion getDSVersion()
+    {
+        return m_dsVersion;
+    }
+
+
+    /**
+     * Returns the name of the component
+     *
+     * @return A string containing the name of the component
+     */
+    public String getName()
+    {
+        // FELIX-2325: Be lenient here and return the name if set or
+        // the implementation class name. This allows for the
+        // BundleComponentActivator.loadComponents method to access the
+        // name before validating the component, which then makes sure
+        // that the name may only be unset for DS 1.1 and newer components
+
+        if ( m_name != null )
+        {
+            return m_name;
+        }
+
+        // return the implementation class name if the name is not set
+        return getImplementationClassName();
+    }
+
+    /**
+     * Returns the configuration pid for the component. The pid is the one specified in the
+     * component's configuration-pid DS 1.2 attribute, if specified. Else the component name is used
+     * as the pid by default.
+     */
+    public List<String> getConfigurationPid()
+    {
+        if ( !m_validated )
+        {
+            throw new IllegalStateException("not yet validated");
+        }
+        return m_configurationPid;
+    }
+
+    public int getPidIndex(TargetedPID pid)
+    {
+        if ( !m_validated )
+        {
+            throw new IllegalStateException("not yet validated");
+        }
+        if (m_configurationPid == null )
+        {
+        	throw new IllegalStateException( "Apparently trying to configure a component " + m_name + " without a configurationPid using " + pid);
+        }
+    	return m_configurationPid.indexOf(pid.getServicePid());
+    }
+
+    /**
+     * Returns whether the configuration-pid has been declared in the descriptor
+     * or not.
+     *
+     * @return whether the configuration-pid has method has been declared in the descriptor
+     *      or not.
+     * @since DS 1.2
+     */
+    public boolean isConfigurationPidDeclared()
+    {
+        return m_configurationPid != null;
+    }
+
+    /**
+     * Returns the value of the enabled flag
+     *
+     * @return a boolean containing the value of the enabled flag
+     */
+    public boolean isEnabled()
+    {
+        return m_enabled;
+    }
+
+
+    /**
+     * Returns the factory identifier
+     *
+     * @return A string containing a factory identifier or null
+     */
+    public String getFactoryIdentifier()
+    {
+        return m_factory;
+    }
+
+
+    /**
+     * Returns the flag that defines the activation policy for the component.
+     * <p>
+     * This method may only be trusted after this instance has been validated
+     * by the {@link #validate( Logger logger )} call. Else it will either return the value
+     * of an explicitly set "immediate" attribute or return false if a service
+     * element or the factory attribute is set or true otherwise. This latter
+     * default value deduction may be unsafe while the descriptor has not been
+     * completely read.
+     *
+     * @return a boolean that defines the activation policy
+     */
+    public boolean isImmediate()
+    {
+        // return explicit value if known
+        if ( m_immediate != null )
+        {
+            return m_immediate.booleanValue();
+        }
+
+        // deduce default from service element and factory attribute presence
+        return m_service == null && m_factory == null;
+    }
+
+
+    /**
+     * Returns the name of the implementation class
+     *
+     * @return the name of the implementation class
+     */
+    public String getImplementationClassName()
+    {
+        return m_implementationClassName;
+    }
+
+
+    /**
+     * Returns the configuration Policy
+     *
+     * @return the configuration policy
+     * @since 1.2.0 (DS 1.1)
+     */
+    public String getConfigurationPolicy()
+    {
+        return m_configurationPolicy;
+    }
+
+
+    /**
+     * Returns the name of the activate method
+     *
+     * @return the name of the activate method
+     * @since 1.2.0 (DS 1.1)
+     */
+    public String getActivate()
+    {
+        return m_activate;
+    }
+
+
+    /**
+     * Returns whether the activate method has been declared in the descriptor
+     * or not.
+     *
+     * @return whether the activate method has been declared in the descriptor
+     *      or not.
+     * @since 1.2.0 (DS 1.1)
+     */
+    public boolean isActivateDeclared()
+    {
+        return m_activateDeclared;
+    }
+
+
+    /**
+     * Returns the name of the deactivate method
+     *
+     * @return the name of the deactivate method
+     * @since 1.2.0 (DS 1.1)
+     */
+    public String getDeactivate()
+    {
+        return m_deactivate;
+    }
+
+
+    /**
+     * Returns whether the deactivate method has been declared in the descriptor
+     * or not.
+     *
+     * @return whether the deactivate method has been declared in the descriptor
+     *      or not.
+     * @since 1.2.0 (DS 1.1)
+     */
+    public boolean isDeactivateDeclared()
+    {
+        return m_deactivateDeclared;
+    }
+
+
+    /**
+     * Returns the name of the modified method
+     *
+     * @return the name of the modified method
+     * @since 1.2.0 (DS 1.1)
+     */
+    public String getModified()
+    {
+        return m_modified;
+    }
+
+
+    /**
+     * Returns the associated ServiceMetadata
+     *
+     * @return a ServiceMetadata object or null if the Component does not provide any service
+     */
+    public ServiceMetadata getServiceMetadata()
+    {
+        return m_service;
+    }
+
+    public Scope getServiceScope()
+    {
+    	if (m_service == null)
+    	{
+    		return Scope.singleton;
+    	}
+    	return m_service.getScope();
+    }
+
+
+    /**
+     * Returns the properties.
+     *
+     * @return the properties as a Dictionary
+     */
+    public Map<String, Object> getProperties()
+    {
+        return m_properties;
+    }
+
+
+    /**
+     * Returns the list of property meta data.
+     * <b>Note: This method is intended for unit testing only</b>
+     *
+     * @return the list of property meta data.
+     */
+    List<PropertyMetadata> getPropertyMetaData()
+    {
+        return m_propertyMetaData;
+    }
+
+
+    /**
+     * Returns the dependency descriptors
+     *
+     * @return a Collection of dependency descriptors
+     */
+    public List<ReferenceMetadata> getDependencies()
+    {
+        return m_references;
+    }
+
+
+    /**
+     * Test to see if this service is a factory
+     *
+     * @return true if it is a factory, false otherwise
+     */
+    public boolean isFactory()
+    {
+        return m_factory != null;
+    }
+
+
+    /**
+     * Returns <code>true</code> if the configuration policy is configured to
+     * {@link #CONFIGURATION_POLICY_REQUIRE}.
+     */
+    public boolean isConfigurationRequired()
+    {
+        return CONFIGURATION_POLICY_REQUIRE.equals( m_configurationPolicy );
+    }
+
+
+    /**
+     * Returns <code>true</code> if the configuration policy is configured to
+     * {@link #CONFIGURATION_POLICY_IGNORE}.
+     */
+    public boolean isConfigurationIgnored()
+    {
+        return CONFIGURATION_POLICY_IGNORE.equals( m_configurationPolicy );
+    }
+
+
+    /**
+     * Returns <code>true</code> if the configuration policy is configured to
+     * {@link #CONFIGURATION_POLICY_OPTIONAL}.
+     */
+    public boolean isConfigurationOptional()
+    {
+        return CONFIGURATION_POLICY_OPTIONAL.equals( m_configurationPolicy );
+    }
+
+
+    public boolean isConfigurableServiceProperties() {
+		return m_configurableServiceProperties;
+	}
+
+	public boolean isPersistentFactoryComponent() {
+		return m_persistentFactoryComponent;
+	}
+
+	public boolean isDeleteCallsModify() {
+		return m_deleteCallsModify;
+	}
+
+	public boolean isObsoleteFactoryComponentFactory() {
+		return m_obsoleteFactoryComponentFactory == null ? false : m_obsoleteFactoryComponentFactory;
+	}
+
+	public boolean isConfigureWithInterfaces() {
+		return m_configureWithInterfaces;
+	}
+
+	public boolean isDelayedKeepInstances() {
+		return m_delayedKeepInstances;
+	}
+
+	/**
+     * Method used to verify if the semantics of this metadata are correct
+     */
+    public void validate( Logger logger )
+    {
+        // nothing to do if already validated
+        if ( m_validated )
+        {
+            return;
+        }
+
+        // 112.10 The name of the component is required
+        if ( m_name == null )
+        {
+            // 112.4.3 name is optional defaulting to implementation class name since DS 1.1
+            if ( !m_dsVersion.isDS11() )
+            {
+                throw new ComponentException( "The component name has not been set" );
+            }
+            setName( getImplementationClassName() );
+        }
+
+        // 112.10 There must be one implementation element and the class atribute is required
+        if ( m_implementationClassName == null )
+        {
+            throw validationFailure( "Implementation class name missing" );
+        }
+        else if ( m_implementationClassName == IMPLEMENTATION_CLASS_DUPLICATE )
+        {
+            throw validationFailure( "Implementation element must occur exactly once" );
+        }
+
+        // 112.4.3 configuration-policy (since DS 1.1)
+        if ( m_configurationPolicy == null )
+        {
+            // default if not specified or pre DS 1.1
+            m_configurationPolicy = CONFIGURATION_POLICY_OPTIONAL;
+        }
+        else if ( !m_dsVersion.isDS11() )
+        {
+            throw validationFailure( "configuration-policy declaration requires DS 1.1 or later namespace " );
+        }
+        else if ( !CONFIGURATION_POLICY_VALID.contains( m_configurationPolicy ) )
+        {
+            throw validationFailure( "configuration-policy must be one of " + CONFIGURATION_POLICY_VALID );
+        }
+
+        // 112.5.8 activate can be specified (since DS 1.1)
+        if ( m_activate == null )
+        {
+            // default if not specified or pre DS 1.1
+            m_activate = "activate";
+        }
+        else if ( !m_dsVersion.isDS11() )
+        {
+            throw validationFailure( "activate method declaration requires DS 1.1 or later namespace " );
+        }
+
+        // 112.5.12 deactivate can be specified (since DS 1.1)
+        if ( m_deactivate == null )
+        {
+            // default if not specified or pre DS 1.1
+            m_deactivate = "deactivate";
+        }
+        else if ( !m_dsVersion.isDS11() )
+        {
+            throw validationFailure( "deactivate method declaration requires DS 1.1 or later namespace " );
+        }
+
+        // 112.??.?? modified can be specified (since DS 1.1)
+        if ( m_modified != null && !m_dsVersion.isDS11() )
+        {
+            throw validationFailure( "modified method declaration requires DS 1.1 or later namespace " );
+        }
+
+        // 112.4.4 configuration-pid can be specified since DS 1.2
+        if ( m_configurationPid == null )
+        {
+            m_configurationPid = Collections.singletonList( getName() );
+        }
+        else
+        {
+            if ( !m_dsVersion.isDS12() )
+            {
+                throw validationFailure( "configuration-pid attribute requires DS 1.2 or later namespace " );
+            }
+            if (m_configurationPid.isEmpty())
+            {
+                throw validationFailure( "configuration-pid nust not be empty string " );
+            }
+            if (m_configurationPid.size() > 1 && !m_dsVersion.isDS13())
+            {
+                throw validationFailure( "multiple configuration-pid requires DS 1.3 or later namespace " );
+            }
+            for (int i = 0; i < m_configurationPid.size(); i++)
+            {
+                if ("$".equals( m_configurationPid.get(i)))
+                {
+                    if (!m_dsVersion.isDS13())
+                    {
+                        throw validationFailure( "Use of '$' configuration-pid wildcard requires DS 1.3 or later namespace " );
+                    }
+                    m_configurationPid.set( i, getName() );
+                }
+            }
+            if ( new HashSet<String>( m_configurationPid ).size() != m_configurationPid.size())
+            {
+                throw validationFailure( "Duplicate pids not allowed: " + m_configurationPid );
+            }
+        }
+
+        // Next check if the properties are valid (and extract property values)
+        for ( PropertyMetadata propMeta: m_propertyMetaData )
+        {
+            propMeta.validate( this );
+            m_properties.put( propMeta.getName(), propMeta.getValue() );
+        }
+        m_propertyMetaData.clear();
+
+        // Check that the provided services are valid too
+        if ( m_service == SERVICE_DUPLICATE )
+        {
+            throw validationFailure( "Service element must occur at most once" );
+        }
+        else if ( m_service != null )
+        {
+            m_service.validate( this );
+        }
+
+        // Check that the references are ok
+        Set<String> refs = new HashSet<String>();
+        for ( ReferenceMetadata refMeta: m_references )
+        {
+            refMeta.validate( this, logger );
+
+            // flag duplicates
+            if ( !refs.add( refMeta.getName() ) )
+            {
+                throw validationFailure( "Detected duplicate reference name: ''" + refMeta.getName() + "''" );
+            }
+        }
+
+        // verify value of immediate attribute if set
+        if ( m_immediate != null )
+        {
+            if ( isImmediate() )
+            {
+                // FELIX-593: 112.4.3 clarification, immediate is false for factory
+                if ( isFactory() )
+                {
+                    throw validationFailure( "Factory cannot be immediate" );
+                }
+            }
+            else
+            {
+                // 112.2.3 A delayed component specifies a service, is not specified to be a factory component
+                // and does not have the immediate attribute of the component element set to true.
+                // FELIX-593: 112.4.3 clarification, immediate may be true for factory
+                if ( m_service == null && !isFactory() )
+                {
+                    throw validationFailure( "Delayed must provide a service or be a factory" );
+                }
+            }
+        }
+
+        // 112.4.6 The serviceFactory attribute (of a provided service) must not be true if
+        // the component is a factory component or an immediate component
+        if ( m_service != null )
+        {
+            if ( (m_service.getScope() != ServiceMetadata.Scope.singleton) && ( isFactory() || isImmediate() ) )
+            {
+                throw validationFailure( "factory or immediate must be scope singleton not " +  m_service.getScope());
+            }
+        }
+
+        if (m_dsVersion == DSVersion.DS12Felix)
+        {
+        	m_configurableServiceProperties = true;
+        }
+        if ( m_configurableServiceProperties && getServiceScope() != Scope.singleton )
+        {
+            throw validationFailure( "configurable service properties only allowed with singleton scope" );
+        }
+        if (m_dsVersion.isDS13())
+        {
+        	m_deleteCallsModify = true; //spec behavior as of 1.3
+        }
+        if ( !m_dsVersion.isDS13() && m_configureWithInterfaces)
+        {
+        	throw validationFailure("Configuration with interfaces or annotations only possible with version 1.3 or later");
+        }
+        if (m_dsVersion.isDS13() && m_obsoleteFactoryComponentFactory != null)
+        {
+        	throw validationFailure("Configuration of component factory instances through config admin factory pids supported only through the 1.2 namespace");
+        }
+        if (m_persistentFactoryComponent && !isFactory())
+        {
+        	throw validationFailure("Only a factory component can be a persistent factory component");
+        }
+
+
+        m_validated = true;
+    }
+
+
+    /**
+     * Returns a <code>ComponentException</code> for this compeonent with the
+     * given explanation for failure.
+     *
+     * @param reason The explanation for failing to validate this component.
+     */
+    ComponentException validationFailure( String reason )
+    {
+        return new ComponentException( "Component " + getName() + " validation failed: " + reason );
+    }
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/DSVersion.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/DSVersion.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/DSVersion.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/DSVersion.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,58 @@
+/*
+ * 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.metadata;
+
+public enum DSVersion
+{
+    DSnone(-1),
+    DS10(0),
+    DS11(1),
+    DS11Felix(2),
+    DS12(3),
+    DS12Felix(4),
+    DS13(5);
+    
+    private final int version;
+    
+    DSVersion(int version) 
+    {
+        this.version = version;
+    }
+    
+    public boolean isDS10()
+    {
+        return version >=DS10.version;
+    }
+
+    public boolean isDS11()
+    {
+        return version >=DS11.version;
+    }
+
+    public boolean isDS12()
+    {
+        return version >=DS12.version;
+    }
+
+    public boolean isDS13()
+    {
+        return version >=DS13.version;
+    }
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/PropertyMetadata.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/PropertyMetadata.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/PropertyMetadata.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/PropertyMetadata.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,336 @@
+/*
+ * 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.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * A property descriptor that contains the information for properties
+ * defined in the descriptor
+ *
+ */
+public class PropertyMetadata {
+
+	// Name of the property (required)
+	private String m_name;
+
+	// Type of the property (optional)
+	private String m_type;
+
+	// Value of the type (optional)
+	// - before validate: raw value from XML (String or String[])
+	// - after validate: converted value provided to component
+	private Object m_value;
+
+	// Flag that indicates if this PropertyMetadata has been validated and thus has become immutable
+	private boolean m_validated = false;
+
+	/**
+	 * Set the name
+	 *
+	 * @param name
+	 */
+	public void setName(String name) {
+		if (m_validated == true) {
+			return;
+		}
+
+		m_name = name;
+	}
+
+
+	/**
+	 * Set the type
+	 *
+	 * @param type
+	 */
+	public void setType(String type) {
+		if (m_validated == true) {
+			return;
+		}
+		m_type = type;
+	}
+
+	/**
+	 * Set the value
+	 *
+	 * @param value
+	 */
+	public void setValue(String value) {
+		if (m_validated == true) {
+			return;
+		}
+        m_value = value;
+	}
+
+    /**
+     * Set multiple values as an array, where the values are contained in
+     * the string as one value per line.
+     *
+     * @param values
+     */
+    public void setValues(String values) {
+        if (m_validated == true) {
+            return;
+        }
+        // splite th values
+        List<String> valueList = new ArrayList<String>();
+        StringTokenizer tokener = new StringTokenizer(values, "\r\n");
+        while (tokener.hasMoreTokens()) {
+            String value = tokener.nextToken().trim();
+            if (value.length() > 0) {
+                valueList.add( value );
+            }
+        }
+        m_value = valueList.toArray( new String[valueList.size()] );
+    }
+
+    /**
+     * Get the name of the property
+     *
+     * @return the name of the property
+     */
+    public String getName() {
+        return m_name;
+    }
+
+    /**
+     * Get the type of the property
+     *
+     * @return the type of the property
+     */
+    public String getType() {
+        return m_type;
+    }
+
+    /**
+     * Get the value of the property
+     *
+     * @return the value of the property as an Object
+     */
+    public Object getValue() {
+        return m_value;
+    }
+
+    /**
+     * Method used to verify if the semantics of this metadata are correct
+     */
+    public void validate( ComponentMetadata componentMetadata )
+    {
+        if ( m_name == null )
+        {
+            throw componentMetadata.validationFailure( "Property name attribute is mandatory" );
+        }
+
+        // check character type name
+        if ( m_type == null )
+        {
+            m_type = "String";
+        }
+        else if ( componentMetadata.getDSVersion().isDS11() && m_type.equals( "Char" ) )
+        {
+            throw componentMetadata
+                .validationFailure( "Illegal property type 'Char' used for DS 1.1 descriptor, use 'Character' instead" );
+        }
+        else if ( !componentMetadata.getDSVersion().isDS11() && m_type.equals( "Character" ) )
+        {
+            throw componentMetadata
+                .validationFailure( "Illegal property type 'Character' used for DS 1.0 descriptor, use 'Char' instead" );
+        }
+
+        // validate and covert value
+        if ( m_value != null )
+        {
+            try
+            {
+                if ( m_value instanceof String )
+                {
+                    m_value = toType( ( String ) m_value );
+                }
+                else
+                {
+                    m_value = toTypeArray( ( String[] ) m_value );
+                }
+            }
+            catch ( NumberFormatException nfe )
+            {
+                throw componentMetadata.validationFailure( getName() + ": Cannot convert property value to "
+                    + getType() );
+            }
+            catch ( IllegalArgumentException e )
+            {
+                throw componentMetadata.validationFailure( getName() + ": " + e.getMessage() );
+            }
+        }
+
+        m_validated = true;
+    }
+
+
+    /**
+     * @throws IllegalArgumentException if the property type is not valid
+     *          according to the spec
+     * @throws NumberFormatException if the string value cannot be converted
+     *          to the numeric type indicated by the property type
+     */
+    private Object toType( String value )
+    {
+        // 112.4.5 Parsing of the value is done by the valueOf(String) method (P. 291)
+        // Should the type accept lowercase too?
+        if ( m_type.equals( "String" ) )
+        {
+            return value;
+        }
+        else if ( m_type.equals( "Long" ) )
+        {
+            return Long.valueOf( value );
+        }
+        else if ( m_type.equals( "Double" ) )
+        {
+            return Double.valueOf( value );
+        }
+        else if ( m_type.equals( "Float" ) )
+        {
+            return Float.valueOf( value );
+        }
+        else if ( m_type.equals( "Integer" ) )
+        {
+            return Integer.valueOf( value );
+        }
+        else if ( m_type.equals( "Byte" ) )
+        {
+            return Byte.valueOf( value );
+        }
+        else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) )
+        {
+            // DS 1.1 changes the "Char" type to "Character", here we support both
+            // For Character types, the conversion is handled by Integer.valueOf method.
+            // (since valueOf is defined in terms of parseInt we directly call
+            // parseInt to prevent unneeded Object creation)
+            return Character.valueOf( ( char ) Integer.parseInt( value ) );
+        }
+        else if ( m_type.equals( "Boolean" ) )
+        {
+            return Boolean.valueOf( value );
+        }
+        else if ( m_type.equals( "Short" ) )
+        {
+            return Short.valueOf( value );
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" );
+        }
+    }
+
+
+    /**
+     * @throws IllegalArgumentException if the property type is not valid
+     *          according to the spec
+     * @throws NumberFormatException if the string value cannot be converted
+     *          to the numeric type indicated by the property type
+     */
+    private Object toTypeArray( String[] valueList )
+    {
+        // 112.4.5 Except for String objects, the result will be translated to an array of primitive types.
+        if ( m_type.equals( "String" ) )
+        {
+            return valueList;
+        }
+        else if ( m_type.equals( "Double" ) )
+        {
+            double[] array = new double[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Double.parseDouble( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Float" ) )
+        {
+            float[] array = new float[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Float.parseFloat( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Long" ) )
+        {
+            long[] array = new long[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Long.parseLong( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Integer" ) )
+        {
+            int[] array = new int[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Integer.parseInt( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Short" ) )
+        {
+            short[] array = new short[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Short.parseShort( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Byte" ) )
+        {
+            byte[] array = new byte[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Byte.parseByte( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) )
+        {
+            // DS 1.1 changes the "Char" type to "Character", here we support both
+            char[] array = new char[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = ( char ) Integer.parseInt( valueList[i] );
+            }
+            return array;
+        }
+        else if ( m_type.equals( "Boolean" ) )
+        {
+            boolean[] array = new boolean[valueList.length];
+            for ( int i = 0; i < array.length; i++ )
+            {
+                array[i] = Boolean.valueOf( valueList[i] );
+            }
+            return array;
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" );
+        }
+    }
+}