[FELIX-4406] [FELIX-4506] [FELIX-4507] finish r6 xml processing, felix extension processing, and test persistent factory component
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1591421 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index 91a9b16..5d82523 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -237,7 +237,7 @@
stream = descriptorURL.openStream();
BufferedReader in = new BufferedReader( new InputStreamReader( stream, "UTF-8" ) );
- XmlHandler handler = new XmlHandler( m_bundle, this );
+ XmlHandler handler = new XmlHandler( m_bundle, this, getConfiguration().isFactoryEnabled(), getConfiguration().keepInstances() );
KXml2SAXParser parser;
parser = new KXml2SAXParser( in );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
index c40ab5f..435d323 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
@@ -544,7 +544,7 @@
// 112.2.4 SCR must register a Component Factory
// service on behalf of the component
// as soon as the component factory is satisfied
- if ( !activator.getConfiguration().isFactoryEnabled() )
+ if ( !metadata.isObsoleteFactoryComponentFactory() )
{
holder = new ComponentFactoryImpl(activator, metadata );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
index 2615fa4..1efe84b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
@@ -38,7 +38,7 @@
* {@link org.apache.felix.scr.impl.BundleComponentActivator} and the
* {@link org.apache.felix.scr.impl.ComponentRegistry}.
*/
-public interface ComponentHolder
+public interface ComponentHolder<S>
{
/**
@@ -125,5 +125,5 @@
* Informs the holder that the component has been disposed as a result of
* calling the dispose method.
*/
- void disposed( SingleComponentManager component );
+ void disposed( SingleComponentManager<S> component );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
index b921092..3c878b4 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
@@ -54,7 +54,7 @@
* <code>service.factoryPid</code> equals the component name.</li>
* </ul>
*/
-public class ConfigurableComponentHolder<S> implements ComponentHolder, SimpleLogger
+public class ConfigurableComponentHolder<S> implements ComponentHolder<S>, SimpleLogger
{
/**
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 5c1d1e9..a9e75db 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -1389,7 +1389,7 @@
* <code>source</code> is <code>null</code> or empty and
* <code>target</code> was <code>null</code>.
*/
- protected static Dictionary<String, Object> copyTo( Dictionary<String, Object> target, Dictionary<String, Object> source )
+ protected static Dictionary<String, Object> copyTo( Dictionary<String, Object> target, Dictionary<String, ?> source )
{
return copyTo( target, source, true );
}
@@ -1413,7 +1413,7 @@
* <code>target</code> was <code>null</code> or all properties are
* private and had not to be copied
*/
- protected static Dictionary<String, Object> copyTo( Dictionary<String, Object> target, final Dictionary<String, Object> source, final boolean allProps )
+ protected static Dictionary<String, Object> copyTo( Dictionary<String, Object> target, final Dictionary<String, ?> source, final boolean allProps )
{
if ( target == null )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
index b210cdc..fa7d72c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
@@ -52,13 +52,12 @@
* class directly as the holder for component instances created by the
* {@link #newInstance(Dictionary)} method.
* <p>
- * Finally, if the <code>ds.factory.enabled</code> bundle context property is
- * set to <code>true</code>, component instances can be created by factory
- * configurations. This functionality is present for backwards compatibility
- * with earlier releases of the Apache Felix Declarative Services implementation.
- * But keep in mind, that this is non-standard behaviour.
+ * This class implements spec-compliant component factories and the felix
+ * "persistent" component factory, where the factory is always registered whether or
+ * not all dependencies are present and the created components also persist whether or
+ * not the dependencies are present to allow the component instance to exist.
*/
-public class ComponentFactoryImpl<S> extends AbstractComponentManager<S> implements ComponentFactory, ComponentHolder
+public class ComponentFactoryImpl<S> extends AbstractComponentManager<S> implements ComponentFactory, ComponentHolder<S>
{
/**
@@ -94,12 +93,6 @@
protected TargetedPID m_targetedPID;
- /**
- * True if this is a R5 spec component factory
- * False if this is a persistent component factory.
- */
- private boolean m_nonPersistentFactory;
-
public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
{
super( activator, metadata, new ComponentMethods() );
@@ -132,8 +125,7 @@
log( LogService.LOG_DEBUG, "Creating new instance from component factory {0} with configuration {1}",
new Object[] {getComponentMetadata().getName(), dictionary}, null );
- ComponentInstance instance;
- cm.setFactoryProperties( ( Dictionary<String, Object> ) dictionary );
+ cm.setFactoryProperties( dictionary );
//configure the properties
cm.reconfigure( m_configuration, m_changeCount, m_targetedPID );
// enable
@@ -141,12 +133,20 @@
//activate immediately
cm.activateInternal( getTrackingCount().get() );
- instance = cm.getComponentInstance();
- if ( instance == null || (!getComponentMetadata().isPersistentFactoryComponent() && instance.getInstance() == null) )
+ ComponentInstance instance;
+ if ( getComponentMetadata().isPersistentFactoryComponent() )
{
- // activation failed, clean up component manager
- cm.dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
- throw new ComponentException( "Failed activating component" );
+ instance = new ModifyComponentInstance<S>(cm);
+ }
+ else
+ {
+ instance = cm.getComponentInstance();
+ if ( instance == null || instance.getInstance() == null )
+ {
+ // activation failed, clean up component manager
+ cm.dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+ throw new ComponentException( "Failed activating component" );
+ }
}
synchronized ( m_componentInstances )
@@ -154,27 +154,21 @@
m_componentInstances.put( cm, cm );
}
- if ( getComponentMetadata().isPersistentFactoryComponent() )
- {
- instance = new ModifyComponentInstance(cm);
- }
-
return instance;
}
- private static class ModifyComponentInstance implements ExtFactoryComponentInstance
+ private static class ModifyComponentInstance<S> implements ExtFactoryComponentInstance
{
- private final SingleComponentManager cm;
- private long changeCount = 0;
+ private final SingleComponentManager<S> cm;
- public ModifyComponentInstance(SingleComponentManager cm)
+ public ModifyComponentInstance(SingleComponentManager<S> cm)
{
this.cm = cm;
}
public void dispose()
{
- cm.getComponentInstance().dispose();
+ cm.dispose();
}
public Object getInstance()
@@ -205,12 +199,12 @@
*/
public boolean equals(Object object)
{
- if (!(object instanceof ComponentFactoryImpl))
+ if (!(object instanceof ComponentFactoryImpl<?>))
{
return false;
}
- ComponentFactoryImpl other = (ComponentFactoryImpl) object;
+ ComponentFactoryImpl<?> other = (ComponentFactoryImpl<?>) object;
return getComponentMetadata().getName().equals(other.getComponentMetadata().getName());
}
@@ -355,7 +349,7 @@
// So far, we were configured: clear the current configuration.
m_hasConfiguration = false;
- m_configuration = new Hashtable();
+ m_configuration = new Hashtable<String, Object>();
log( LogService.LOG_DEBUG, "Current component factory state={0}", new Object[] {getState()}, null );
@@ -507,7 +501,7 @@
{
List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>( );
getComponentManagers( m_componentInstances, cms );
- for ( AbstractComponentManager acm: cms )
+ for ( AbstractComponentManager<S> acm: cms )
{
acm.dispose( reason );
}
@@ -522,7 +516,8 @@
}
- public void disposed( SingleComponentManager component )
+ @Override
+ public void disposed( SingleComponentManager<S> component )
{
synchronized ( m_componentInstances )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
index 41406af..9c7fd58 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
@@ -35,20 +35,14 @@
import org.osgi.service.log.LogService;
/**
- * The <code>ComponentFactoryImpl</code> extends the {@link org.apache.felix.scr.impl.manager.AbstractComponentManager}
- * class to implement the component factory functionality. As such the
- * OSGi Declarative Services <code>ComponentFactory</code> interface is
- * implemented.
- * <p>
- * In addition the {@link org.apache.felix.scr.impl.config.ComponentHolder} interface is implemented to use this
- * class directly as the holder for component instances created by the
- * {@link #newInstance(java.util.Dictionary)} method.
- * <p>
- * Finally, if the <code>ds.factory.enabled</code> bundle context property is
- * set to <code>true</code>, component instances can be created by factory
- * configurations. This functionality is present for backwards compatibility
- * with earlier releases of the Apache Felix Declarative Services implementation.
- * But keep in mind, that this is non-standard behaviour.
+ * This class implements the Felix non-standard and obsolete extended compponent factory
+ * that allows factory instances to be created through config admin using the component factory pid
+ * as a factory pid. Do not use this for new code, use a plain component instead.
+ * Use of this behavior can be turned on globally with the framework config or config admin
+ * property <code>ds.factory.enabled</code> bundle context property
+ * set to <code>true</code> or turned on per-component with a component descriptor attribute
+ * xmlns:felix="http://felix.apache.org/xmlns/scr/extensions/v1.0.0"
+ * felix:obsoleteFactoryComponentFactory='true'
*/
public class ConfigurationComponentFactoryImpl<S> extends ComponentFactoryImpl<S>
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
index 9ddcdce..61ca8b8 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
@@ -405,7 +405,7 @@
}
}
- protected void setFactoryProperties( Dictionary<String, Object> dictionary )
+ protected void setFactoryProperties( Dictionary<String, ?> dictionary )
{
m_factoryProperties = copyTo( null, dictionary );
}
@@ -936,7 +936,7 @@
private boolean keepInstances()
{
- return getActivator() != null && getActivator().getConfiguration().keepInstances();
+ return getComponentMetadata().isDelayedKeepInstances();
}
public long getChangeCount()
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
index 5a35d8b..c0d3208 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
@@ -118,6 +118,7 @@
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;
@@ -394,11 +395,15 @@
}
public void setConfigureWithInterfaces(boolean configureWithInterfaces) {
+ this.m_configureWithInterfaces = configureWithInterfaces;
+ }
+
+ public void setDelayedKeepInstances(boolean delayedKeepInstances) {
if ( m_validated )
{
return;
}
- this.m_configureWithInterfaces = configureWithInterfaces;
+ this.m_delayedKeepInstances = delayedKeepInstances;
}
@@ -758,6 +763,10 @@
return m_configureWithInterfaces;
}
+ public boolean isDelayedKeepInstances() {
+ return m_delayedKeepInstances;
+ }
+
/**
* Method used to verify if the semantics of this metadata are correct
*/
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
index dd44dcc..c6d53d6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
@@ -29,6 +29,8 @@
*/
public class ReferenceMetadata
{
+ public enum ReferenceScope {bundle, prototype}
+
// constant for option single reference - 0..1
public static final String CARDINALITY_0_1 = "0..1";
@@ -42,7 +44,7 @@
public static final String CARDINALITY_1_N = "1..n";
// set of valid cardinality settings
- private static final Set CARDINALITY_VALID;
+ private static final Set<String> CARDINALITY_VALID;
// constant for static policy
public static final String POLICY_STATIC = "static";
@@ -51,7 +53,7 @@
public static final String POLICY_DYNAMIC = "dynamic";
// set of valid policy settings
- private static final Set POLICY_VALID;
+ private static final Set<String> POLICY_VALID;
// constant for reluctant policy option
public static final String POLICY_OPTION_RELUCTANT = "reluctant";
@@ -60,7 +62,7 @@
public static final String POLICY_OPTION_GREEDY = "greedy";
// set of valid policy option settings
- private static final Set POLICY_OPTION_VALID;
+ private static final Set<String> POLICY_OPTION_VALID;
// Name for the reference (required)
private String m_name = null;
@@ -88,9 +90,9 @@
// Policy option attribute (optional, default = reluctant)
private String m_policy_option = null;
-
- // Flag that is set once the component is verified (its properties cannot be changed)
- private boolean m_validated = false;
+
+ private String m_scopeName;
+ private ReferenceScope m_scope = ReferenceScope.bundle;
// Flags that store the values passed as strings
private boolean m_isStatic = true;
@@ -98,19 +100,22 @@
private boolean m_isMultiple = false;
private boolean m_isReluctant = true;
+ // Flag that is set once the component is verified (its properties cannot be changed)
+ private boolean m_validated = false;
+
static
{
- CARDINALITY_VALID = new TreeSet();
+ CARDINALITY_VALID = new TreeSet<String>();
CARDINALITY_VALID.add( CARDINALITY_0_1 );
CARDINALITY_VALID.add( CARDINALITY_0_N );
CARDINALITY_VALID.add( CARDINALITY_1_1 );
CARDINALITY_VALID.add( CARDINALITY_1_N );
- POLICY_VALID = new TreeSet();
+ POLICY_VALID = new TreeSet<String>();
POLICY_VALID.add( POLICY_DYNAMIC );
POLICY_VALID.add( POLICY_STATIC );
- POLICY_OPTION_VALID = new TreeSet();
+ POLICY_OPTION_VALID = new TreeSet<String>();
POLICY_OPTION_VALID.add( POLICY_OPTION_RELUCTANT );
POLICY_OPTION_VALID.add( POLICY_OPTION_GREEDY );
}
@@ -272,10 +277,18 @@
m_unbind = unbind;
}
+ public void setScope(String scopeName) {
+ if ( m_validated )
+ {
+ return;
+ }
+ this.m_scopeName = scopeName;
+ }
+
/////////////////////////////////////////////// getters ///////////////////////////////////
- /**
+ /**
* Returns the name of the reference
*
* @return A string containing the reference's name
@@ -441,6 +454,10 @@
}
+ public ReferenceScope getScope() {
+ return m_scope;
+ }
+
/**
* Method used to verify if the semantics of this metadata are correct
*
@@ -502,6 +519,21 @@
throw componentMetadata.validationFailure( "updated method declaration requires DS 1.2 or later namespace " );
}
+ if (m_scopeName != null) {
+ if (componentMetadata.getNamespaceCode() < XmlHandler.DS_VERSION_1_3)
+ {
+ throw componentMetadata.validationFailure( "reference scope can be set only for DS >= 1.3");
+ }
+ try
+ {
+ m_scope = ReferenceScope.valueOf(m_scopeName);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw componentMetadata.validationFailure( "reference scope must be 'bundle' or 'prototype' not " + m_scopeName);
+
+ }
+ }
m_validated = true;
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ServiceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ServiceMetadata.java
index 6853996..7c6f62c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ServiceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ServiceMetadata.java
@@ -34,7 +34,8 @@
// 112.4.6 Flag that indicates if the service is a ServiceFactory
private Boolean m_serviceFactory;
- private Scope m_scope;
+ private String m_scopeName;
+ private Scope m_scope = Scope.singleton;
// List of provided interfaces
private List<String> m_provides = new ArrayList<String>();
@@ -55,11 +56,11 @@
m_serviceFactory = serviceFactory;
}
- public void setScope(Scope scope) {
+ public void setScope(String scopeName) {
if(m_validated) {
return;
}
- this.m_scope = scope;
+ this.m_scopeName = scopeName;
}
@@ -101,10 +102,6 @@
throw componentMetadata
.validationFailure( "At least one provided interface must be declared in the service element" );
}
- if (m_scope != null && componentMetadata.getNamespaceCode() < XmlHandler.DS_VERSION_1_3)
- {
- throw componentMetadata.validationFailure("scope can only be specified in version 1.3 and later");
- }
if (m_serviceFactory != null)
{
if (componentMetadata.getNamespaceCode() >= XmlHandler.DS_VERSION_1_3)
@@ -113,9 +110,20 @@
}
m_scope = m_serviceFactory? Scope.bundle: Scope.singleton;
}
- if (m_scope == null)
+ if ( m_scopeName != null )
{
- m_scope = Scope.singleton;
+ if (componentMetadata.getNamespaceCode() < XmlHandler.DS_VERSION_1_3)
+ {
+ throw componentMetadata.validationFailure("service scope can only be specified in version 1.3 and later");
+ }
+ try
+ {
+ m_scope = Scope.valueOf(m_scopeName);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw componentMetadata.validationFailure("Service scope may be only 'singleton' 'bundle' or 'prototype' not " + m_scopeName);
+ }
}
m_validated = true;
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
index f193527..32394c7 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
@@ -29,6 +29,7 @@
import java.util.Map;
import java.util.Properties;
import org.apache.felix.scr.impl.helper.Logger;
+import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
import org.apache.felix.scr.impl.parser.KXml2SAXHandler;
import org.apache.felix.scr.impl.parser.KXml2SAXParser.Attributes;
import org.apache.felix.scr.impl.parser.ParseException;
@@ -78,6 +79,8 @@
public static final String CONFIGURE_WITH_INTERFACES = "configureWithInterfaces";
+ public static final String DELAYED_KEEP_INSTANCES = "delayedKeepInstances";
+
// namespace code for non-DS namespace
public static final int DS_VERSION_NONE = -1;
@@ -107,6 +110,10 @@
// logger for any messages
private final Logger m_logger;
+
+ private final boolean m_globalObsoleteFactoryComponentFactory;
+
+ private final boolean m_globalDelayedKeepInstances;
// A reference to the current component
private ComponentMetadata m_currentComponent;
@@ -144,10 +151,12 @@
// creates an instance with the bundle owning the component descriptor
// file parsed by this instance
- public XmlHandler( Bundle bundle, Logger logger )
+ public XmlHandler( Bundle bundle, Logger logger, boolean globalObsoleteFactoryComponentFactory, boolean globalDelayedKeepInstances )
{
m_bundle = bundle;
m_logger = logger;
+ m_globalObsoleteFactoryComponentFactory = globalObsoleteFactoryComponentFactory;
+ m_globalDelayedKeepInstances = globalDelayedKeepInstances;
}
@@ -270,8 +279,9 @@
m_currentComponent.setConfigurableServiceProperties("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURABLE_SERVICE_PROPERTIES)));
m_currentComponent.setPersistentFactoryComponent("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, PERSISTENT_FACTORY_COMPONENT)));
m_currentComponent.setDeleteCallsModify("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELETE_CALLS_MODIFY)));
- m_currentComponent.setObsoleteFactoryComponentFactory("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, OBSOLETE_FACTORY_COMPONENT_FACTORY)));
+ m_currentComponent.setObsoleteFactoryComponentFactory(m_globalObsoleteFactoryComponentFactory || "true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, OBSOLETE_FACTORY_COMPONENT_FACTORY)));
m_currentComponent.setConfigureWithInterfaces("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURE_WITH_INTERFACES)));
+ m_currentComponent.setDelayedKeepInstances(m_globalDelayedKeepInstances || "true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELAYED_KEEP_INSTANCES)));
// Add this component to the list
m_components.add( m_currentComponent );
@@ -333,6 +343,11 @@
{
m_currentService.setServiceFactory( attributes.getAttribute( "servicefactory" ).equals( "true" ) );
}
+
+ if ( attributes.getAttribute( "scope" ) != null )
+ {
+ m_currentService.setScope( attributes.getAttribute( "scope" ) );
+ }
m_currentComponent.setService( m_currentService );
}
@@ -370,6 +385,11 @@
ref.setPolicyOption( attributes.getAttribute( "policy-option" ) );
}
+ if ( attributes.getAttribute( "scope" ) != null )
+ {
+ ref.setScope( attributes.getAttribute( "scope" ) );
+ }
+
//if
ref.setTarget( attributes.getAttribute( "target" ) );
ref.setBind( attributes.getAttribute( "bind" ) );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/parser/KXml2SAXParser.java b/scr/src/main/java/org/apache/felix/scr/impl/parser/KXml2SAXParser.java
index ec79086..c9d2ad8 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/parser/KXml2SAXParser.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/parser/KXml2SAXParser.java
@@ -23,7 +23,9 @@
import java.util.Properties;
import java.util.Stack;
+import org.apache.felix.scr.impl.helper.Logger;
import org.kxml2.io.KXmlParser;
+import org.osgi.service.log.LogService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -161,5 +163,6 @@
public String getAttribute(String uri, String name) {
return getAttributeValue(uri, name);
}
+
}
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
index 833dc37..56c0b38 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
@@ -382,7 +382,7 @@
{
final KXml2SAXParser parser = new KXml2SAXParser( reader );
- XmlHandler handler = new XmlHandler( new MockBundle(), logger );
+ XmlHandler handler = new XmlHandler( new MockBundle(), logger, false, false );
parser.parseXML( handler );
return handler.getComponentMetadataList();
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java
new file mode 100644
index 0000000..c7b11ed
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java
@@ -0,0 +1,664 @@
+/*
+ * 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.integration;
+
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.apache.felix.scr.integration.components.SimpleServiceImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.log.LogService;
+
+
+@RunWith(JUnit4TestRunner.class)
+public class PersistentComponentFactoryTest extends ComponentTestBase
+{
+
+ private static final String PROP_NAME_FACTORY = ComponentTestBase.PROP_NAME + ".factory";
+
+ static
+ {
+ descriptorFile = "/integration_test_persistent_factory_components.xml";
+ // uncomment to enable debugging of this test class
+// paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
+ @Test
+ public void test_component_factory() throws InvalidSyntaxException
+ {
+ final String componentname = "factory.component";
+ final String componentfactory = "factory.component.factory";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_componentInstances" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ final Object instanceManager = getComponentManagerFromExtComponentInstance( instance );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+ // check registered components
+ final Component[] allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ instance.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ TestCase.assertEquals( 0, instanceMap.size() );
+ TestCase.assertFalse( instanceMap.containsValue( instanceManager ) );
+ }
+
+
+ @Test
+ public void test_component_factory_disable_factory() throws InvalidSyntaxException
+ {
+ // tests components remain alive after factory has been disabled
+
+ final String componentname = "factory.component";
+ final String componentfactory = "factory.component.factory";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_componentInstances" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ final Object instanceManager = getComponentManagerFromExtComponentInstance( instance );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+ // disable the factory
+ component.disable();
+ delay();
+
+ // factory is disabled but the instance is still alive
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( 1, instanceMap.size() );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+ instance.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ TestCase.assertEquals( 0, instanceMap.size() );
+ TestCase.assertFalse( instanceMap.containsValue( instanceManager ) );
+ }
+
+
+ @Test
+ public void test_component_factory_newInstance_failure() throws InvalidSyntaxException
+ {
+ final String componentname = "factory.component";
+ final String componentfactory = "factory.component.factory";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ props.put( SimpleComponent.PROP_ACTIVATE_FAILURE, "Requested Failure" );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_componentInstances" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ }
+
+
+ @Test
+ public void test_component_factory_require_configuration() throws InvalidSyntaxException
+ {
+ final String componentname = "factory.component.configuration";
+ final String componentfactory = "factory.component.factory.configuration";
+
+ // ensure there is no configuration for the component
+ deleteConfig( componentname );
+ delay();
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ // At this point, since we don't have created the configuration, then the ComponentFactory
+ // should not be available.
+
+ ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNull( refs );
+
+ // supply configuration now and ensure active
+ configure( componentname );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ // get the component factory service
+ refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ // create an instance
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ final Object instanceObject = instance.getInstance();
+ TestCase.assertNotNull( instanceObject );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instanceObject );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_componentInstances" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ final Object instanceManager = getComponentManagerFromExtComponentInstance( instance );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+ // delete config, ensure factory is not active anymore and component instance not changed
+ deleteConfig( componentname );
+ delay();
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( instanceObject, instance.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+ instance.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE ); // component is deactivated
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ // with removal of the factory, the created instance should also be removed
+ TestCase.assertEquals( 0, instanceMap.size() );
+ TestCase.assertFalse( instanceMap.containsValue( instanceManager ) );
+ }
+
+ @Test
+ public void test_component_factory_reference() throws InvalidSyntaxException
+ {
+ final String componentname = "factory.component.reference";
+ final String componentfactory = "factory.component.factory.reference";
+
+ SimpleServiceImpl.create( bundleContext, "ignored" ).setFilterProperty( "ignored" );
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ // missing reference, persistent -> created anyway
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ // register a service : filterprop=match
+ SimpleServiceImpl match = SimpleServiceImpl.create( bundleContext, "required" ).setFilterProperty( "required" );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ // non-overwrite filterprop
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+ TestCase.assertEquals( 1, SimpleComponent.INSTANCE.m_multiRef.size() );
+ TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( match ) );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_componentInstances" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ final Object instanceManager = getComponentManagerFromExtComponentInstance( instance );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+ // check registered components
+ final Component[] allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ instance.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ TestCase.assertEquals( 0, instanceMap.size() );
+ TestCase.assertFalse( instanceMap.containsValue( instanceManager ) );
+
+ // overwritten filterprop
+ Hashtable<String, String> propsNonMatch = new Hashtable<String, String>();
+ propsNonMatch.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ propsNonMatch.put( "ref.target", "(filterprop=nomatch)" );
+ final ComponentInstance instanceNonMatch = factory.newInstance( propsNonMatch ); //works even without required dependency
+
+ final SimpleServiceImpl noMatch = SimpleServiceImpl.create( bundleContext, "nomatch" ).setFilterProperty(
+ "nomatch" );
+ delay();
+
+ TestCase.assertNotNull( instanceNonMatch );
+
+ TestCase.assertNotNull( instanceNonMatch.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instanceNonMatch.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+
+ TestCase.assertEquals( 1, SimpleComponent.INSTANCE.m_multiRef.size() );
+ TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( noMatch ) );
+
+ // check registered components
+ final Component[] allFactoryComponents2 = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents2 );
+ TestCase.assertEquals( 2, allFactoryComponents2.length );
+ for ( int i = 0; i < allFactoryComponents2.length; i++ )
+ {
+ final Component c = allFactoryComponents2[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c + " id: " + c.getId() + " current: " + SimpleComponent.INSTANCE.m_id );
+ }
+ }
+
+ match.getRegistration().unregister();
+ delay();
+
+ // check registered components (ComponentFactory aint no longer)
+ final Component[] allFactoryComponents3 = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents3 );
+ TestCase.assertEquals( 2, allFactoryComponents3.length );
+ long lastId = SimpleComponent.INSTANCE.m_id;
+ for ( int i = 0; i < allFactoryComponents3.length; i++ )
+ {
+ final Component c = allFactoryComponents3[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c.getState() );
+ }
+ else if ( c.getId() == lastId )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ //it has already been deactivated.... this should cause an exception?
+ noMatch.getRegistration().unregister();
+ delay();
+
+ // check registered components (ComponentFactory is still present)
+ final Component[] allFactoryComponents4 = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents4 );
+ TestCase.assertEquals( 2, allFactoryComponents4.length );
+ for ( int i = 0; i < allFactoryComponents4.length; i++ )
+ {
+ final Component c = allFactoryComponents4[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c.getState() );
+ }
+ else if ( c.getId() == lastId )
+ {
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // deactivated due to unsatisfied reference
+ TestCase.assertNull( instanceNonMatch.getInstance() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ //Check that calling dispose on a deactivated instance has no effect
+ instanceNonMatch.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertNull( instanceNonMatch.getInstance() ); // SCR 112.12.6.2
+ }
+
+ @Test
+ public void test_component_factory_referredTo() throws InvalidSyntaxException
+ {
+ //set up the component that refers to the service the factory will create.
+ final String referringComponentName = "ComponentReferringToFactoryObject";
+ final Component referringComponent = findComponentByName( referringComponentName );
+ TestCase.assertNotNull( referringComponent );
+ referringComponent.enable();
+ delay();
+
+ //make sure it's unsatisfied (service is not yet available
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, referringComponent.getState() );
+
+
+ final String componentname = "factory.component.referred";
+ final String componentfactory = "factory.component.factory.referred";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ // create the factory instance
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( "service.pid", "myFactoryInstance" );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+
+ //The referring service should now be active
+ TestCase.assertEquals( Component.STATE_ACTIVE, referringComponent.getState() );
+
+ instance.dispose();
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ //make sure it's unsatisfied (service is no longer available)
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, referringComponent.getState() );
+ }
+
+ @Test
+ public void test_component_factory_with_target_filters() throws InvalidSyntaxException
+ {
+ final String componentfactory = "factory.component.reference.targetfilter";
+ final Component component = findComponentByName( componentfactory );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ SimpleServiceImpl s1 = SimpleServiceImpl.create(bundleContext, "service1");
+ SimpleServiceImpl s2 = SimpleServiceImpl.create(bundleContext, "service2");
+
+ // supply configuration now and ensure active
+ configure( componentfactory );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ props.put("ref.target", "(value=service2)");
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) );
+
+ log.log(LogService.LOG_WARNING, "Bound Services: " + SimpleComponent.INSTANCE.m_multiRef);
+ TestCase.assertFalse( SimpleComponent.INSTANCE.m_multiRef.contains( s1 ) );
+ TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( s2 ) );
+
+ instance.dispose();
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ s2.drop();
+ s1.drop();
+ }
+
+ @Test
+ public void test_component_factory_set_bundle_location_null() throws Exception
+ {
+ final String componentfactory = "factory.component.reference.targetfilter";
+ final Component component = findComponentByName( componentfactory );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ SimpleServiceImpl s1 = SimpleServiceImpl.create(bundleContext, "service1");
+
+ ConfigurationAdmin ca = getConfigurationAdmin();
+ org.osgi.service.cm.Configuration config = ca.getConfiguration( componentfactory, null );
+ config.setBundleLocation( null );
+ delay();
+ if ( isAtLeastR5() )
+ {
+ //check that ConfigurationSupport got a Location changed event and set the bundle location
+ TestCase.assertNotNull( config.getBundleLocation() );
+ }
+ // supply configuration now and ensure active
+ configure( componentfactory );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ s1.drop();
+ }
+
+ private Object getComponentManagerFromExtComponentInstance( Object extIinstance )
+ {
+ return getFieldValue( extIinstance, "cm");
+ }
+
+
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
index 5c6b017..9f1c7ba 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
@@ -42,7 +42,7 @@
static
{
// uncomment to enable debugging of this test class
- // paxRunnerVmOption = DEBUG_VM_OPTION;
+// paxRunnerVmOption = DEBUG_VM_OPTION;
}
@@ -181,17 +181,17 @@
public void test_DelayedSimpleComponent_service_keep_instance() throws IOException
{
// configure SCR to keep instances
- Configuration scrConfig = getConfigurationAdmin().getConfiguration( ScrConfiguration.PID, null );
- Dictionary props = scrConfig.getProperties();
- if ( props == null )
- {
- props = new Hashtable();
- }
- props.put( ScrConfiguration.PROP_DELAYED_KEEP_INSTANCES, Boolean.TRUE.toString() );
- scrConfig.update( props );
- delay();
+// Configuration scrConfig = getConfigurationAdmin().getConfiguration( ScrConfiguration.PID, null );
+// Dictionary props = scrConfig.getProperties();
+// if ( props == null )
+// {
+// props = new Hashtable();
+// }
+// props.put( ScrConfiguration.PROP_DELAYED_KEEP_INSTANCES, Boolean.TRUE.toString() );
+// scrConfig.update( props );
+// delay();
- final String pid = "DelayedServiceComponent";
+ final String pid = "DelayedKeepInstancesServiceComponent";
// one single component exists without configuration
final Component component = findComponentByName( pid );
@@ -228,6 +228,6 @@
TestCase.assertNotNull( SimpleComponent.INSTANCE );
// delete the SCR configuration again
- scrConfig.delete();
+// scrConfig.delete();
}
}
diff --git a/scr/src/test/resources/integration_test_persistent_factory_components.xml b/scr/src/test/resources/integration_test_persistent_factory_components.xml
new file mode 100644
index 0000000..816e0b1
--- /dev/null
+++ b/scr/src/test/resources/integration_test_persistent_factory_components.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
+ xmlns:felix="http://felix.apache.org/xmlns/scr/extensions/v1.0.0">
+
+ <!-- Component Factory Instances -->
+ <scr:component name="factory.component"
+ felix:persistentFactoryComponent="true"
+ enabled="false"
+ factory="factory.component.factory" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ </scr:component>
+
+ <!-- Component Factory Instances, requiring configuration -->
+ <scr:component name="factory.component.configuration"
+ felix:persistentFactoryComponent="true"
+ enabled="false"
+ configuration-policy="require"
+ factory="factory.component.factory.configuration" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ </scr:component>
+
+ <!-- Component Factory Instances, requiring configuration -->
+ <scr:component name="factory.component.reference"
+ felix:persistentFactoryComponent="true"
+ enabled="false"
+ configuration-policy="ignore"
+ factory="factory.component.factory.reference" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <reference
+ name="ref"
+ interface="org.apache.felix.scr.integration.components.SimpleService"
+ cardinality="1..n"
+ policy="static"
+ bind="bindSimpleService"
+ unbind="unbindSimpleService"
+ target="(filterprop=required)"
+ />
+ </scr:component>
+
+ <!-- Component Factory Instances, instance is referred to by another component -->
+ <scr:component name="factory.component.referred"
+ felix:persistentFactoryComponent="true"
+ enabled="false"
+ factory="factory.component.factory.referred" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleServiceImpl" />
+ <service>
+ <provide interface="org.apache.felix.scr.integration.components.SimpleService" />
+ </service>
+ </scr:component>
+
+ <!-- component has a reference to service created by the factory.component.referred factory component-->
+ <scr:component name="ComponentReferringToFactoryObject"
+ enabled="false"
+ immediate="true">
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <property name="service.pid" value="ComponentReferringToFactoryObject" />
+ <reference
+ name="ref"
+ interface="org.apache.felix.scr.integration.components.SimpleService"
+ cardinality="1..1"
+ policy="dynamic"
+ bind="bindSimpleService"
+ unbind="unbindSimpleService"
+ target="(service.pid=myFactoryInstance)"
+ />
+ </scr:component>
+
+ <!-- Component Factory Instance, requiring configuration + 1 specific Reference -->
+ <scr:component name="factory.component.reference.targetfilter"
+ felix:persistentFactoryComponent="true"
+ enabled="false"
+ configuration-policy="require"
+ factory="factory.component.reference.targetfilter" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <reference
+ name="ref"
+ interface="org.apache.felix.scr.integration.components.SimpleService"
+ cardinality="1..1"
+ policy="dynamic"
+ bind="bindSimpleService"
+ unbind="unbindSimpleService"
+ />
+ </scr:component>
+
+</components>
diff --git a/scr/src/test/resources/integration_test_simple_components.xml b/scr/src/test/resources/integration_test_simple_components.xml
index 3907051..07de31a 100644
--- a/scr/src/test/resources/integration_test_simple_components.xml
+++ b/scr/src/test/resources/integration_test_simple_components.xml
@@ -121,5 +121,17 @@
</service>
</scr:component>
+ <scr:component name="DelayedKeepInstancesServiceComponent"
+ enabled="false" immediate="false"
+ configuration-policy="ignore"
+ xmlns:felix="http://felix.apache.org/xmlns/scr/extensions/v1.0.0"
+ felix:delayedKeepInstances="true" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent"/>
+ <property name="service.pid" value="ServiceComponent" />
+ <service>
+ <provide interface="java.lang.Object" />
+ </service>
+ </scr:component>
+
</components>