felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fmesc...@apache.org
Subject svn commit: r1067145 - in /felix/trunk/scr: ./ src/main/java/org/apache/felix/scr/impl/ src/main/java/org/apache/felix/scr/impl/config/ src/test/java/org/apache/felix/scr/impl/config/ src/test/java/org/apache/felix/scr/integration/
Date Fri, 04 Feb 2011 10:50:18 GMT
Author: fmeschbe
Date: Fri Feb  4 10:50:18 2011
New Revision: 1067145

URL: http://svn.apache.org/viewvc?rev=1067145&view=rev
Log:
FELIX-2578 Refactor SCR configuration setup to support late wiring of Configuration Admin API
Refactored configuration admin support into a support class and
unified component handling again. If Configuration Admin is there
the support class provides configuration, otherwise the support
class is not instantiated and components are not provided with
additional configuration.

Added:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java   (with props)
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java   (contents, props changed)
      - copied, changed from r1067144, felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java   (with props)
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java   (contents, props changed)
      - copied, changed from r1067144, felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java   (with props)
Removed:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java
Modified:
    felix/trunk/scr/pom.xml
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java
    felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
    felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java

Modified: felix/trunk/scr/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/scr/pom.xml?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/pom.xml (original)
+++ felix/trunk/scr/pom.xml Fri Feb  4 10:50:18 2011
@@ -219,18 +219,6 @@
                             org.osgi.service.packageadmin;version="[1.2,2)";resolution:=optional,
                             
                             <!--
-                                Configuration Admin version 1.2 (from R4.0) is enough
-                                (FELIX-2578: API is currently required)  
-                            -->
-                            org.osgi.service.cm;version="[1.2,2)",
-                            
-                            <!--
-                                Metatype is optional and if it is
-                                present, version 1.1 (from R4.1) is enough  
-                            -->
-                            org.osgi.service.metatype;version="[1.1,2)";resolution:=optional,
-
-                            <!--
                                 SCR API is required (we also export it) and must
                                 be of any 1.1 version, because we implement that
                                 exact version. This import is only used if the
@@ -239,6 +227,18 @@
                             -->
                             org.osgi.service.component;version="[1.1,1.2)"
                         </Import-Package>
+                        <DynamicImport-Package>
+                            <!--
+                                Configuration Admin version 1.2 (from R4.0) is enough
+                            -->
+                            org.osgi.service.cm;version="[1.2,2)",
+                            
+                            <!--
+                                Metatype is optional and if it is
+                                present, version 1.1 (from R4.1) is enough  
+                            -->
+                            org.osgi.service.metatype;version="[1.1,2)"
+                        </DynamicImport-Package>
                         <Embed-Dependency>
                             kxml2
                         </Embed-Dependency>

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/Activator.java?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/Activator.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/Activator.java Fri Feb  4 10:50:18 2011
@@ -23,7 +23,6 @@ import java.io.PrintStream;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.felix.scr.impl.config.ConfigurationComponentRegistry;
 import org.apache.felix.scr.impl.config.ScrConfiguration;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -94,7 +93,7 @@ public class Activator implements Bundle
 
         // prepare component registry
         m_componentBundles = new HashMap();
-        m_componentRegistry = createComponentRegistry( context);
+        m_componentRegistry = new ComponentRegistry( context );
 
         // get the configuration
         m_configuration = new ScrConfiguration( context );
@@ -368,22 +367,6 @@ public class Activator implements Bundle
     }
 
 
-    public static ComponentRegistry createComponentRegistry( BundleContext bundleContext )
-    {
-        try
-        {
-            return new ConfigurationComponentRegistry( bundleContext );
-        }
-        catch ( Throwable t )
-        {
-            log( LogService.LOG_INFO, bundleContext.getBundle(),
-                "ConfigurationAdmin supporting ComponentRegistry not available, not using ConfigurationAdmin", t );
-        }
-
-        return new ComponentRegistry( bundleContext );
-    }
-
-
     /**
      * Method to actually emit the log message. If the LogService is available,
      * the message will be logged through the LogService. Otherwise the message

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java Fri Feb  4 10:50:18 2011
@@ -28,13 +28,18 @@ import java.util.Map;
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.ScrService;
 import org.apache.felix.scr.impl.config.ComponentHolder;
-import org.apache.felix.scr.impl.config.UnconfiguredComponentHolder;
+import org.apache.felix.scr.impl.config.ConfigurationSupport;
+import org.apache.felix.scr.impl.config.ImmediateComponentHolder;
 import org.apache.felix.scr.impl.manager.AbstractComponentManager;
 import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentException;
 
@@ -45,9 +50,15 @@ import org.osgi.service.component.Compon
  * registers itself as the {@link ScrService} to support access to the
  * registered components.
  */
-public class ComponentRegistry implements ScrService
+public class ComponentRegistry implements ScrService, ServiceListener
 {
 
+    // the name of the ConfigurationAdmin service
+    public static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
+
+    // the bundle context
+    private BundleContext m_bundleContext;
+
     /**
      * The map of known components indexed by component name. The values are
      * either the component names (for name reservations) or implementations
@@ -88,13 +99,27 @@ public class ComponentRegistry implement
      */
     private ServiceRegistration m_registration;
 
+    // ConfigurationAdmin support -- created on demand upon availability of
+    // the ConfigurationAdmin service
+    private ConfigurationSupport configurationSupport;
 
     protected ComponentRegistry( BundleContext context )
     {
+        m_bundleContext = context;
         m_componentHoldersByName = new HashMap();
         m_componentsById = new HashMap();
         m_componentCounter = -1;
 
+        // keep me informed on ConfigurationAdmin state changes
+        try
+        {
+            context.addServiceListener( this, "(objectclass=" + CONFIGURATION_ADMIN + ")" );
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            // not expected (filter is tested valid)
+        }
+
         // register as ScrService
         Dictionary props = new Hashtable();
         props.put( Constants.SERVICE_DESCRIPTION, "Declarative Services Management Agent" );
@@ -106,6 +131,14 @@ public class ComponentRegistry implement
 
     public void dispose()
     {
+        m_bundleContext.removeServiceListener(this);
+
+        if (configurationSupport != null)
+        {
+            configurationSupport.dispose();
+            configurationSupport = null;
+        }
+
         if ( m_registration != null )
         {
             m_registration.unregister();
@@ -378,18 +411,69 @@ public class ComponentRegistry implement
      */
     public ComponentHolder createComponentHolder( BundleComponentActivator activator, ComponentMetadata metadata )
     {
-        if ( metadata.isFactory() )
+        ComponentHolder holder;
+
+        if (metadata.isFactory())
         {
             // 112.2.4 SCR must register a Component Factory
             // service on behalf ot the component
             // as soon as the component factory is satisfied
-            return new ComponentFactoryImpl( activator, metadata );
+            holder = new ComponentFactoryImpl(activator, metadata);
+        }
+        else
+        {
+            holder = new ImmediateComponentHolder(activator, metadata);
         }
 
-        return new UnconfiguredComponentHolder( activator, metadata );
+        if (configurationSupport != null)
+        {
+            configurationSupport.configureComponentHolder(holder);
+        }
+
+        return holder;
     }
 
 
+    //---------- ServiceListener
+
+    /**
+     * Called if the Configuration Admin service changes state. This
+     * implementation is mainly interested in the Configuration Admin service
+     * being registered <i>after</i> the Declarative Services setup to be able
+     * to forward existing configuration.
+     *
+     * @param event The service change event
+     */
+    public void serviceChanged(ServiceEvent event)
+    {
+        if (event.getType() == ServiceEvent.REGISTERED)
+        {
+            this.configurationSupport = new ConfigurationSupport(this.m_bundleContext, this);
+
+            final ServiceReference caRef = event.getServiceReference();
+            final Object service = m_bundleContext.getService(caRef);
+            if (service != null)
+            {
+                try
+                {
+                    this.configurationSupport.configureComponentHolders(caRef, service);
+                }
+                finally
+                {
+                    m_bundleContext.ungetService(caRef);
+                }
+            }
+        }
+        else if (event.getType() == ServiceEvent.UNREGISTERING)
+        {
+            if (configurationSupport != null)
+            {
+                this.configurationSupport.dispose();
+                this.configurationSupport = null;
+            }
+        }
+    }
+
     //---------- Helper method
 
     /**

Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java?rev=1067145&view=auto
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java (added)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java Fri Feb  4 10:50:18 2011
@@ -0,0 +1,301 @@
+/*
+ * 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.config;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.ComponentRegistry;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.log.LogService;
+
+public class ConfigurationSupport implements ConfigurationListener
+{
+
+    final ComponentRegistry m_registry;
+
+    // the service m_registration of the ConfigurationListener service
+    private ServiceRegistration m_registration;
+
+    public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry)
+    {
+        this.m_registry = registry;
+
+        // register as listener for configurations
+        Dictionary props = new Hashtable();
+        props.put(Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        this.m_registration = bundleContext.registerService(new String[]
+            { "org.osgi.service.cm.ConfigurationListener" }, this, props);
+    }
+
+    public void dispose()
+    {
+        if (this.m_registration != null)
+        {
+            this.m_registration.unregister();
+            this.m_registration = null;
+        }
+    }
+
+    // ---------- BaseConfigurationSupport overwrites
+
+    public void configureComponentHolder(final ComponentHolder holder)
+    {
+
+        // 112.7 configure unless configuration not required
+        if (!holder.getComponentMetadata().isConfigurationIgnored())
+        {
+            final BundleContext bundleContext = holder.getActivator().getBundleContext();
+            final String bundleLocation = bundleContext.getBundle().getLocation();
+            final String name = holder.getComponentMetadata().getName();
+
+            final ServiceReference caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+            if (caRef != null)
+            {
+                final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef);
+                if (ca != null)
+                {
+                    try
+                    {
+                        final Configuration[] factory = findFactoryConfigurations(ca, name);
+                        if (factory != null)
+                        {
+                            for (int i = 0; i < factory.length; i++)
+                            {
+                                final String pid = factory[i].getPid();
+                                final Dictionary props = getConfiguration(ca, pid, bundleLocation);
+                                holder.configurationUpdated(pid, props);
+                            }
+                        }
+                        else
+                        {
+                            // check for configuration and configure the holder
+                            final Configuration singleton = findSingletonConfiguration(ca, name);
+                            if (singleton != null)
+                            {
+                                final Dictionary props = getConfiguration(ca, name, bundleLocation);
+                                holder.configurationUpdated(name, props);
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        bundleContext.ungetService(caRef);
+                    }
+                }
+            }
+        }
+    }
+
+    // ---------- ServiceListener
+
+    public void configureComponentHolders(final ServiceReference configurationAdminReference,
+        final Object configurationAdmin)
+    {
+        if (configurationAdmin instanceof ConfigurationAdmin)
+        {
+            Configuration[] configs = findConfigurations((ConfigurationAdmin) configurationAdmin, null);
+            if (configs != null)
+            {
+                for (int i = 0; i < configs.length; i++)
+                {
+                    ConfigurationEvent cfgEvent = new ConfigurationEvent(configurationAdminReference,
+                        ConfigurationEvent.CM_UPDATED, configs[i].getFactoryPid(), configs[i].getPid());
+                    configurationEvent(cfgEvent);
+                }
+            }
+        }
+    }
+
+    // ---------- ConfigurationListener
+
+    /**
+     * Called by the Configuration Admin service if a configuration is updated
+     * or removed.
+     * <p>
+     * This method is really only called upon configuration changes; it is not
+     * called for existing configurations upon startup of the Configuration
+     * Admin service. To bridge this gap, the
+     * {@link #serviceChanged(ServiceEvent)} method called when the
+     * Configuration Admin service is registered calls this method for all
+     * existing configurations to be able to foward existing configurations to
+     * components.
+     *
+     * @param event The configuration change event
+     */
+    public void configurationEvent(ConfigurationEvent event)
+    {
+        final String pid = event.getPid();
+        final String factoryPid = event.getFactoryPid();
+
+        final ComponentHolder cm;
+        if (factoryPid == null)
+        {
+            cm = this.m_registry.getComponentHolder(pid);
+        }
+        else
+        {
+            cm = this.m_registry.getComponentHolder(factoryPid);
+        }
+
+        Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling "
+            + ((event.getType() == ConfigurationEvent.CM_DELETED) ? "DELETE" : "UPDATE") + " of Configuration PID="
+            + pid, null);
+
+        if (cm != null && !cm.getComponentMetadata().isConfigurationIgnored())
+        {
+            switch (event.getType())
+            {
+                case ConfigurationEvent.CM_DELETED:
+                    cm.configurationDeleted(pid);
+                    break;
+
+                case ConfigurationEvent.CM_UPDATED:
+                    final BundleComponentActivator activator = cm.getActivator();
+                    if (activator == null)
+                    {
+                        break;
+                    }
+
+                    final BundleContext bundleContext = activator.getBundleContext();
+                    if (bundleContext == null)
+                    {
+                        break;
+                    }
+
+                    final ServiceReference caRef = bundleContext
+                        .getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+                    if (caRef != null)
+                    {
+                        try
+                        {
+                            final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef);
+                            if (ca != null)
+                            {
+                                try
+                                {
+                                    final Dictionary dict = getConfiguration(ca, pid, bundleContext.getBundle()
+                                        .getLocation());
+                                    if (dict != null)
+                                    {
+                                        cm.configurationUpdated(pid, dict);
+                                    }
+                                }
+                                finally
+                                {
+                                    bundleContext.ungetService(caRef);
+                                }
+                            }
+                        }
+                        catch (IllegalStateException ise)
+                        {
+                            // If the bundle has been stopped conurrently
+                        }
+                    }
+                    break;
+
+                default:
+                    Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(),
+                        null);
+            }
+        }
+    }
+
+    private Dictionary getConfiguration(final ConfigurationAdmin ca, final String pid, final String bundleLocation)
+    {
+        try
+        {
+            final Configuration cfg = ca.getConfiguration(pid);
+            if (bundleLocation.equals(cfg.getBundleLocation()) || Activator.hasCtWorkaround())
+            {
+                return cfg.getProperties();
+            }
+
+            // configuration belongs to another bundle, cannot be used here
+            Activator.log(LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle "
+                + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null);
+        }
+        catch (IOException ioe)
+        {
+            Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the configuration whose PID equals the given pid. If no such
+     * configuration exists, <code>null</code> is returned.
+     *
+     * @param ctx
+     * @param pid
+     * @return
+     */
+    public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid)
+    {
+        final String filter = "(service.pid=" + pid + ")";
+        final Configuration[] cfg = findConfigurations(ca, filter);
+        return (cfg == null || cfg.length == 0) ? null : cfg[0];
+    }
+
+    /**
+     * Returns all configurations whose factory PID equals the given factory PID
+     * or <code>null</code> if no such configurations exist
+     *
+     * @param ctx
+     * @param factoryPid
+     * @return
+     */
+    public Configuration[] findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid)
+    {
+        final String filter = "(service.factoryPid=" + factoryPid + ")";
+        return findConfigurations(ca, filter);
+    }
+
+    private Configuration[] findConfigurations(final ConfigurationAdmin ca, final String filter)
+    {
+        try
+        {
+            return ca.listConfigurations(filter);
+        }
+        catch (IOException ioe)
+        {
+            Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe);
+        }
+        catch (InvalidSyntaxException ise)
+        {
+            Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise);
+        }
+
+        // no factories in case of problems
+        return null;
+    }
+}

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Copied: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java (from r1067144, felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java)
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java?p2=felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java&p1=felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java&r1=1067144&r2=1067145&rev=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java Fri Feb  4 10:50:18 2011
@@ -26,7 +26,9 @@ import java.util.Map;
 
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.DelayedComponentManager;
 import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.osgi.service.component.ComponentConstants;
 
@@ -52,10 +54,20 @@ import org.osgi.service.component.Compon
  * <code>service.factoryPid</code> equals the component name.</li>
  * </ul>
  */
-public class ConfiguredComponentHolder extends AbstractComponentHolder
+public class ImmediateComponentHolder implements ComponentHolder
 {
 
     /**
+     * The activator owning the per-bundle components
+     */
+    private final BundleComponentActivator m_activator;
+
+    /**
+     * The {@link ComponentMetadata} describing the held component(s)
+     */
+    private final ComponentMetadata m_componentMetadata;
+
+    /**
      * A map of components configured with factory configuration. The indices
      * are the PIDs (<code>service.pid</code>) of the configuration objects.
      * The values are the {@link ImmediateComponentManager component instances}
@@ -91,15 +103,60 @@ public class ConfiguredComponentHolder e
     private boolean m_enabled;
 
 
-    ConfiguredComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+    public ImmediateComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
     {
-        super( activator, metadata );
-
+        this.m_activator = activator;
+        this.m_componentMetadata = metadata;
         this.m_components = new HashMap();
         this.m_singleComponent = createComponentManager();
         this.m_enabled = false;
     }
 
+    protected ImmediateComponentManager createComponentManager()
+    {
+
+        ImmediateComponentManager manager;
+        if ( m_componentMetadata.isFactory() )
+        {
+            throw new IllegalArgumentException( "Cannot create component factory for " + m_componentMetadata.getName() );
+        }
+        else if ( m_componentMetadata.isImmediate() )
+        {
+            manager = new ImmediateComponentManager( m_activator, this, m_componentMetadata );
+        }
+        else if ( m_componentMetadata.getServiceMetadata() != null )
+        {
+            if ( m_componentMetadata.getServiceMetadata().isServiceFactory() )
+            {
+                manager = new ServiceFactoryComponentManager( m_activator, this, m_componentMetadata );
+            }
+            else
+            {
+                manager = new DelayedComponentManager( m_activator, this, m_componentMetadata );
+            }
+        }
+        else
+        {
+            // if we get here, which is not expected after all, we fail
+            throw new IllegalArgumentException( "Cannot create a component manager for "
+                + m_componentMetadata.getName() );
+        }
+
+        return manager;
+    }
+
+
+    public final BundleComponentActivator getActivator()
+    {
+        return m_activator;
+    }
+
+
+    public final ComponentMetadata getComponentMetadata()
+    {
+        return m_componentMetadata;
+    }
+
 
     /**
      * The configuration with the given <code>pid</code>
@@ -128,7 +185,7 @@ public class ConfiguredComponentHolder e
             return;
         }
 
-        if ( pid.equals( getComponentName() ) )
+        if ( pid.equals( getComponentMetadata().getName() ) )
         {
             // singleton configuration deleted
             m_singleComponent.reconfigure( null );
@@ -195,7 +252,7 @@ public class ConfiguredComponentHolder e
             return;
         }
 
-        if ( pid.equals( getComponentName() ) )
+        if ( pid.equals( getComponentMetadata().getName() ) )
         {
             // singleton configuration has pid equal to component name
             m_singleComponent.reconfigure( props );

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java Fri Feb  4 10:50:18 2011
@@ -25,10 +25,7 @@ import java.util.Hashtable;
 import org.apache.felix.scr.impl.Activator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
-import org.osgi.service.metatype.MetaTypeProvider;
 
 
 /**
@@ -68,8 +65,6 @@ public class ScrConfiguration
 
     private boolean factoryEnabled;
 
-    private boolean ctWorkaround;
-
     static final String PID = "org.apache.felix.scr.ScrService";
 
     public ScrConfiguration( BundleContext bundleContext )
@@ -80,35 +75,12 @@ public class ScrConfiguration
         configure( null );
 
         // listen for Configuration Admin configuration
-        try
-        {
-            Object service = new ManagedService()
-            {
-                public void updated( Dictionary properties ) throws ConfigurationException
-                {
-                    configure( properties );
-                }
-            };
-            // add meta type provider if interfaces are available
-            Object enhancedService = tryToCreateMetaTypeProvider(service);
-            final String[] interfaceNames;
-            if ( enhancedService == null )
-            {
-                interfaceNames = new String[] {ManagedService.class.getName()};
-            }
-            else
-            {
-                interfaceNames = new String[] {ManagedService.class.getName(), MetaTypeProvider.class.getName()};
-                service = enhancedService;
-            }
-            Dictionary props = new Hashtable();
-            props.put( Constants.SERVICE_PID, PID );
-            bundleContext.registerService( interfaceNames, service, props );
-        }
-        catch ( Throwable t )
-        {
-            // don't care
-        }
+        Dictionary props = new Hashtable();
+        props.put(Constants.SERVICE_PID, PID);
+        props.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        bundleContext.registerService("org.osgi.service.cm.ManagedService", new ScrManagedServiceServiceFactory(this),
+            props);
     }
 
     void configure( Dictionary config )
@@ -223,19 +195,4 @@ public class ScrConfiguration
         // default log level (errors only)
         return LogService.LOG_ERROR;
     }
-
-
-    private Object tryToCreateMetaTypeProvider( final Object managedService )
-    {
-        try
-        {
-            return new MetaTypeProviderImpl( getDefaultLogLevel(), getDefaultFactoryEnabled(),
-                ( ManagedService ) managedService );
-        }
-        catch ( Throwable t )
-        {
-            // we simply ignore this
-        }
-        return null;
-    }
 }

Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java?rev=1067145&view=auto
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java (added)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java Fri Feb  4 10:50:18 2011
@@ -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.config;
+
+import java.util.Dictionary;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * The <code>ScrManagedService</code> receives configuration for the Declarative
+ * Services Runtime itself. This class is instantiated in a ServiceFactory
+ * manner by the {@link ScrManagedServiceServiceFactory} when the Configuration
+ * Admin service implementation and API is available.
+ */
+public class ScrManagedService implements ManagedService
+{
+
+    private final ScrConfiguration scrConfiguration;
+
+    protected final ScrConfiguration getScrConfiguration()
+    {
+        return scrConfiguration;
+    }
+
+    public ScrManagedService(final ScrConfiguration scrConfiguration)
+    {
+        this.scrConfiguration = scrConfiguration;
+    }
+
+    public void updated(Dictionary properties) throws ConfigurationException
+    {
+        this.scrConfiguration.configure(properties);
+    }
+}

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Copied: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java (from r1067144, felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java)
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java?p2=felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java&p1=felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java&r1=1067144&r2=1067145&rev=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java Fri Feb  4 10:50:18 2011
@@ -20,38 +20,29 @@ package org.apache.felix.scr.impl.config
 
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Dictionary;
 
-import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
 import org.osgi.service.metatype.AttributeDefinition;
 import org.osgi.service.metatype.MetaTypeProvider;
 import org.osgi.service.metatype.ObjectClassDefinition;
 
-public class MetaTypeProviderImpl
-    implements MetaTypeProvider, ManagedService
+/**
+ * The <code>ScrManagedServiceMetaTypeProvider</code> receives the Declarative
+ * Services Runtime configuration (by extending the {@link ScrManagedService}
+ * class but also provides a MetaType Service ObjectClassDefinition.
+ */
+class ScrManagedServiceMetaTypeProvider extends ScrManagedService
+    implements MetaTypeProvider
 {
 
-    private final int logLevel;
-
-    private final boolean factoryEnabled;
-
-    private final ManagedService delegatee;
-
-    public MetaTypeProviderImpl(final int logLevel,
-                                final boolean factoryEnabled,
-                                final ManagedService delegatee)
+    static ManagedService create(final ScrConfiguration scrConfiguration)
     {
-        this.logLevel = logLevel;
-        this.factoryEnabled = factoryEnabled;
-        this.delegatee = delegatee;
+        return new ScrManagedServiceMetaTypeProvider(scrConfiguration);
     }
 
-    private ObjectClassDefinition ocd;
-
-    public void updated(Dictionary properties) throws ConfigurationException
+    private ScrManagedServiceMetaTypeProvider(final ScrConfiguration scrConfiguration)
     {
-        this.delegatee.updated(properties);
+        super(scrConfiguration);
     }
 
     /**
@@ -72,68 +63,61 @@ public class MetaTypeProviderImpl
             return null;
         }
 
-        if ( ocd == null )
-        {
-            final ArrayList adList = new ArrayList();
-
-            adList.add( new AttributeDefinitionImpl( ScrConfiguration.PROP_LOGLEVEL, "SCR Log Level",
-                    "Allows limiting the amount of logging information sent to the OSGi LogService." +
-                    " Supported values are DEBUG, INFO, WARN, and ERROR. Default is ERROR.",
-                    AttributeDefinition.INTEGER,
-                    new String[] {String.valueOf(this.logLevel)}, 0,
-                    new String[] {"Debug", "Information", "Warnings", "Error"},
-                    new String[] {"4", "3", "2", "1"} ) );
-
-            adList.add( new AttributeDefinitionImpl( ScrConfiguration.PROP_FACTORY_ENABLED, "Extended Factory Components",
-                "Whether or not to enable the support for creating Factory Component instances based on factory configuration." +
-                " This is an Apache Felix SCR specific extension, explicitly not supported by the Declarative Services " +
-                "specification. Reliance on this feature prevent the component from being used with other Declarative " +
-                "Services implementations. The default value is false to disable this feature.",
-                this.factoryEnabled ) );
-
-            ocd = new ObjectClassDefinition()
-            {
-
-                private final AttributeDefinition[] attrs = ( AttributeDefinition[] ) adList
-                    .toArray( new AttributeDefinition[adList.size()] );
-
+        final ArrayList adList = new ArrayList();
 
-                public String getName()
-                {
-                    return "Apache Felix Declarative Service Implementation";
-                }
-
-
-                public InputStream getIcon( int arg0 )
-                {
-                    return null;
-                }
+        adList.add(new AttributeDefinitionImpl(ScrConfiguration.PROP_LOGLEVEL, "SCR Log Level",
+            "Allows limiting the amount of logging information sent to the OSGi LogService."
+                + " Supported values are DEBUG, INFO, WARN, and ERROR. Default is ERROR.", AttributeDefinition.INTEGER,
+            new String[]
+                { String.valueOf(this.getScrConfiguration().getLogLevel()) }, 0, new String[]
+                { "Debug", "Information", "Warnings", "Error" }, new String[]
+                { "4", "3", "2", "1" }));
+
+        adList
+            .add(new AttributeDefinitionImpl(
+                ScrConfiguration.PROP_FACTORY_ENABLED,
+                "Extended Factory Components",
+                "Whether or not to enable the support for creating Factory Component instances based on factory configuration."
+                    + " This is an Apache Felix SCR specific extension, explicitly not supported by the Declarative Services "
+                    + "specification. Reliance on this feature prevent the component from being used with other Declarative "
+                    + "Services implementations. The default value is false to disable this feature.", this
+                    .getScrConfiguration().isFactoryEnabled()));
 
+        return new ObjectClassDefinition()
+        {
 
-                public String getID()
-                {
-                    return ScrConfiguration.PID;
-                }
+            private final AttributeDefinition[] attrs = (AttributeDefinition[]) adList
+                .toArray(new AttributeDefinition[adList.size()]);
 
+            public String getName()
+            {
+                return "Apache Felix Declarative Service Implementation";
+            }
 
-                public String getDescription()
-                {
-                    return "Configuration for the Apache Felix Declarative Services Implementation." +
-                           " This configuration overwrites configuration defined in framework properties of the same names.";
-                }
+            public InputStream getIcon(int arg0)
+            {
+                return null;
+            }
 
+            public String getID()
+            {
+                return ScrConfiguration.PID;
+            }
 
-                public AttributeDefinition[] getAttributeDefinitions( int filter )
-                {
-                    return ( filter == OPTIONAL ) ? null : attrs;
-                }
-            };
-        }
+            public String getDescription()
+            {
+                return "Configuration for the Apache Felix Declarative Services Implementation."
+                    + " This configuration overwrites configuration defined in framework properties of the same names.";
+            }
 
-        return ocd;
+            public AttributeDefinition[] getAttributeDefinitions(int filter)
+            {
+                return (filter == OPTIONAL) ? null : attrs;
+            }
+        };
     }
 
-    class AttributeDefinitionImpl implements AttributeDefinition
+    private static class AttributeDefinitionImpl implements AttributeDefinition
     {
 
         private final String id;

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java?rev=1067145&view=auto
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java (added)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java Fri Feb  4 10:50:18 2011
@@ -0,0 +1,67 @@
+/*
+ * 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.config;
+
+import org.apache.felix.scr.impl.Activator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+
+/**
+ * The <code>ScrManagedServiceServiceFactory</code> is the ServiceFactory
+ * registered on behalf of the {@link ScrManagedService} (or
+ * {@link ScrManagedServiceMetaTypeProvider}, resp.) to create the instance on
+ * demand once it is used by the Configuration Admin Service or the MetaType
+ * Service.
+ * <p>
+ * In contrast to the {@link ScrManagedService} and
+ * {@link ScrManagedServiceMetaTypeProvider} classes, this class only requires
+ * core OSGi API and thus may be instantiated without the Configuration Admin
+ * and/or MetaType Service API actually available at the time of instantiation.
+ */
+public class ScrManagedServiceServiceFactory implements ServiceFactory
+{
+    private final ScrConfiguration scrConfiguration;
+
+    public ScrManagedServiceServiceFactory(final ScrConfiguration scrConfiguration)
+    {
+        this.scrConfiguration = scrConfiguration;
+    }
+
+    public Object getService(Bundle bundle, ServiceRegistration registration)
+    {
+        try
+        {
+            return ScrManagedServiceMetaTypeProvider.create(this.scrConfiguration);
+        }
+        catch (Throwable t)
+        {
+            // assume MetaType Service API not available
+            Activator.log(LogService.LOG_ERROR, null, "Cannot create MetaType providing ManagedService", t);
+        }
+        return new ScrManagedService(this.scrConfiguration);
+    }
+
+    public void ungetService(Bundle bundle, ServiceRegistration registration, Object service)
+    {
+        // nothing really todo; GC will do the rest
+    }
+
+}

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java (original)
+++ felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java Fri Feb  4 10:50:18 2011
@@ -178,11 +178,11 @@ public class ConfiguredComponentHolderTe
     }
 
 
-    private static ImmediateComponentManager getSingleManager( ConfiguredComponentHolder holder )
+    private static ImmediateComponentManager getSingleManager( ImmediateComponentHolder holder )
     {
         try
         {
-            final Field f = ConfiguredComponentHolder.class.getDeclaredField( "m_singleComponent" );
+            final Field f = ImmediateComponentHolder.class.getDeclaredField( "m_singleComponent" );
             f.setAccessible( true );
             return ( ImmediateComponentManager ) f.get( holder );
         }
@@ -194,11 +194,11 @@ public class ConfiguredComponentHolderTe
     }
 
 
-    private static ImmediateComponentManager[] getComponentManagers( ConfiguredComponentHolder holder )
+    private static ImmediateComponentManager[] getComponentManagers( ImmediateComponentHolder holder )
     {
         try
         {
-            final Method m = ConfiguredComponentHolder.class.getDeclaredMethod( "getComponentManagers", new Class[]
+            final Method m = ImmediateComponentHolder.class.getDeclaredMethod( "getComponentManagers", new Class[]
                 { Boolean.TYPE } );
             m.setAccessible( true );
             return ( ImmediateComponentManager[] ) m.invoke( holder, new Object[]
@@ -211,7 +211,7 @@ public class ConfiguredComponentHolderTe
         }
     }
 
-    private static class TestingConfiguredComponentHolder extends ConfiguredComponentHolder
+    private static class TestingConfiguredComponentHolder extends ImmediateComponentHolder
     {
         TestingConfiguredComponentHolder( ComponentMetadata metadata )
         {

Modified: felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java?rev=1067145&r1=1067144&r2=1067145&view=diff
==============================================================================
--- felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java (original)
+++ felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java Fri Feb  4 10:50:18 2011
@@ -44,6 +44,7 @@ import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.OptionUtils;
 import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
 import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.options.MavenArtifactUrlReference;
 import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -120,9 +121,9 @@ public abstract class ComponentTestBase
     @Before
     public void setUp() throws BundleException
     {
-        scrTracker = new ServiceTracker( bundleContext, ScrService.class.getName(), null );
+        scrTracker = new ServiceTracker( bundleContext, "org.apache.felix.scr.ScrService", null );
         scrTracker.open();
-        configAdminTracker = new ServiceTracker( bundleContext, ConfigurationAdmin.class.getName(), null );
+        configAdminTracker = new ServiceTracker( bundleContext, "org.osgi.service.cm.ConfigurationAdmin", null );
         configAdminTracker.open();
 
         bundle = installBundle( descriptorFile );



Mime
View raw message