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 + "'" );
+ }
+ }
+}