FELIX-3651 Location tests for LOCATION_CHANGED event and region locations
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1515660 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 33fc587..24fdf65 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -20,10 +20,12 @@
import java.io.PrintStream;
+import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.apache.felix.scr.impl.config.ScrConfiguration;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.apache.felix.utils.extender.AbstractExtender;
import org.apache.felix.utils.extender.Extension;
import org.osgi.framework.Bundle;
@@ -98,8 +100,8 @@
m_configuration.start( m_context );
// log SCR startup
- log( LogService.LOG_INFO, m_context.getBundle(), " Version = "
- + m_context.getBundle().getHeaders().get( Constants.BUNDLE_VERSION ), null );
+ log( LogService.LOG_INFO, m_context.getBundle(), " Version = {0}",
+ new Object[] {m_context.getBundle().getHeaders().get( Constants.BUNDLE_VERSION )}, null );
// create and start the component actor
m_componentActor = new ComponentActorThread();
@@ -195,8 +197,8 @@
BundleContext context = bundle.getBundleContext();
if ( context == null )
{
- log( LogService.LOG_ERROR, m_context.getBundle(), "Cannot get BundleContext of bundle "
- + bundle.getSymbolicName() + "/" + bundle.getBundleId(), null );
+ log( LogService.LOG_ERROR, m_context.getBundle(), "Cannot get BundleContext of bundle {0}/{1}",
+ new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, null );
return;
}
@@ -223,8 +225,8 @@
// terminate if already loaded (or currently being loaded)
if ( loaded )
{
- log( LogService.LOG_DEBUG, m_context.getBundle(), "Components for bundle " + bundle.getSymbolicName()
- + "/" + bundle.getBundleId() + " already loaded. Nothing to do.", null );
+ log( LogService.LOG_DEBUG, m_context.getBundle(), "Components for bundle {0}/{1} already loaded. Nothing to do.",
+ new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, null );
return;
}
@@ -253,17 +255,14 @@
log(
LogService.LOG_DEBUG,
m_context.getBundle(),
- "Bundle "
- + bundle.getSymbolicName()
- + "/"
- + bundle.getBundleId()
- + " has been stopped while trying to activate its components. Trying again when the bundles gets startet again.",
+ "Bundle {0}/{1} has been stopped while trying to activate its components. Trying again when the bundles gets started again.",
+ new Object[] {bundle.getSymbolicName(), bundle.getBundleId()},
e );
}
else
{
- log( LogService.LOG_ERROR, m_context.getBundle(), "Error while loading components of bundle "
- + bundle.getSymbolicName() + "/" + bundle.getBundleId(), e );
+ log( LogService.LOG_ERROR, m_context.getBundle(), "Error while loading components of bundle {0}/{1}",
+ new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, e );
}
}
}
@@ -292,8 +291,8 @@
}
catch ( Exception e )
{
- log( LogService.LOG_ERROR, m_context.getBundle(), "Error while disposing components of bundle "
- + bundle.getSymbolicName() + "/" + bundle.getBundleId(), e );
+ log( LogService.LOG_ERROR, m_context.getBundle(), "Error while disposing components of bundle {0}/{1}",
+ new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, e );
}
}
}
@@ -313,6 +312,23 @@
log( LogService.LOG_DEBUG, m_context.getBundle(), msg, t );
}
+ public static void log( int level, Bundle bundle, String pattern, Object[] arguments, Throwable ex )
+ {
+ if ( isLogEnabled( level ) )
+ {
+ final String message = MessageFormat.format( pattern, arguments );
+ log( level, bundle, message, ex );
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if logging for the given level is enabled.
+ */
+ public static boolean isLogEnabled( int level )
+ {
+ return m_configuration.getLogLevel() >= level;
+ }
+
/**
* Method to actually emit the log message. If the LogService is available,
* the message will be logged through the LogService. Otherwise the message
@@ -325,7 +341,7 @@
*/
public static void log( int level, Bundle bundle, String message, Throwable ex )
{
- if ( m_configuration.getLogLevel() >= level )
+ if ( isLogEnabled( level ) )
{
ServiceTracker t = m_logService;
Object logger = ( t != null ) ? t.getService() : null;
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentActorThread.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentActorThread.java
index 8083ee7..0194a9f 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentActorThread.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentActorThread.java
@@ -144,8 +144,8 @@
// append to the task queue
tasks.add( task );
- Activator.log( LogService.LOG_DEBUG, null, "Adding task [" + task + "] as #" + tasks.size()
- + " in the queue", null );
+ Activator.log( LogService.LOG_DEBUG, null, "Adding task [{0}] as #{1} in the queue"
+ , new Object[] {task, tasks.size()}, null );
// notify the waiting thread
tasks.notifyAll();
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 8737d6b..9a12d1e 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
@@ -51,6 +51,7 @@
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentException;
+import org.osgi.service.log.LogService;
/**
@@ -386,13 +387,17 @@
*/
final void registerComponentHolder( final ComponentRegistryKey key, ComponentHolder componentHolder )
{
+ Activator.log(LogService.LOG_DEBUG, null,
+ "Registering component with pid {0} for bundle {1}",
+ new Object[] {componentHolder.getComponentMetadata().getConfigurationPid(),key.getBundleId()},
+ null);
synchronized ( m_componentHoldersByName )
{
// only register the component if there is a m_registration for it !
if ( m_componentHoldersByName.get( key ) != null )
{
// this is not expected if all works ok
- throw new ComponentException( "The component name '" + componentHolder.getComponentMetadata().getName()
+ throw new ComponentException( "The component name '{0}" + componentHolder.getComponentMetadata().getName()
+ "' has already been registered." );
}
@@ -505,6 +510,9 @@
}
if (component != null) {
+ Activator.log(LogService.LOG_DEBUG, null,
+ "Unregistering component with pid {0} for bundle {1}",
+ new Object[] {component.getComponentMetadata().getConfigurationPid(), key.getBundleId()}, null);
synchronized (m_componentHoldersByPid)
{
String configurationPid = component.getComponentMetadata().getConfigurationPid();
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistryKey.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistryKey.java
index ca9cef4..b71e854 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistryKey.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistryKey.java
@@ -66,4 +66,18 @@
return false;
}
+
+
+ public long getBundleId()
+ {
+ return bundleId;
+ }
+
+
+ public String getComponentName()
+ {
+ return componentName;
+ }
+
+
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
index 4492cb4..a6af683 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
@@ -155,8 +156,8 @@
}
else
{
- Activator.log( LogService.LOG_WARNING, null, "Cannot configure component "
- + holder.getComponentMetadata().getName(), null );
+ Activator.log( LogService.LOG_WARNING, null, "Cannot configure component {0}",
+ new Object[] {holder.getComponentMetadata().getName()}, null );
Activator.log( LogService.LOG_WARNING, null,
"Component Bundle's Configuration Admin is not compatible with "
+ "ours. This happens if multiple Configuration Admin API versions "
@@ -235,9 +236,9 @@
holders = this.m_registry.getComponentHoldersByPid(factoryPid);
}
- Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling "
- + ((event.getType() == ConfigurationEvent.CM_DELETED) ? "DELETE" : "UPDATE")
- + " of Configuration PID=" + pid, null);
+ Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling {0} of Configuration PID={1} for component holders {2}",
+ new Object[] {getEventType(event), pid, holders},
+ null);
for ( ComponentHolder componentHolder: holders )
{
@@ -384,13 +385,29 @@
break;
}
default:
- Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(),
+ Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type {0}", new Object[] {event.getType()},
null);
}
}
}
}
+ private String getEventType(ConfigurationEvent event)
+ {
+ switch (event.getType())
+ {
+ case ConfigurationEvent.CM_UPDATED:
+ return "UPDATED";
+ case ConfigurationEvent.CM_DELETED:
+ return "DELETED";
+ case ConfigurationEvent.CM_LOCATION_CHANGED:
+ return "LOCATION CHANGED";
+ default:
+ return "Unkown event type: " + event.getType();
+ }
+
+ }
+
private static class ConfigurationInfo
{
private final Configuration configuration;
@@ -438,8 +455,8 @@
}
else
{
- Activator.log( LogService.LOG_WARNING, null, "Cannot reconfigure component "
- + componentHolder.getComponentMetadata().getName(), null );
+ Activator.log( LogService.LOG_WARNING, null, "Cannot reconfigure component {0}",
+ new Object[] {componentHolder.getComponentMetadata().getName()}, null );
Activator.log( LogService.LOG_WARNING, null,
"Component Bundle's Configuration Admin is not compatible with " +
"ours. This happens if multiple Configuration Admin API versions " +
@@ -474,7 +491,7 @@
}
catch (IOException ioe)
{
- Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe);
+ Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid={0}", new Object[] {pid}, ioe);
}
return null;
@@ -583,11 +600,11 @@
}
catch (IOException ioe)
{
- Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe);
+ Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter={0}", new Object[] {filter}, ioe);
}
catch (InvalidSyntaxException ise)
{
- Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise);
+ Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter {0}", new Object[] {filter}, ise);
}
// no factories in case of problems
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
index 367d547..3d2edc0 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
@@ -25,6 +25,7 @@
import java.util.Map;
import org.apache.felix.scr.Component;
+import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.TargetedPID;
import org.apache.felix.scr.impl.helper.ComponentMethods;
@@ -488,7 +489,7 @@
* <p>
* A ImmediateComponentHolder is considered to be <b>equal to </b> another
* ImmediateComponentHolder if the component names are equal(using
- * {@code String.equals}).
+ * {@code String.equals}) and they have the same bundle activator
*
* @param object The {@code ImmediateComponentHolder} object to be compared.
* @return {@code true} if {@code object} is a
@@ -503,7 +504,8 @@
}
ImmediateComponentHolder other = (ImmediateComponentHolder) object;
- return getComponentMetadata().getName().equals(other.getComponentMetadata().getName());
+ return m_activator == other.m_activator
+ && getComponentMetadata().getName().equals(other.getComponentMetadata().getName());
}
/**
@@ -543,14 +545,7 @@
public boolean isLogEnabled( int level )
{
- BundleComponentActivator activator = getActivator();
- if ( activator != null )
- {
- return activator.isLogEnabled( level );
- }
-
- // bundle activator has already been removed, so no logging
- return false;
+ return Activator.isLogEnabled( level );
}
public void log( int level, String message, Throwable ex )
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 7266990..8e9d5f2 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
@@ -40,6 +40,7 @@
import org.apache.felix.scr.Component;
import org.apache.felix.scr.Reference;
+import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.config.ScrConfiguration;
import org.apache.felix.scr.impl.helper.ComponentMethods;
@@ -1091,14 +1092,7 @@
*/
public boolean isLogEnabled( int level )
{
- BundleComponentActivator activator = getActivator();
- if ( activator != null )
- {
- return activator.isLogEnabled( level );
- }
-
- // bundle activator has already been removed, so no logging
- return false;
+ return Activator.isLogEnabled( level );
}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index 7f7011b..abbc7c5 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -269,19 +269,30 @@
return ca;
}
+ protected org.osgi.service.cm.Configuration configure( String pid )
+ {
+ return configure( pid, null );
+
+ }
- protected void configure( String pid )
+ protected org.osgi.service.cm.Configuration configure( String pid, String bundleLocation )
{
ConfigurationAdmin ca = getConfigurationAdmin();
try
{
org.osgi.service.cm.Configuration config = ca.getConfiguration( pid, null );
+ if (bundleLocation != null)
+ {
+ config.setBundleLocation( bundleLocation );
+ }
config.update( theConfig );
+ return config;
}
catch ( IOException ioe )
{
TestCase.fail( "Failed updating configuration " + pid + ": " + ioe.toString() );
}
+ return null;
}
@@ -403,14 +414,19 @@
protected Bundle installBundle( final String descriptorFile, String componentPackage ) throws BundleException
{
+ return installBundle(descriptorFile, componentPackage, "simplecomponent", "0.0.11");
+ }
+
+ protected Bundle installBundle( final String descriptorFile, String componentPackage, String symbolicName, String version ) throws BundleException
+ {
final InputStream bundleStream = bundle()
- .add("OSGI-INF/components.xml", getClass().getResource(descriptorFile))
+ .add("OSGI-INF/components.xml", getClass().getResource(descriptorFile))
- .set(Constants.BUNDLE_SYMBOLICNAME, "simplecomponent")
- .set(Constants.BUNDLE_VERSION, "0.0.11")
+ .set(Constants.BUNDLE_SYMBOLICNAME, symbolicName)
+ .set(Constants.BUNDLE_VERSION, version)
.set(Constants.IMPORT_PACKAGE, componentPackage)
.set("Service-Component", "OSGI-INF/components.xml")
- .build(withBnd());
+ .build(withBnd());
try
{
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java
new file mode 100644
index 0000000..63e24f1
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java
@@ -0,0 +1,238 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.cm.ConfigurationPermission;
+
+@RunWith(JUnit4TestRunner.class)
+public class LocationTest extends ComponentTestBase
+{
+
+ private static final String COMPONENT_NAME = "SimpleComponent.configuration.require";
+ private static final String REGION = "?foo";
+ private boolean eventReceived;
+
+ static
+ {
+ descriptorFile = "/integration_test_simple_components_location.xml";
+ // uncomment to enable debugging of this test class
+// paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
+
+ @Test
+ public void testLocationBinding() throws Exception
+ {
+ final String pid = COMPONENT_NAME;
+ final Component component = findComponentByName( pid );
+
+ deleteConfig( pid );
+ delay();
+
+ 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 );
+
+ Configuration config = configure( pid );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+
+ Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+ b2.start();
+ Component[] components = findComponentsByName( pid );
+ TestCase.assertEquals( 2, components.length );
+ Component c2 = components[0] == component? components[1]: components[0];
+
+ c2.enable();
+ delay();
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c2.getState() );
+
+ bundle.stop();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c2.getState() );
+
+ ConfigurationListener listener = new ConfigurationListener() {
+
+ public void configurationEvent(ConfigurationEvent event)
+ {
+ if (event.getType() == ConfigurationEvent.CM_LOCATION_CHANGED)
+ {
+ eventReceived = true;
+ }
+ }
+
+ };
+ ServiceRegistration<ConfigurationListener> sr = bundleContext.registerService( ConfigurationListener.class, listener, null );
+ config.setBundleLocation( null );
+ delay();
+
+ if ( eventReceived )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c2.getState() );
+ }
+
+ sr.unregister();
+
+
+ }
+
+ @Test
+ public void testLocationChangeToRegionBinding() throws Exception
+ {
+ final String pid = COMPONENT_NAME;
+ final Component component = findComponentByName( pid );
+
+ deleteConfig( pid );
+ delay();
+
+ 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 );
+
+ Configuration config = configure( pid );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+
+ Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+ b2.start();
+ Component[] components = findComponentsByName( pid );
+ TestCase.assertEquals( 2, components.length );
+ Component c2 = components[0] == component? components[1]: components[0];
+
+ c2.enable();
+ delay();
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c2.getState() );
+
+ bundle.stop();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c2.getState() );
+
+ ConfigurationListener listener = new ConfigurationListener() {
+
+ public void configurationEvent(ConfigurationEvent event)
+ {
+ if (event.getType() == ConfigurationEvent.CM_LOCATION_CHANGED)
+ {
+ eventReceived = true;
+ }
+ }
+
+ };
+ ServiceRegistration<ConfigurationListener> sr = bundleContext.registerService( ConfigurationListener.class, listener, null );
+ config.setBundleLocation( REGION );
+ delay();
+
+ if ( eventReceived )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c2.getState() );
+ }
+
+ sr.unregister();
+
+
+ }
+
+ @Test
+ public void testRegionBinding() throws Exception
+ {
+ try
+ {
+ new ConfigurationPermission(REGION, ConfigurationPermission.TARGET);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return;//not an R5 CA
+ }
+
+ final String pid = COMPONENT_NAME;
+ final Component component = findComponentByName( pid );
+
+ deleteConfig( pid );
+ delay();
+
+ 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 );
+
+ Configuration config = configure( pid, REGION );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+
+ Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+ b2.start();
+ Component[] components = findComponentsByName( pid );
+ TestCase.assertEquals( 2, components.length );
+ Component c2 = components[0] == component? components[1]: components[0];
+
+ c2.enable();
+ delay();
+ TestCase.assertEquals( Component.STATE_ACTIVE, c2.getState() );
+ }
+
+}
diff --git a/scr/src/test/resources/integration_test_simple_components_location.xml b/scr/src/test/resources/integration_test_simple_components_location.xml
new file mode 100644
index 0000000..746497d
--- /dev/null
+++ b/scr/src/test/resources/integration_test_simple_components_location.xml
@@ -0,0 +1,30 @@
+<?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">
+
+ <!-- component requires configuration -->
+ <scr:component name="SimpleComponent.configuration.require"
+ enabled="false"
+ configuration-policy="require" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <property name="service.pid" value="SimpleComponent.configuration.require" />
+ </scr:component>
+
+</components>