You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2015/07/09 00:10:16 UTC
svn commit: r1689973 [11/25] - in
/felix/sandbox/pderop/dependencymanager.ds: cnf/ext/ cnf/localrepo/
cnf/localrepo/org.apache.felix.framework/ cnf/releaserepo/
org.apache.felix.dependencymanager.ds.itest/
org.apache.felix.dependencymanager.ds.itest/.s...
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,168 @@
+/*
+ * 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;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.apache.felix.shell.Command;
+
+/**
+ * The <code>ScrShellCommand</code> implements command shell access for the
+ * legacy Apache Felix Shell. The actual implementation of the commands is
+ * found in the {@link ScrCommand} class.
+ */
+class ScrShellCommand implements Command
+{
+
+ private static final String HELP_CMD = "help";
+ private static final String LIST_CMD = "list";
+ private static final String INFO_CMD = "info";
+ private static final String ENABLE_CMD = "enable";
+ private static final String DISABLE_CMD = "disable";
+ private static final String CONFIG_CMD = "config";
+
+ private final ScrCommand scrCommand;
+
+ ScrShellCommand(final ScrCommand scrCommand)
+ {
+ this.scrCommand = scrCommand;
+ }
+
+ public String getName()
+ {
+ return "scr";
+ }
+
+ public String getUsage()
+ {
+ return "scr help";
+ }
+
+ public String getShortDescription()
+ {
+ return "Declarative Services Runtime";
+ }
+
+ public void execute(String commandLine, PrintStream out, PrintStream err)
+ {
+ // Parse the commandLine to get the OBR command.
+ String[] st = commandLine.split("\\s+");
+ // Ignore the invoking command.
+ // Try to get the OBR command, default is HELP command.
+ String command = st.length > 1? st[1]: HELP_CMD;
+ String arg = (st.length > 2) ? st[2] : null;
+
+ // Perform the specified command.
+ if (command.equals(HELP_CMD))
+ {
+ help(out, arg);
+ }
+ else
+ {
+ PrintWriter pw = new PrintWriter(out);
+ try
+ {
+ if (command.equals(LIST_CMD))
+ {
+ scrCommand.list(arg, pw);
+ }
+ else if (command.equals(INFO_CMD))
+ {
+ scrCommand.info(arg, pw);
+ }
+ else if (command.equals(ENABLE_CMD))
+ {
+ scrCommand.change(arg, pw, true);
+ }
+ else if (command.equals(DISABLE_CMD))
+ {
+ scrCommand.change(arg, pw, false);
+ }
+ else if (command.equals(CONFIG_CMD))
+ {
+ scrCommand.config(pw);
+ }
+ else
+ {
+ err.println("Unknown command: " + command);
+ }
+ }
+ catch ( IllegalArgumentException e )
+ {
+ System.err.println(e.getMessage());
+ }
+ }
+ }
+
+ private void help(PrintStream out, String command)
+ {
+ if (LIST_CMD.equals( command ))
+ {
+ out.println("");
+ out.println("scr " + LIST_CMD + " [ <bundleId> ]");
+ out.println("");
+ out.println("This command lists registered components. If a bundle ID is\n"
+ + "added, only the components of the selected bundles are listed.");
+ out.println("");
+ }
+ else if (INFO_CMD.equals( command ))
+ {
+ out.println("");
+ out.println("scr " + INFO_CMD + " <componentId>");
+ out.println("");
+ out.println("This command dumps information of the component whose\n"
+ + "component ID is given as command argument.");
+ out.println("");
+ }
+ else if (ENABLE_CMD.equals( command ))
+ {
+ out.println("");
+ out.println("scr " + ENABLE_CMD + " <componentId>");
+ out.println("");
+ out.println("This command enables the component whose component ID\n" + "is given as command argument.");
+ out.println("");
+ }
+ else if (DISABLE_CMD.equals( command ))
+ {
+ out.println("");
+ out.println("scr " + DISABLE_CMD + " <componentId>");
+ out.println("");
+ out.println("This command disables the component whose component ID\n" + "is given as command argument.");
+ out.println("");
+ }
+ else if (CONFIG_CMD.equals( command ))
+ {
+ out.println("");
+ out.println("scr " + CONFIG_CMD);
+ out.println("");
+ out.println("This command lists the current SCR configuration.");
+ out.println("");
+ }
+ else
+ {
+ out.println("scr " + HELP_CMD + " [" + LIST_CMD + "]");
+ out.println("scr " + LIST_CMD + " [ <bundleId> ]");
+ out.println("scr " + INFO_CMD + " <componentId>");
+ out.println("scr " + ENABLE_CMD + " <componentId>");
+ out.println("scr " + DISABLE_CMD + " <componentId>");
+ out.println("scr " + CONFIG_CMD);
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,263 @@
+/*
+ * 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;
+
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * Copied with modifications from felix configadmin.
+ *
+ * The <code>TargetedPID</code> class represents a targeted PID as read
+ * from a configuration object.
+ * <p>
+ * For a factory configuration the <code>TargetedPID</code> represents
+ * the factory PID of the configuration. Otherwise it represents the
+ * PID itself of the configuration.
+ */
+public class TargetedPID
+{
+
+ private final String rawPid;
+
+ private final String servicePid;
+
+ private final String symbolicName;
+ private final String version;
+ private final String location;
+
+ /**
+ * The level of binding of this targeted PID:
+ * <ul>
+ * <li><code>0</code> -- this PID is not targeted at all</li>
+ * <li><code>1</code> -- this PID is targeted by the symbolic name</li>
+ * <li><code>2</code> -- this PID is targeted by the symbolic name and version</li>
+ * <li><code>3</code> -- this PID is targeted by the symbolic name, version, and location</li>
+ * </ul>
+ */
+ private final short bindingLevel;
+
+
+ /**
+ * Returns the bundle's version as required for targeted PIDs: If the
+ * bundle has a version the string representation of the version
+ * string converted to a Version object is returned. Otherwise the
+ * string representation of <code>Version.emptyVersion</code> is
+ * returned.
+ * <p>
+ * To remain compatible with pre-R4.2 (Framework API < 1.5) we cannot
+ * use the <code>Bundle.getVersion()</code> method.
+ *
+ * @param bundle The bundle whose version is to be returned.
+ */
+ public static String getBundleVersion( final Bundle bundle )
+ {
+ Object vHeader = bundle.getHeaders().get( Constants.BUNDLE_VERSION );
+ Version version = ( vHeader == null ) ? Version.emptyVersion : new Version( vHeader.toString() );
+ return version.toString();
+ }
+
+
+ public TargetedPID( final String rawPid )
+ {
+ this.rawPid = rawPid;
+
+ if ( rawPid.indexOf( '|' ) < 0 )
+ {
+ this.servicePid = rawPid;
+ this.symbolicName = null;
+ this.version = null;
+ this.location = null;
+ this.bindingLevel = 0;
+ }
+ else
+ {
+ int start = 0;
+ int end = rawPid.indexOf( '|' );
+ this.servicePid = rawPid.substring( start, end );
+
+ start = end + 1;
+ end = rawPid.indexOf( '|', start );
+ if ( end >= 0 )
+ {
+ this.symbolicName = rawPid.substring( start, end );
+ start = end + 1;
+ end = rawPid.indexOf( '|', start );
+ if ( end >= 0 )
+ {
+ this.version = rawPid.substring( start, end );
+ this.location = rawPid.substring( end + 1 );
+ this.bindingLevel = 3;
+ }
+ else
+ {
+ this.version = rawPid.substring( start );
+ this.location = null;
+ this.bindingLevel = 2;
+ }
+ }
+ else
+ {
+ this.symbolicName = rawPid.substring( start );
+ this.version = null;
+ this.location = null;
+ this.bindingLevel = 1;
+ }
+ }
+ }
+
+
+ /**
+ * Returns true if the target of this PID (bundle symbolic name,
+ * version, and location) match the bundle registering the referenced
+ * service.
+ * <p>
+ * This method just checks the target not the PID value itself, so
+ * this method returning <code>true</code> does not indicate whether
+ * the service actually is registered with a service PID equal to the
+ * raw PID of this targeted PID.
+ * <p>
+ * This method also returns <code>false</code> if the service has
+ * concurrently been unregistered and the registering bundle is now
+ * <code>null</code>.
+ *
+ * @param reference <code>ServiceReference</code> to the registered
+ * service
+ * @return <code>true</code> if the referenced service matches the
+ * target of this PID.
+ */
+ public boolean matchesTarget( ComponentHolder<?> holder )
+ {
+ // already unregistered
+ final Bundle serviceBundle = holder.getActivator().getBundleContext().getBundle();
+ if ( serviceBundle == null )
+ {
+ return false;
+ }
+
+ // This is not really targeted
+ if ( this.symbolicName == null )
+ {
+ return true;
+ }
+
+ // bundle symbolic names don't match
+ if ( !this.symbolicName.equals( serviceBundle.getSymbolicName() ) )
+ {
+ return false;
+ }
+
+ // no more specific target
+ if ( this.version == null )
+ {
+ return true;
+ }
+
+ // bundle version does not match
+
+ if ( !this.version.equals( getBundleVersion( serviceBundle ) ) )
+ {
+ return false;
+ }
+
+ // assert bundle location match
+ return this.location == null || this.location.equals( serviceBundle.getLocation() );
+ }
+
+
+ /**
+ * Gets the raw PID with which this instance has been created.
+ * <p>
+ * If an actual service PID contains pipe symbols that PID might be
+ * considered being targeted PID without it actually being one. This
+ * method provides access to the raw PID to allow for such services to
+ * be configured.
+ */
+ public String getRawPid()
+ {
+ return rawPid;
+ }
+
+
+ /**
+ * Returns the service PID of this targeted PID which basically is
+ * the targeted PID without the targeting information.
+ */
+ public String getServicePid()
+ {
+ return servicePid;
+ }
+
+
+ /**
+ * Returns <code>true</code> if this targeted PID binds stronger than
+ * the <code>other</code> {@link TargetedPID}.
+ * <p>
+ * This method assumes both targeted PIDs have already been checked for
+ * suitability for the bundle encoded in the targetting.
+ *
+ * @param other The targeted PID to check whether it is binding stronger
+ * or not.
+ * @return <code>true</code> if the <code>other</code> targeted PID
+ * is binding strong.
+ */
+ public boolean bindsStronger( final TargetedPID other )
+ {
+ return other == null || this.bindingLevel > other.bindingLevel;
+ }
+
+
+ @Override
+ public int hashCode()
+ {
+ return this.rawPid.hashCode();
+ }
+
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null )
+ {
+ return false;
+ }
+ else if ( obj == this )
+ {
+ return true;
+ }
+
+ // assume equality if same class and raw PID equals
+ if ( this.getClass() == obj.getClass() )
+ {
+ return this.rawPid.equals( ( ( TargetedPID ) obj ).rawPid );
+ }
+
+ // not the same class or different raw PID
+ return false;
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return this.rawPid;
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,46 @@
+/*
+ * 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.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.SingleComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+
+public interface ComponentContainer<S>
+{
+
+ /**
+ * Returns the {@link BundleComponentActivator} owning this component
+ * holder. (overlaps ComponentHolder)
+ */
+ BundleComponentActivator getActivator();
+
+ /**
+ * Returns the {@link ComponentMetadata} describing and declaring this
+ * component. (overlaps ComponentHolder)
+ */
+ ComponentMetadata getComponentMetadata();
+
+ /**
+ * Informs the holder that the component has been disposed as a result of
+ * calling the dispose method.
+ */
+ void disposed(SingleComponentManager<S> component);
+
+}
\ No newline at end of file
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,129 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.TargetedPID;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.util.promise.Promise;
+
+
+/**
+ * The <code>ComponentHolder</code> interface provides the API for supporting
+ * component instances configured through either singleton configurations (or
+ * no configuration at all) and factory configurations.
+ * <p>
+ * Instances of this interface are managed by the {@link ConfigurationSupport}
+ * class on behalf of the
+ * {@link org.apache.felix.scr.impl.BundleComponentActivator} and the
+ * {@link org.apache.felix.scr.impl.ComponentRegistry}.
+ */
+public interface ComponentHolder<S>
+{
+
+ /**
+ * Returns the {@link BundleComponentActivator} owning this component
+ * holder. (overlaps ComponentContaienr)
+ */
+ BundleComponentActivator getActivator();
+
+ /**
+ * Returns the {@link ComponentMetadata} describing and declaring this
+ * component. (overlaps ComponentContaienr)
+ */
+ ComponentMetadata getComponentMetadata();
+
+ /**
+ * The configuration with the given PID has been deleted from the
+ * Configuration Admin service.
+ *
+ * @param pid The PID of the deleted configuration
+ * @param factoryPid The factory PID of the deleted configuration
+ */
+ void configurationDeleted( TargetedPID pid, TargetedPID factoryPid );
+
+
+ /**
+ * Configure a component with configuration from the given PID.
+ * @param targetedPid Targeted PID for the configuration
+ * @param factoryTargetedPid the (targeted) factory pid or null for a singleton pid
+ * @param props the property dictionary from the configuration.
+ * @param changeCount change count of the configuration, or R4 imitation.
+ *
+ * @return true if a new component is created for a factory PID, false if an existing factory pid configuration is updated or
+ * we have no factory pid
+ */
+ boolean configurationUpdated( TargetedPID targetedPid, TargetedPID factoryTargetedPid, Dictionary<String, Object> props, long changeCount );
+
+ /**
+ * Change count (or fake R4 imitation)
+ * @param pid a PID for the component we are interested in.
+ * @param targetedPid For a singleton pid, same as "pid"; for a factory pid, the factory pid.
+ * @return the last change count from a configurationUpdated call for the given pid.
+ */
+ long getChangeCount( TargetedPID pid, TargetedPID targetedPid );
+
+ /**
+ * Returns the targeted PID used to configure this component
+ * @param pid a targetedPID containing the service pid for the component desired (the rest of the targeted pid is ignored)
+ * @param factoryPid a targetedPID containing the factory pid for the component desired.
+ * @return the complete targeted pid actually used to configure the comonent.
+ */
+ TargetedPID getConfigurationTargetedPID(TargetedPID pid, TargetedPID factoryPid);
+
+ /**
+ * Returns all <code>Component</code> instances held by this holder.
+ */
+ List<? extends ComponentManager<?>> getComponents();
+
+ /**
+ * Enables all components of this holder and if satisfied activates
+ * them.
+ *
+ * @param async Whether the actual activation should take place
+ * asynchronously or not.
+ */
+ Promise<Void> enableComponents( boolean async );
+
+
+ /**
+ * Disables all components of this holder.
+ *
+ * @param async Whether the actual deactivation should take place
+ * asynchronously or not.
+ */
+ Promise<Void> disableComponents( boolean async );
+
+ /**
+ * whether the component is currently enabled
+ * @return whether the component is enabled
+ */
+ boolean isEnabled();
+
+
+ /**
+ * Disposes off all components of this holder.
+ * @param reason
+ */
+ void disposeComponents( int reason );
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,44 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+
+
+public interface ComponentManager<S> {
+
+ int STATE_UNSATISFIED_CONFIGURATION = ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION;
+ int STATE_UNSATISFIED_REFERENCE = ComponentConfigurationDTO.UNSATISFIED_REFERENCE;
+ int STATE_SATISFIED = ComponentConfigurationDTO.SATISFIED;
+ int STATE_ACTIVE = ComponentConfigurationDTO.ACTIVE;
+ int STATE_DISPOSED = 32;
+ int STATE_DISABLED = 64; //TODO????
+
+ Map<String, Object> getProperties();
+
+ long getId();
+
+ int getState();
+
+ List<? extends ReferenceManager<S, ?>> getReferenceManagers();
+
+}
\ No newline at end of file
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,882 @@
+/*
+ * 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.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+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;
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
+import org.apache.felix.scr.impl.manager.PrototypeServiceFactoryComponentManager;
+import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
+import org.apache.felix.scr.impl.manager.SingleComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
+import org.osgi.util.promise.Promises;
+
+
+/**
+ * The <code>ConfigurableComponentHolder</code> class is a
+ * {@link ComponentHolder} for automatically configured components instances
+ * that may or may not be configured through Config Admin.
+ * <p>
+ * The holder copes with three situations:
+ * <ul>
+ * <li>No configuration is available for the held component. That is there is
+ * no configuration whose <code>service.pid</code> or
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * <li>A singleton configuration is available whose <code>service.pid</code>
+ * equals the component name.</li>
+ * <li>One or more factory configurations exist whose
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * </ul>
+ */
+public class ConfigurableComponentHolder<S> implements ComponentHolder<S>, ComponentContainer<S>, SimpleLogger
+{
+
+ /**
+ * 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;
+
+ /** the targeted pids corresponding to the pids specified in the config metadata, except possibly for the single
+ * factory pid
+ */
+ private final TargetedPID[] m_targetedPids;
+
+ private final Long[] m_changeCount;
+
+ private final Map<String, Long> m_factoryChangeCount = new HashMap<String, Long>();
+
+ /**
+ * the index in metadata.getConfigurationPid() of the base factory pid, if any. Each component created from a factory configuration
+ * might have a different targeted pid.
+ */
+ private Integer m_factoryPidIndex;
+
+ /**
+ * the non-factory configurations shared between all instances.
+ */
+ private final Dictionary<String, Object>[] m_configurations;
+
+ /**
+ * the factory configurations indexed by pid (which cannot be a TargetedPID since it's generated by CA). We have to track these since
+ * other required configs may not yet be present so we can't create the component manager yet.
+ */
+ private final Map<String, Dictionary<String, Object>> m_factoryConfigurations = new HashMap<String, Dictionary<String, Object>>();
+
+ /**
+ * Each factory config may be from a different TargetedPID (sharing the same base service pid, but with different level of detail)
+ */
+ private final Map<String, TargetedPID> m_factoryTargetedPids = new HashMap<String, TargetedPID>();
+ /**
+ * 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 SingleComponentManager<S> component instances}
+ * created on behalf of the configurations.
+ */
+ private final Map<String, AbstractComponentManager<S>> m_components;
+
+ /**
+ * The special component used if there is no configuration or a singleton
+ * configuration. This field is only <code>null</code> once all components
+ * held by this holder have been disposed of by
+ * {@link #disposeComponents(int)} and is first created in the constructor.
+ * As factory configurations are provided this instance may be configured
+ * or "deconfigured".
+ * <p>
+ * Expected invariants:
+ * <ul>
+ * <li>This field is only <code>null</code> after disposal of all held
+ * components</li>
+ * <li>The {@link #m_components} map is empty or the component pointed to
+ * by this field is also contained in the map</li>
+ * <ul>
+ */
+ private AbstractComponentManager<S> m_singleComponent;
+
+ /**
+ * Whether components have already been enabled by calling the
+ * {@link #enableComponents(boolean)} method. If this field is <code>true</code>
+ * component instances created per configuration by the
+ * {@link #configurationUpdated(TargetedPID, TargetedPID, Dictionary, long)} method are also
+ * enabled. Otherwise they are not enabled immediately.
+ */
+ private volatile boolean m_enabled;
+ private final Object enableLock = new Object();
+ private Promise<Void> m_enablePromise;
+ private Promise<Void> m_disablePromise = Promises.resolved(null);
+
+ private final ComponentMethods m_componentMethods;
+
+ public ConfigurableComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+ {
+ this.m_activator = activator;
+ this.m_componentMetadata = metadata;
+ int pidCount = metadata.getConfigurationPid().size();
+ this.m_targetedPids = new TargetedPID[pidCount];
+ this.m_configurations = new Dictionary[pidCount];
+ this.m_changeCount = new Long[pidCount];
+ this.m_components = new HashMap<String, AbstractComponentManager<S>>();
+ this.m_componentMethods = new ComponentMethods();
+ this.m_enabled = false;
+ }
+
+ protected AbstractComponentManager<S> createComponentManager(boolean factoryConfiguration)
+ {
+
+ AbstractComponentManager<S> manager;
+ if ( m_componentMetadata.isFactory() )
+ {
+ //TODO is there any check to make sure factory component factories are enabled before creating them?
+ if ( !m_componentMetadata.isObsoleteFactoryComponentFactory() || !factoryConfiguration )
+ {
+ manager = new ComponentFactoryImpl<S>(this );
+ }
+ else
+ {
+ manager = new SingleComponentManager<S>(this, m_componentMethods, true );
+ }
+ }
+ else if ( m_componentMetadata.getServiceScope() == Scope.bundle )
+ {
+ manager = new ServiceFactoryComponentManager<S>( this, m_componentMethods );
+ }
+
+ else if ( m_componentMetadata.getServiceScope() == Scope.prototype )
+ {
+ manager = PSFLoader.newPSFComponentManager(this, m_componentMethods);
+ }
+
+ else
+ {
+ //immediate or delayed
+ manager = new SingleComponentManager<S>( this, m_componentMethods );
+ }
+
+ return manager;
+ }
+
+ private static class PSFLoader
+ {
+ static <S> AbstractComponentManager<S> newPSFComponentManager(ConfigurableComponentHolder<S> holder, ComponentMethods methods)
+ {
+ return new PrototypeServiceFactoryComponentManager<S>( holder, methods );
+ }
+ }
+
+
+ public final BundleComponentActivator getActivator()
+ {
+ return m_activator;
+ }
+
+
+ public final ComponentMetadata getComponentMetadata()
+ {
+ return m_componentMetadata;
+ }
+
+
+ /**
+ * The configuration with the given <code>pid</code>
+ * (<code>service.pid</code> of the configuration object) is deleted.
+ * <p>
+ * The following situations are supported:
+ * <ul>
+ * <li>The configuration was a singleton configuration (pid equals the
+ * component name). In this case the internal component map is empty and
+ * the single component has been configured by the singleton configuration
+ * and is no "deconfigured".</li>
+ * <li>A factory configuration object has been deleted and the configured
+ * object is set as the single component. If the single component held the
+ * last factory configuration object, it is deconfigured. Otherwise the
+ * single component is disposed off and replaced by another component in
+ * the map of existing components.</li>
+ * <li>A factory configuration object has been deleted and the configured
+ * object is not set as the single component. In this case the component is
+ * simply disposed off and removed from the internal map.</li>
+ * </ul>
+ */
+ public void configurationDeleted( final TargetedPID pid, TargetedPID factoryPid )
+ {
+ log( LogService.LOG_DEBUG, "ImmediateComponentHolder configuration deleted for pid {0}",
+ new Object[] {pid}, null);
+
+ // component to deconfigure or dispose of
+ final Map<AbstractComponentManager<S>, Map<String, Object>> scms = new HashMap<AbstractComponentManager<S>, Map<String, Object>>();
+ boolean reconfigure = false;
+
+ synchronized ( m_components )
+ {
+ if (factoryPid != null) {
+ checkFactoryPidIndex(factoryPid);
+ String servicePid = pid.getServicePid();
+ m_factoryTargetedPids.remove(servicePid);
+ m_factoryChangeCount.remove(servicePid);
+ m_factoryConfigurations.remove(servicePid);
+ AbstractComponentManager<S> scm = m_components.remove(servicePid);
+ if ( m_factoryConfigurations.isEmpty() )
+ {
+ m_factoryPidIndex = null;
+ }
+ if ( !m_enabled || scm == null )
+ {
+ return;
+ }
+ reconfigure = m_componentMetadata.isConfigurationOptional() && m_components.isEmpty();
+ if ( reconfigure )
+ {
+ m_singleComponent = scm;
+ scms.put( scm, mergeProperties(null) );
+ }
+ else
+ {
+ scms.put( scm, null );
+ }
+ }
+ else
+ {
+ //singleton pid
+ int index = getSingletonPidIndex(pid);
+ m_targetedPids[index] = null;
+ m_changeCount[index] = null;
+ m_configurations[index] = null;
+ if ( !m_enabled )
+ {
+ return;
+ }
+ reconfigure = m_componentMetadata.isConfigurationOptional();
+
+ if ( m_factoryPidIndex == null)
+ {
+ if ( m_singleComponent != null ) {
+ if (reconfigure) {
+ scms.put(m_singleComponent, mergeProperties(null));
+ } else {
+ scms.put(m_singleComponent, null);
+ m_singleComponent = null;
+ }
+ }
+ }
+ else
+ {
+ if (reconfigure) {
+ for (Map.Entry<String, AbstractComponentManager<S>> entry : m_components.entrySet()) {
+ scms.put(entry.getValue(), mergeProperties(entry.getKey()));
+ }
+ }
+ else
+ {
+ for (Map.Entry<String, AbstractComponentManager<S>> entry : m_components.entrySet()) {
+ scms.put(entry.getValue(), null );
+ }
+ m_components.clear();
+ }
+ }
+
+ }
+ }
+
+ for ( Map.Entry<AbstractComponentManager<S>,Map<String, Object>> entry: scms.entrySet())
+ {
+ if ( reconfigure ) {
+ entry.getKey().reconfigure( entry.getValue(), true);
+ } else {
+ entry.getKey().dispose(ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED);
+ }
+ }
+ }
+
+
+ /**
+ * Configures a component with the given configuration. This configuration
+ * update may happen in various situations:
+ * <ul>
+ * <li>The <code>pid</code> equals the component name. Hence we have a
+ * singleton configuration for the single component held by this holder</li>
+ * <li>The configuration is a factory configuration and is the first
+ * configuration provided. In this case the single component is provided
+ * with the configuration and also stored in the map.</li>
+ * <li>The configuration is a factory configuration but not the first. In
+ * this case a new component is created, configured and stored in the map</li>
+ * </ul>
+ * @return true if a new configuration was created, false otherwise. //TODO there are now 3 states..... still not satisfied, existing, and new
+ */
+ public boolean configurationUpdated( TargetedPID pid, TargetedPID factoryPid, final Dictionary<String, Object> props, long changeCount )
+ {
+ log( LogService.LOG_DEBUG, "ConfigurableComponentHolder configuration updated for pid {0} with properties {1}",
+ new Object[] {pid, props}, null);
+
+ // component to update or create
+ final Map<AbstractComponentManager<S>, Map<String, Object>> scms = new HashMap< AbstractComponentManager<S>, Map<String, Object>>();
+ boolean created = false;
+
+ //TODO better change count tracking
+ synchronized (m_components) {
+ //Find or create the component manager, or return if not satisfied.
+ if (factoryPid != null) {
+ checkFactoryPidIndex(factoryPid);
+ m_factoryConfigurations.put(pid.getServicePid(), props);
+ m_factoryTargetedPids.put(pid.getServicePid(), factoryPid);
+ m_factoryChangeCount.put(pid.getServicePid(), changeCount);
+ if (m_enabled && isSatisfied()) {
+ if (m_singleComponent != null && !m_componentMetadata.isObsoleteFactoryComponentFactory()) {
+ AbstractComponentManager<S> scm = m_singleComponent;
+ scms.put( scm, mergeProperties( pid.getServicePid() ) );
+ m_singleComponent = null;
+ m_components.put(pid.getServicePid(), scm);
+ } else if (m_components.containsKey(pid.getServicePid())) {
+ scms.put( m_components.get(pid.getServicePid()), mergeProperties( pid.getServicePid()) );
+ } else {
+ AbstractComponentManager<S> scm = createComponentManager(true);
+ m_components.put(pid.getServicePid(), scm);
+ scms.put( scm, mergeProperties( pid.getServicePid()) );
+ created = true;
+ }
+ } else {
+ return false;
+ }
+
+ } else {
+ //singleton pid
+ int index = getSingletonPidIndex(pid);
+ m_targetedPids[index] = pid;
+ m_changeCount[index] = changeCount;
+ m_configurations[index] = props;
+ if (m_enabled && isSatisfied()) {
+ if (m_singleComponent != null) {
+ scms.put( m_singleComponent, mergeProperties( pid.getServicePid() ) );
+ }
+ else if ( m_factoryPidIndex != null)
+ {
+ for (Map.Entry<String, AbstractComponentManager<S>> entry: m_components.entrySet())
+ {
+ scms.put(entry.getValue(), mergeProperties( entry.getKey()));
+ }
+ }
+ else
+ {
+ m_singleComponent = createComponentManager(false);
+ scms.put( m_singleComponent, mergeProperties( pid.getServicePid() ) );
+ created = true;
+ }
+ } else {
+ return false;
+ }
+
+ }
+
+ }
+
+
+ // we have the icm.
+ //properties is all the configs merged together (without any possible component factory info.
+
+ final boolean enable = created && m_enabled;// TODO WTF?? && getComponentMetadata().isEnabled();
+ for ( Map.Entry<AbstractComponentManager<S>,Map<String, Object>> entry: scms.entrySet())
+ {
+ // configure the component
+ entry.getKey().reconfigure(entry.getValue(), false);
+ log(LogService.LOG_DEBUG,
+ "ImmediateComponentHolder Finished configuring the dependency managers for component for pid {0} ",
+ new Object[] { pid }, null);
+ if (enable) {
+ entry.getKey().enable(false);
+ log(LogService.LOG_DEBUG,
+ "ImmediateComponentHolder Finished enabling component for pid {0} ",
+ new Object[] { pid }, null);
+ } else {
+ log(LogService.LOG_DEBUG,
+ "ImmediateComponentHolder Will not enable component for pid {0}: holder enabled state: {1}, metadata enabled: {2} ",
+ new Object[] { pid, m_enabled,
+ m_componentMetadata.isEnabled() }, null);
+ }
+ }
+ return created;
+ }
+
+ private Map<String, Object> mergeProperties(String servicePid) {
+ Map<String, Object> properties = new HashMap<String, Object>(m_componentMetadata.getProperties());
+ List<String> pids = null;
+ boolean isDS13 = m_componentMetadata.getDSVersion().isDS13();
+ if (isDS13)
+ {
+ pids = new ArrayList<String>();
+ if (properties.get(Constants.SERVICE_PID) instanceof String)
+ {
+ pids.add((String) properties.get(Constants.SERVICE_PID));
+ }
+ }
+ for (int i = 0; i < m_configurations.length; i++)
+ {
+ if ( m_factoryPidIndex != null && i == m_factoryPidIndex
+ && !( m_componentMetadata.isObsoleteFactoryComponentFactory() && servicePid == null)) //obsolete special case
+ {
+ copyTo(properties, m_factoryConfigurations.get(servicePid));
+ if (isDS13)
+ {
+ pids.add((String) m_factoryConfigurations.get(servicePid).get(Constants.SERVICE_PID));
+ }
+ }
+ else if ( m_configurations[i] != null )
+ {
+ copyTo(properties, m_configurations[i]);
+ if (isDS13)
+ {
+ pids.add((String) m_configurations[i].get(Constants.SERVICE_PID));
+ }
+ }
+ }
+ if (isDS13 && !pids.isEmpty())
+ {
+ if ( pids.size() == 1 )
+ {
+ properties.put(Constants.SERVICE_PID, pids.get(0));
+ }
+ else
+ {
+ properties.put(Constants.SERVICE_PID, pids);
+ }
+ }
+ return properties;
+ }
+
+ private int getSingletonPidIndex(TargetedPID pid) {
+ int index = m_componentMetadata.getPidIndex(pid);
+ if (index == -1) {
+ log(LogService.LOG_ERROR,
+ "Unrecognized pid {0}, expected one of {1}",
+ new Object[] { pid,
+ m_componentMetadata.getConfigurationPid() },
+ null);
+ throw new IllegalArgumentException("Unrecognized pid "
+ + pid);
+ }
+ if (m_factoryPidIndex != null && index == m_factoryPidIndex) {
+ log(LogService.LOG_ERROR,
+ "singleton pid {0} supplied, but matches an existing factory pid at index: {1}",
+ new Object[] { pid, m_factoryPidIndex }, null);
+ throw new IllegalStateException(
+ "Singleton pid supplied matching a previous factory pid "
+ + pid);
+ }
+ return index;
+ }
+
+ //TODO update error messages so they make sense for deleting config too.
+ private void checkFactoryPidIndex(TargetedPID factoryPid) {
+ int index = m_componentMetadata.getPidIndex(factoryPid);
+ if (index == -1) {
+ log(LogService.LOG_ERROR,
+ "Unrecognized factory pid {0}, expected one of {1}",
+ new Object[] { factoryPid,
+ m_componentMetadata.getConfigurationPid() },
+ null);
+ throw new IllegalArgumentException(
+ "Unrecognized factory pid " + factoryPid);
+ }
+ if (m_configurations[index] != null) {
+ log(LogService.LOG_ERROR,
+ "factory pid {0}, but this pid is already supplied as a singleton: {1} at index {2}",
+ new Object[] { factoryPid, Arrays.asList(m_targetedPids), index }, null);
+ throw new IllegalStateException(
+ "Factory pid supplied after all non-factory configurations supplied "
+ + factoryPid);
+ }
+ if (m_factoryPidIndex == null) {
+ m_factoryPidIndex = index;
+ } else if (index != m_factoryPidIndex) {
+ log(LogService.LOG_ERROR,
+ "factory pid {0} supplied for index {1}, but a factory pid previously supplied at index {2}",
+ new Object[] { factoryPid, index, m_factoryPidIndex },
+ null);
+ throw new IllegalStateException(
+ "Factory pid supplied at wrong index " + factoryPid);
+ }
+ }
+
+ protected static void copyTo( Map<String, Object> target, Dictionary<String, ?> source )
+ {
+
+ for ( Enumeration<String> keys = source.keys(); keys.hasMoreElements(); )
+ {
+ String key = keys.nextElement();
+ Object value = source.get(key);
+ target.put(key, value);
+ }
+ }
+
+ /**
+ * Determine if the holder is satisfied with configurations
+ * @return true if configuration optional or all pids supplied with configurations
+ */
+ private boolean isSatisfied() {
+ if ( m_componentMetadata.isConfigurationOptional() || m_componentMetadata.isConfigurationIgnored() )
+ {
+ return true;
+ }
+ for ( int i = 0; i < m_componentMetadata.getConfigurationPid().size(); i++)
+ {
+ if ( m_configurations[i] != null)
+ {
+ continue;
+ }
+ if ( m_factoryPidIndex != null && m_factoryPidIndex == i)
+ {
+ continue;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param pid the Targeted PID we need the change count for
+ * @param targetedPid the targeted factory pid for a factory configuration or the pid for a singleton configuration
+ * @return pid for this service pid.
+ */
+ public long getChangeCount( TargetedPID pid, TargetedPID targetedPid)
+ {
+ int index = m_componentMetadata.getPidIndex(targetedPid);
+ Long result;
+ if ( index == -1 )
+ {
+ throw new IllegalArgumentException("pid not recognized as for this component: " + pid);
+ }
+ if ( m_factoryPidIndex != null && index == m_factoryPidIndex )
+ {
+ result = m_factoryChangeCount.get(pid.getServicePid());
+ }
+ else
+ {
+ result = m_changeCount[index];
+ }
+ return result == null? -1: result;
+
+ }
+
+ public List<? extends ComponentManager<?>> getComponents()
+ {
+ synchronized ( m_components )
+ {
+ return getComponentManagers( );
+ }
+ }
+
+
+ public boolean isEnabled() {
+ return m_enabled;
+ }
+
+
+ private void wait(Promise<Void> promise)
+ {
+ boolean waited = false;
+ boolean interrupted = false;
+ while ( !waited )
+ {
+ try
+ {
+ promise.getValue();
+ waited = true;
+ }
+ catch ( InterruptedException e )
+ {
+ interrupted = true;
+ }
+ catch (InvocationTargetException e)
+ {
+ //this is not going to happen
+ }
+ }
+ if ( interrupted )
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public Promise<Void> enableComponents( final boolean async )
+ {
+ synchronized (enableLock)
+ {
+ if ( m_enablePromise != null)
+ {
+ return m_enablePromise;
+ }
+ wait( m_disablePromise );
+
+
+ List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+ synchronized ( m_components )
+ {
+ if ( isSatisfied() )
+ {
+ if ( m_factoryPidIndex == null ||
+ (m_componentMetadata.isObsoleteFactoryComponentFactory() && !m_componentMetadata.isConfigurationRequired()))
+ {
+ m_singleComponent = createComponentManager(false);
+ cms.add( m_singleComponent );
+ m_singleComponent.reconfigure(mergeProperties( null ), false);
+ }
+ if ( m_factoryPidIndex != null)
+ {
+ for (String pid: m_factoryConfigurations.keySet()) {
+ AbstractComponentManager<S> scm = createComponentManager(true);
+ m_components.put(pid, scm);
+ scm.reconfigure( mergeProperties( pid ), false);
+ cms.add( scm );
+ }
+ }
+ }
+ m_enabled = true;
+ }
+ List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
+ for ( AbstractComponentManager<S> cm : cms )
+ {
+ promises.add(cm.enable( async ));
+ }
+ m_enablePromise = new Deferred<List<Void>>().resolveWith(Promises.<Void, Void>all(promises));
+ m_disablePromise = null;
+ return m_enablePromise;
+ }
+ }
+
+
+ public Promise<Void> disableComponents( final boolean async )
+ {
+ synchronized (enableLock)
+ {
+ if ( m_disablePromise != null)
+ {
+ return m_disablePromise;
+ }
+ wait( m_enablePromise );
+
+ List<AbstractComponentManager<S>> cms;
+ synchronized ( m_components )
+ {
+ m_enabled = false;
+
+ cms = getDirectComponentManagers( );
+ clearComponents();
+ }
+ List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
+ for ( AbstractComponentManager<S> cm : cms )
+ {
+ promises.add(cm.disable( async ));
+ }
+ m_disablePromise = new Deferred<List<Void>>().resolveWith(Promises.<Void, Void>all(promises));
+ m_enablePromise = null;
+ return m_disablePromise;
+ }
+ }
+
+
+ public void disposeComponents( final int reason )
+ {
+ List<AbstractComponentManager<S>> cms;
+ synchronized ( m_components )
+ {
+ cms = getDirectComponentManagers( );
+ clearComponents();
+ }
+ for ( AbstractComponentManager<S> cm : cms )
+ {
+ cm.dispose( reason );
+ }
+ }
+
+
+ public void disposed( SingleComponentManager<S> component )
+ {
+ // ensure the component is removed from the components map
+ synchronized ( m_components )
+ {
+ if ( !m_components.isEmpty() )
+ {
+ for ( Iterator<AbstractComponentManager<S>> vi = m_components.values().iterator(); vi.hasNext(); )
+ {
+ if ( component == vi.next() )
+ {
+ vi.remove();
+ break;
+ }
+ }
+ }
+
+ if ( component == m_singleComponent )
+ {
+ m_singleComponent = null;
+ }
+ }
+ }
+
+ /**
+ * Compares this {@code ImmediateComponentHolder} object to another object.
+ *
+ * <p>
+ * A ImmediateComponentHolder is considered to be <b>equal to </b> another
+ * ImmediateComponentHolder if the component names are equal(using
+ * {@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
+ * {@code ImmediateComponentHolder} and is equal to this object;
+ * {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object object)
+ {
+ if (!(object instanceof ConfigurableComponentHolder))
+ {
+ return false;
+ }
+
+ ConfigurableComponentHolder<S> other = (ConfigurableComponentHolder<S>) object;
+ return m_activator == other.m_activator
+ && getName().equals(other.getName());
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return An integer which is a hash code value for this object.
+ */
+ @Override
+ public int hashCode()
+ {
+ return getName().hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "[ImmediateComponentHolder:" + getName() + "]";
+ }
+
+ String getName()
+ {
+ return m_componentMetadata.getName();
+ }
+
+ //---------- internal
+
+ /**
+ * Returns all component managers from the map and the single component manager, optionally also removing them
+ * from the map. If there are no component managers, <code>null</code>
+ * is returned. Must be called synchronized on m_components.
+ */
+ List<AbstractComponentManager<S>> getComponentManagers( )
+ {
+ List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+ if ( m_singleComponent != null)
+ {
+ m_singleComponent.getComponentManagers(cms);
+ }
+
+ for (AbstractComponentManager<S> cm: m_components.values())
+ {
+ cm.getComponentManagers(cms);
+ }
+ return cms;
+ }
+
+ List<AbstractComponentManager<S>> getDirectComponentManagers( )
+ {
+ List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+ if ( m_singleComponent != null)
+ {
+ cms.add(m_singleComponent);
+ }
+ cms.addAll(m_components.values());
+ return cms;
+ }
+
+ void clearComponents()
+ {
+ m_components.clear();
+ m_singleComponent = null;
+ }
+
+ public boolean isLogEnabled( int level )
+ {
+ return Activator.isLogEnabled( level );
+ }
+
+ public void log( int level, String message, Throwable ex )
+ {
+ BundleComponentActivator activator = getActivator();
+ if ( activator != null )
+ {
+ activator.log( level, message, getComponentMetadata(), null, ex );
+ }
+ }
+
+ public void log( int level, String message, Object[] arguments, Throwable ex )
+ {
+ BundleComponentActivator activator = getActivator();
+ if ( activator != null )
+ {
+ activator.log( level, message, arguments, getComponentMetadata(), null, ex );
+ }
+ }
+
+ public TargetedPID getConfigurationTargetedPID(TargetedPID pid, TargetedPID factoryPid)
+ {
+ if ( factoryPid == null )
+ {
+ int index = m_componentMetadata.getPidIndex(pid);
+ if (index != -1)
+ {
+ return m_targetedPids[index];
+ }
+ return null;
+ }
+ //each factory configured component may have a different factory targeted pid.
+ synchronized (m_components)
+ {
+ return m_factoryTargetedPids.get(pid.getServicePid());
+ }
+ }
+
+}