You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ui...@apache.org on 2012/02/24 11:47:51 UTC
svn commit: r1293173 [4/8] - in
/felix/sandbox/uiterlix/dependencymanager/core: ./ .externalToolBuilders/
.settings/ src/ src/main/ src/main/java/ src/main/java/org/
src/main/java/org/apache/ src/main/java/org/apache/felix/
src/main/java/org/apache/fel...
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,288 @@
+/*
+ * 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.dm.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.PropertyMetaData;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * Factory configuration adapter service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual adapter service implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FactoryConfigurationAdapterServiceImpl extends FilterService {
+ public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ Hashtable props = new Hashtable();
+ props.put(Constants.SERVICE_PID, factoryPid);
+ m_component
+ .setInterface(ManagedServiceFactory.class.getName(), props)
+ .setImplementation(new AdapterImpl(factoryPid, update, propagate));
+ }
+
+ public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
+ BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ Hashtable props = new Hashtable();
+ props.put(Constants.SERVICE_PID, factoryPid);
+ m_component
+ .setInterface(ManagedServiceFactory.class.getName(), props)
+ .setImplementation(new MetaTypeAdapterImpl(factoryPid, update, propagate,
+ bctx, logger, heading, description,
+ localization, properyMetaData));
+ }
+
+ /**
+ * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
+ */
+ public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {
+ // Our Managed Service Factory PID
+ protected String m_factoryPid;
+
+ // The adapter "update" method used to provide the configuration
+ protected String m_update;
+
+ // Tells if the CM config must be propagated along with the adapter service properties
+ protected boolean m_propagate;
+
+ /**
+ * Creates a new CM factory configuration adapter.
+ *
+ * @param factoryPid
+ * @param updateMethod
+ * @param adapterInterface
+ * @param adapterImplementation
+ * @param adapterProperties
+ * @param propagate
+ */
+ public AdapterImpl(String factoryPid, String updateMethod, boolean propagate) {
+ m_factoryPid = factoryPid;
+ m_update = updateMethod;
+ m_propagate = propagate;
+ }
+
+ /**
+ * Returns the managed service factory name.
+ */
+ public String getName() {
+ return m_factoryPid;
+ }
+
+ /**
+ * Method called from our superclass, when we need to create a service.
+ */
+ public Component createService(Object[] properties) {
+ Dictionary settings = (Dictionary) properties[0];
+ Component newService = m_manager.createComponent();
+ Object impl = null;
+
+ try {
+ if (m_serviceImpl != null) {
+ impl = (m_serviceImpl instanceof Class) ? ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
+ }
+ else {
+ impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
+ }
+ InvocationUtil.invokeCallbackMethod(impl, m_update,
+ new Class[][] {{ Dictionary.class }, {}},
+ new Object[][] {{ settings }, {}});
+ }
+
+ catch (Throwable t) {
+ handleException(t);
+ }
+
+ // Merge adapter service properties, with CM settings
+ Dictionary serviceProperties = getServiceProperties(settings);
+ newService.setInterface(m_serviceInterfaces, serviceProperties);
+ newService.setImplementation(impl);
+ newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
+ newService.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy); // if not set, no effect
+ configureAutoConfigState(newService, m_component);
+
+ List dependencies = m_component.getDependencies();
+ for (int i = 0; i < dependencies.size(); i++) {
+ newService.add(((Dependency) dependencies.get(i)).createCopy());
+ }
+
+ for (int i = 0; i < m_stateListeners.size(); i ++) {
+ newService.addStateListener((ComponentStateListener) m_stateListeners.get(i));
+ }
+
+ return newService;
+ }
+
+ /**
+ * Method called from our superclass, when we need to update a Service, because
+ * the configuration has changed.
+ */
+ public void updateService(Object[] properties) {
+ Dictionary cmSettings = (Dictionary) properties[0];
+ Component service = (Component) properties[1];
+ Object impl = service.getService();
+
+ try {
+ InvocationUtil.invokeCallbackMethod(impl, m_update,
+ new Class[][] {{ Dictionary.class }, {}},
+ new Object[][] {{ cmSettings }, {}});
+ if (m_serviceInterfaces != null && m_propagate == true) {
+ Dictionary serviceProperties = getServiceProperties(cmSettings);
+ service.setServiceProperties(serviceProperties);
+ }
+ }
+
+ catch (Throwable t) {
+ handleException(t);
+ }
+ }
+
+ /**
+ * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
+ * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
+ *
+ * @param adapterProperties
+ * @param settings
+ * @return
+ */
+ private Dictionary getServiceProperties(Dictionary settings) {
+ Dictionary props = new Hashtable();
+
+ // Add adapter Service Properties
+ if (m_serviceProperties != null) {
+ Enumeration keys = m_serviceProperties.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ Object val = m_serviceProperties.get(key);
+ props.put(key, val);
+ }
+ }
+
+ if (m_propagate) {
+ // Add CM setting into adapter service properties.
+ // (CM setting will override existing adapter service properties).
+ Enumeration keys = settings.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ if (! key.toString().startsWith(".")) {
+ // public properties are propagated
+ Object val = settings.get(key);
+ props.put(key, val);
+ }
+ }
+ }
+
+
+ return props;
+ }
+
+ private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod) {
+ Object factory = null;
+ if (m_factory instanceof Class) {
+ try {
+ factory = createInstance((Class) m_factory);
+ }
+ catch (Throwable t) {
+ handleException(t);
+ }
+ }
+ else {
+ factory = m_factory;
+ }
+
+ try {
+ return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod, new Class[][] { {} }, new Object[][] { {} }, false);
+ }
+ catch (Throwable t) {
+ handleException(t);
+ return null;
+ }
+ }
+
+ private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+ Constructor constructor = clazz.getConstructor(new Class[] {});
+ constructor.setAccessible(true);
+ return clazz.newInstance();
+ }
+
+ private void handleException(Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ // Our super class will check if the target exception is itself a ConfigurationException.
+ // In this case, it will simply re-thrown.
+ throw new RuntimeException(((InvocationTargetException) t).getTargetException());
+ }
+ else if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ else {
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+
+ /**
+ * Extends AdapterImpl for MetaType support.
+ */
+ class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
+ // Our MetaType Provider for describing our properties metadata
+ private MetaTypeProviderImpl m_metaType;
+
+ public MetaTypeAdapterImpl(String factoryPid, String updateMethod, boolean propagate,
+ BundleContext bctx, Logger logger, String heading,
+ String description, String localization,
+ PropertyMetaData[] properyMetaData) {
+ super(factoryPid, updateMethod, propagate);
+ m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
+ m_metaType.setName(heading);
+ m_metaType.setDescription(description);
+ if (localization != null) {
+ m_metaType.setLocalization(localization);
+ }
+ for (int i = 0; i < properyMetaData.length; i++) {
+ m_metaType.add(properyMetaData[i]);
+ }
+ }
+
+ public String[] getLocales() {
+ return m_metaType.getLocales();
+ }
+
+ public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
+ return m_metaType.getObjectClassDefinition(id, locale);
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,276 @@
+/*
+ * 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.dm.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentDeclaration;
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This class allows to filter a Component interface. All Aspect/Adapters extend this class
+ * in order to add functionality to the default Component implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FilterService implements Component, ComponentDeclaration {
+ protected ComponentImpl m_component;
+ protected List m_stateListeners = new ArrayList();
+ protected String m_init = "init";
+ protected String m_start = "start";
+ protected String m_stop = "stop";
+ protected String m_destroy = "destroy";
+ protected Object m_callbackObject;
+ protected Object m_compositionInstance;
+ protected String m_compositionMethod;
+ protected String[] m_serviceInterfaces;
+ protected Object m_serviceImpl;
+ protected Object m_factory;
+ protected String m_factoryCreateMethod;
+ protected Dictionary m_serviceProperties;
+
+ public FilterService(Component service) {
+ m_component = (ComponentImpl) service;
+ }
+
+ public Component add(Dependency dependency) {
+ m_component.add(dependency);
+ // Add the dependency (if optional) to all already instantiated services.
+ // If the dependency is required, our internal service will be stopped/restarted, so in this case
+ // we have nothing to do.
+ if (! dependency.isRequired()) {
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null)
+ {
+ ad.addDependency(dependency);
+ }
+ }
+ return this;
+ }
+
+ public Component add(List dependencies) {
+ m_component.add(dependencies);
+ // Add the dependencies to all already instantiated services.
+ // If one dependency from the list is required, we have nothing to do, since our internal
+ // service will be stopped/restarted.
+ Iterator it = dependencies.iterator();
+ while (it.hasNext()) {
+ if (((Dependency) it.next()).isRequired()) {
+ return this;
+ }
+ }
+ // Ok, the list contains no required dependencies: add optionals dependencies in already instantiated
+ // services.
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null) {
+ ad.addDependencies(dependencies);
+ }
+ return this;
+ }
+
+ public void addStateListener(ComponentStateListener listener) {
+ synchronized (this) {
+ m_stateListeners.add(listener);
+ }
+ // Add the listener to all already instantiated services.
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null) {
+ ad.addStateListener(listener);
+ }
+ }
+
+ public List getDependencies() {
+ return m_component.getDependencies();
+ }
+
+ public Object getService() {
+ return m_component.getService();
+ }
+
+ public synchronized Dictionary getServiceProperties() {
+ return m_serviceProperties;
+ }
+
+ public ServiceRegistration getServiceRegistration() {
+ return m_component.getServiceRegistration();
+ }
+
+ public Component remove(Dependency dependency) {
+ m_component.remove(dependency);
+ // Remove the dependency (if optional) from all already instantiated services.
+ // If the dependency is required, our internal service will be stopped, so in this case
+ // we have nothing to do.
+ if (!dependency.isRequired())
+ {
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null)
+ {
+ ad.removeDependency(dependency);
+ }
+ }
+ return this;
+ }
+
+ public void removeStateListener(ComponentStateListener listener) {
+ synchronized (this) {
+ m_stateListeners.remove(listener);
+ }
+ // Remove the listener from all already instantiated services.
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null) {
+ ad.removeStateListener(listener);
+ }
+ }
+
+ public synchronized Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
+ m_component.ensureNotActive();
+ m_callbackObject = instance;
+ m_init = init;
+ m_start = start;
+ m_stop = stop;
+ m_destroy = destroy;
+ return this;
+ }
+
+ public Component setCallbacks(String init, String start, String stop, String destroy) {
+ setCallbacks(null, init, start, stop, destroy);
+ return this;
+ }
+
+ public synchronized Component setComposition(Object instance, String getMethod) {
+ m_component.ensureNotActive();
+ m_compositionInstance = instance;
+ m_compositionMethod = getMethod;
+ return this;
+ }
+
+ public synchronized Component setComposition(String getMethod) {
+ m_component.ensureNotActive();
+ m_compositionMethod = getMethod;
+ return this;
+ }
+
+ public synchronized Component setFactory(Object factory, String createMethod) {
+ m_component.ensureNotActive();
+ m_factory = factory;
+ m_factoryCreateMethod = createMethod;
+ return this;
+ }
+
+ public Component setFactory(String createMethod) {
+ return setFactory(null, createMethod);
+ }
+
+ public synchronized Component setImplementation(Object implementation) {
+ m_component.ensureNotActive();
+ m_serviceImpl = implementation;
+ return this;
+ }
+
+ public Component setInterface(String serviceName, Dictionary properties) {
+ return setInterface(new String[] { serviceName }, properties);
+ }
+
+ public synchronized Component setInterface(String[] serviceInterfaces, Dictionary properties) {
+ m_component.ensureNotActive();
+ if (serviceInterfaces != null) {
+ m_serviceInterfaces = new String[serviceInterfaces.length];
+ System.arraycopy(serviceInterfaces, 0, m_serviceInterfaces, 0, serviceInterfaces.length);
+ m_serviceProperties = properties;
+ }
+ return this;
+ }
+
+ public Component setServiceProperties(Dictionary serviceProperties) {
+ synchronized (this) {
+ m_serviceProperties = serviceProperties;
+ }
+ // Set the properties to all already instantiated services.
+ if (serviceProperties != null) {
+ AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+ if (ad != null) {
+ ad.setServiceProperties(serviceProperties);
+ }
+ }
+ return this;
+ }
+
+ public void start() {
+ m_component.start();
+ }
+
+ public void stop() {
+ m_component.stop();
+ }
+
+ public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
+ m_component.invokeCallbackMethod(instances, methodName, signatures, parameters);
+ }
+
+ public Object[] getCompositionInstances() {
+ return m_component.getCompositionInstances();
+ }
+
+ public DependencyManager getDependencyManager() {
+ return m_component.getDependencyManager();
+ }
+
+ public Component setAutoConfig(Class clazz, boolean autoConfig) {
+ m_component.setAutoConfig(clazz, autoConfig);
+ return this;
+ }
+
+ public Component setAutoConfig(Class clazz, String instanceName) {
+ m_component.setAutoConfig(clazz, instanceName);
+ return this;
+ }
+
+ public boolean getAutoConfig(Class clazz) {
+ return m_component.getAutoConfig(clazz);
+ }
+
+ public String getAutoConfigInstance(Class clazz) {
+ return m_component.getAutoConfigInstance(clazz);
+ }
+
+ public ComponentDependencyDeclaration[] getComponentDependencies() {
+ return m_component.getComponentDependencies();
+ }
+
+ public String getName() {
+ return m_component.getName();
+ }
+
+ public int getState() {
+ return m_component.getState();
+ }
+
+ public BundleContext getBundleContext() {
+ return m_component.getBundleContext();
+ };
+}
\ No newline at end of file
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,228 @@
+/*
+ * 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.dm.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This class mimics the standard OSGi <tt>LogService</tt> interface. An
+ * instance of this class is used by the dependency manager for all logging.
+ * By default this class logs messages to standard out. The log level can be set to
+ * control the amount of logging performed, where a higher number results in
+ * more logging. A log level of zero turns off logging completely.
+ *
+ * The log levels match those specified in the OSGi Log Service.
+ * This class also tracks log services and will use the highest ranking
+ * log service, if present, as a back end instead of printing to standard
+ * out. The class uses reflection to invoking the log service's method to
+ * avoid a dependency on the log interface, which is also why it does not
+ * actually implement <code>LogService</code>. This class is in many ways
+ * similar to the one used in the system bundle for that same purpose.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Logger implements ServiceListener {
+ public static final int LOG_ERROR = 1;
+ public static final int LOG_WARNING = 2;
+ public static final int LOG_INFO = 3;
+ public static final int LOG_DEBUG = 4;
+
+ private final BundleContext m_context;
+
+ private final static int LOGGER_OBJECT_IDX = 0;
+ private final static int LOGGER_METHOD_IDX = 1;
+ private ServiceReference m_logRef = null;
+ private Object[] m_logger = null;
+
+ public Logger(BundleContext context) {
+ m_context = context;
+ startListeningForLogService();
+ }
+
+ public final void log(int level, String msg) {
+ _log(null, level, msg, null);
+ }
+
+ public final void log(int level, String msg, Throwable throwable) {
+ _log(null, level, msg, throwable);
+ }
+
+ public final void log(ServiceReference sr, int level, String msg) {
+ _log(sr, level, msg, null);
+ }
+
+ public final void log(ServiceReference sr, int level, String msg, Throwable throwable) {
+ _log(sr, level, msg, throwable);
+ }
+
+ protected void doLog(ServiceReference sr, int level, String msg, Throwable throwable) {
+ String s = (sr == null) ? null : "SvcRef " + sr;
+ s = (s == null) ? msg : s + " " + msg;
+ s = (throwable == null) ? s : s + " (" + throwable + ")";
+ switch (level) {
+ case LOG_DEBUG:
+ System.out.println("DEBUG: " + s);
+ break;
+ case LOG_ERROR:
+ System.out.println("ERROR: " + s);
+ if (throwable != null) {
+ if ((throwable instanceof BundleException) && (((BundleException) throwable).getNestedException() != null)) {
+ throwable = ((BundleException) throwable).getNestedException();
+ }
+ throwable.printStackTrace();
+ }
+ break;
+ case LOG_INFO:
+ System.out.println("INFO: " + s);
+ break;
+ case LOG_WARNING:
+ System.out.println("WARNING: " + s);
+ break;
+ default:
+ System.out.println("UNKNOWN[" + level + "]: " + s);
+ }
+ }
+
+ private void _log(ServiceReference sr, int level, String msg, Throwable throwable) {
+ // Save our own copy just in case it changes. We could try to do
+ // more conservative locking here, but let's be optimistic.
+ Object[] logger = m_logger;
+ // Use the log service if available.
+ if (logger != null) {
+ _logReflectively(logger, sr, level, msg, throwable);
+ }
+ // Otherwise, default logging action.
+ else {
+ doLog(sr, level, msg, throwable);
+ }
+ }
+
+ private void _logReflectively(Object[] logger, ServiceReference sr, int level, String msg, Throwable throwable) {
+ if (logger != null) {
+ Object[] params = { sr, new Integer(level), msg, throwable };
+ try {
+ ((Method) logger[LOGGER_METHOD_IDX]).invoke(logger[LOGGER_OBJECT_IDX], params);
+ }
+ catch (InvocationTargetException ex) {
+ System.err.println("Logger: " + ex);
+ }
+ catch (IllegalAccessException ex) {
+ System.err.println("Logger: " + ex);
+ }
+ }
+ }
+
+ /**
+ * This method is called when the bundle context is set;
+ * it simply adds a service listener so that the bundle can track
+ * log services to be used as the back end of the logging mechanism. It also
+ * attempts to get an existing log service, if present, but in general
+ * there will never be a log service present since the system bundle is
+ * started before every other bundle.
+ */
+ private synchronized void startListeningForLogService() {
+ try {
+ // add a service listener for log services, carefully avoiding any code dependency on it
+ m_context.addServiceListener(this, "(objectClass=org.osgi.service.log.LogService)");
+ }
+ catch (InvalidSyntaxException ex) {
+ // this will never happen since the filter is hard coded
+ }
+ // try to get an existing log service
+ m_logRef = m_context.getServiceReference("org.osgi.service.log.LogService");
+ // get the service object if available and set it in the logger
+ if (m_logRef != null) {
+ setLogger(m_context.getService(m_logRef));
+ }
+ }
+
+ /**
+ * This method implements the callback for the ServiceListener interface.
+ * It is public as a byproduct of implementing the interface and should
+ * not be called directly. This method tracks run-time changes to log
+ * service availability. If the log service being used by the framework's
+ * logging mechanism goes away, then this will try to find an alternative.
+ * If a higher ranking log service is registered, then this will switch
+ * to the higher ranking log service.
+ */
+ public final synchronized void serviceChanged(ServiceEvent event) {
+ // if no logger is in use, then grab this one
+ if ((event.getType() == ServiceEvent.REGISTERED) && (m_logRef == null)) {
+ m_logRef = event.getServiceReference();
+ // get the service object and set it in the logger
+ setLogger(m_context.getService(m_logRef));
+ }
+ // if a logger is in use, but this one has a higher ranking, then swap
+ // it for the existing logger
+ else if ((event.getType() == ServiceEvent.REGISTERED) && (m_logRef != null)) {
+ ServiceReference ref = m_context.getServiceReference("org.osgi.service.log.LogService");
+ if (!ref.equals(m_logRef)) {
+ m_context.ungetService(m_logRef);
+ m_logRef = ref;
+ setLogger(m_context.getService(m_logRef));
+ }
+ }
+ // if the current logger is going away, release it and try to
+ // find another one
+ else if ((event.getType() == ServiceEvent.UNREGISTERING) && m_logRef.equals(event.getServiceReference())) {
+ // Unget the service object.
+ m_context.ungetService(m_logRef);
+ // Try to get an existing log service.
+ m_logRef = m_context.getServiceReference("org.osgi.service.log.LogService");
+ // get the service object if available and set it in the logger
+ if (m_logRef != null) {
+ setLogger(m_context.getService(m_logRef));
+ }
+ else {
+ setLogger(null);
+ }
+ }
+ }
+
+ /**
+ * This method sets the new log service object. It also caches the method to
+ * invoke. The service object and method are stored in array to optimistically
+ * eliminate the need to locking when logging.
+ */
+ private void setLogger(Object logObj) {
+ if (logObj == null) {
+ m_logger = null;
+ }
+ else {
+ Class[] formalParams = { ServiceReference.class, Integer.TYPE, String.class, Throwable.class };
+ try {
+ Method logMethod = logObj.getClass().getMethod("log", formalParams);
+ logMethod.setAccessible(true);
+ m_logger = new Object[] { logObj, logMethod };
+ }
+ catch (NoSuchMethodException ex) {
+ System.err.println("Logger: " + ex);
+ m_logger = null;
+ }
+ }
+ }
+}
\ No newline at end of file
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,134 @@
+/*
+ * 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.dm.impl;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceDependency;
+
+/**
+ * Resource adapter service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual resource adapter service implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResourceAdapterServiceImpl extends FilterService {
+ private Object m_callbackInstance = null;
+ private String m_callbackChanged = "changed";
+ private String m_callbackAdded = "setResource";
+
+ /**
+ * Creates a new Resource Adapter Service implementation.
+ * @param dm the dependency manager used to create our internal adapter service
+ */
+ public ResourceAdapterServiceImpl(DependencyManager dm, String resourceFilter, boolean propagate, Object callbackInstance, String callbackSet, String callbackChanged) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_callbackInstance = callbackInstance;
+ m_callbackAdded = callbackSet;
+ m_callbackChanged = callbackChanged;
+ m_component.setImplementation(new ResourceAdapterImpl(propagate))
+ .add(dm.createResourceDependency()
+ .setFilter(resourceFilter)
+ .setAutoConfig(false)
+ .setCallbacks("added", "removed"));
+ }
+
+ public ResourceAdapterServiceImpl(DependencyManager dm, String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackSet, String callbackChanged) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_callbackInstance = callbackInstance;
+ m_callbackAdded = callbackSet;
+ m_callbackChanged = callbackChanged;
+ m_component.setImplementation(new ResourceAdapterImpl(propagateCallbackInstance, propagateCallbackMethod))
+ .add(dm.createResourceDependency()
+ .setFilter(resourceFilter)
+ .setAutoConfig(false)
+ .setCallbacks("added", "removed"));
+ }
+
+ public class ResourceAdapterImpl extends AbstractDecorator {
+ private final boolean m_propagate;
+ private final Object m_propagateCallbackInstance;
+ private final String m_propagateCallbackMethod;
+
+ public ResourceAdapterImpl(boolean propagate) {
+ this(propagate, null, null);
+ }
+
+ public ResourceAdapterImpl(Object propagateCallbackInstance, String propagateCallbackMethod) {
+ this(true, propagateCallbackInstance, propagateCallbackMethod);
+ }
+
+ private ResourceAdapterImpl(boolean propagate, Object propagateCallbackInstance, String propagateCallbackMethod) {
+ m_propagate = propagate;
+ m_propagateCallbackInstance = propagateCallbackInstance;
+ m_propagateCallbackMethod = propagateCallbackMethod;
+ }
+
+ public Component createService(Object[] properties) {
+ URL resource = (URL) properties[0];
+ Properties props = new Properties();
+ if (m_serviceProperties != null) {
+ Enumeration e = m_serviceProperties.keys();
+ while (e.hasMoreElements()) {
+ Object key = e.nextElement();
+ props.put(key, m_serviceProperties.get(key));
+ }
+ }
+ List dependencies = m_component.getDependencies();
+ // the first dependency is always the dependency on the resource, which
+ // will be replaced with a more specific dependency below
+ dependencies.remove(0);
+ ResourceDependency resourceDependency = m_manager.createResourceDependency()
+ .setResource(resource)
+ .setCallbacks(m_callbackInstance, m_callbackAdded, m_callbackChanged, null)
+ .setAutoConfig(m_callbackAdded == null)
+ .setRequired(true);
+ if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+ resourceDependency.setPropagate(m_propagateCallbackInstance, m_propagateCallbackMethod);
+ } else {
+ resourceDependency.setPropagate(m_propagate);
+ }
+ Component service = m_manager.createComponent()
+ .setInterface(m_serviceInterfaces, props)
+ .setImplementation(m_serviceImpl)
+ .setFactory(m_factory, m_factoryCreateMethod) // if not set, no effect
+ .setComposition(m_compositionInstance, m_compositionMethod) // if not set, no effect
+ .setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy) // if not set, no effect
+ .add(resourceDependency);
+
+ configureAutoConfigState(service, m_component);
+
+ for (int i = 0; i < dependencies.size(); i++) {
+ service.add(((Dependency) dependencies.get(i)).createCopy());
+ }
+
+ for (int i = 0; i < m_stateListeners.size(); i ++) {
+ service.addStateListener((ComponentStateListener) m_stateListeners.get(i));
+ }
+ return service;
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,87 @@
+/*
+ * 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.dm.impl;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+/**
+ * Allows you to enqueue tasks from multiple threads and then execute
+ * them on one thread sequentially. It assumes more than one thread will
+ * try to execute the tasks and it will make an effort to pick the first
+ * task that comes along whilst making sure subsequent tasks return
+ * without waiting.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class SerialExecutor {
+ private final LinkedList m_workQueue = new LinkedList();
+ private Runnable m_active;
+
+ /**
+ * Enqueue a new task for later execution. This method is
+ * thread-safe, so multiple threads can contribute tasks.
+ *
+ * @param runnable the runnable containing the actual task
+ */
+ public synchronized void enqueue(final Runnable runnable) {
+ m_workQueue.addLast(new Runnable() {
+ public void run() {
+ try {
+ runnable.run();
+ }
+ finally {
+ scheduleNext();
+ }
+ }
+ });
+ }
+
+ /**
+ * Execute any pending tasks. This method is thread safe,
+ * so multiple threads can try to execute the pending
+ * tasks, but only the first will be used to actually do
+ * so. Other threads will return immediately.
+ */
+ public void execute() {
+ Runnable active;
+ synchronized (this) {
+ active = m_active;
+ }
+ if (active == null) {
+ scheduleNext();
+ }
+ }
+
+ private void scheduleNext() {
+ Runnable active;
+ synchronized (this) {
+ try {
+ m_active = (Runnable) m_workQueue.removeFirst();
+ }
+ catch (NoSuchElementException e) {
+ m_active = null;
+ }
+ active = m_active;
+ }
+ if (active != null) {
+ active.run();
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,98 @@
+/*
+ * 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.dm.impl;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * A wrapper around a service registration that blocks until the
+ * service registration is available.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class ServiceRegistrationImpl implements ServiceRegistration {
+ public static final ServiceRegistrationImpl ILLEGAL_STATE = new ServiceRegistrationImpl();
+ private volatile ServiceRegistration m_registration;
+
+ public ServiceRegistrationImpl() {
+ m_registration = null;
+ }
+
+ public ServiceReference getReference() {
+ return ensureRegistration().getReference();
+ }
+
+ public void setProperties(Dictionary dictionary) {
+ ensureRegistration().setProperties(dictionary);
+ }
+
+ public void unregister() {
+ ensureRegistration().unregister();
+ }
+
+ public boolean equals(Object obj) {
+ return ensureRegistration().equals(obj);
+ }
+
+ public int hashCode() {
+ return ensureRegistration().hashCode();
+ }
+
+ public String toString() {
+ return ensureRegistration().toString();
+ }
+
+ private synchronized ServiceRegistration ensureRegistration() {
+ while (m_registration == null) {
+ try {
+ wait();
+ }
+ catch (InterruptedException ie) {
+ // we were interrupted so hopefully we will now have a
+ // service registration ready; if not we wait again
+ }
+ }
+ // check if we're in an illegal state and throw an exception
+ if (ILLEGAL_STATE == m_registration) {
+ throw new IllegalStateException("Service is not registered.");
+ }
+ return m_registration;
+ }
+
+ /**
+ * Sets the service registration and notifies all waiting parties.
+ */
+ void setServiceRegistration(ServiceRegistration registration) {
+ synchronized (this) {
+ m_registration = registration;
+ notifyAll();
+ }
+ }
+
+ /**
+ * Sets this wrapper to an illegal state, which will cause all threads
+ * that are waiting for this service registration to fail.
+ */
+ void setIllegalState() {
+ setServiceRegistration(ServiceRegistrationImpl.ILLEGAL_STATE);
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,133 @@
+/*
+ * 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.dm.impl;
+
+import java.util.List;
+
+import org.apache.felix.dm.Dependency;
+
+/**
+ * Encapsulates the current state of the dependencies of a service. A state is
+ * basically an immutable value object.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class State {
+ private static final String[] STATES = { "?", "inactive", "waiting for required", "tracking optional", "bound", "waiting for required (instantiated)" };
+ private static final int INACTIVE = 1;
+ private static final int WAITING_FOR_REQUIRED = 2;
+ private static final int TRACKING_OPTIONAL = 3;
+ private static final int BOUND = 4;
+ private static final int WAITING_FOR_REQUIRED_INSTANTIATED = 5;
+ private final List m_deps;
+ private final int m_state;
+ private String m_stringValue;
+
+ /**
+ * Creates a new state instance.
+ *
+ * @param deps the dependencies that determine the state
+ * @param isActive <code>true</code> if the service is active (started)
+ */
+ public State(List deps, boolean isActive, boolean isInstantiated, boolean isBound /* unused? */) {
+ m_deps = deps;
+ // only bother calculating dependencies if we're active
+ if (isActive) {
+ boolean allRequiredAvailable = true;
+ boolean keepInstanceAround = isInstantiated;
+ for (int i = 0; i < deps.size(); i++) {
+ Dependency dep = (Dependency) deps.get(i);
+ if (dep.isRequired()) {
+ if (!dep.isAvailable()) {
+ allRequiredAvailable = false;
+ if (!dep.isInstanceBound()) {
+ keepInstanceAround = false;
+ }
+ }
+ }
+ }
+ if (allRequiredAvailable) {
+ if (isInstantiated) {
+ m_state = BOUND;
+ }
+ else {
+ m_state = TRACKING_OPTIONAL;
+ }
+ }
+ else {
+ if (keepInstanceAround) {
+ m_state = WAITING_FOR_REQUIRED_INSTANTIATED;
+ }
+ else {
+ m_state = WAITING_FOR_REQUIRED;
+ }
+ }
+ }
+ else {
+ m_state = INACTIVE;
+ }
+ }
+
+ public boolean isInactive() {
+ return m_state == INACTIVE;
+ }
+
+ public boolean isWaitingForRequired() {
+ return m_state == WAITING_FOR_REQUIRED;
+ }
+
+ public boolean isTrackingOptional() {
+ return m_state == TRACKING_OPTIONAL;
+ }
+
+ public boolean isBound() {
+ return m_state == BOUND;
+ }
+
+ public boolean isAllRequiredAvailable() {
+ return isTrackingOptional() || isBound();
+ }
+
+ public boolean isWaitingForRequiredInstantiated() {
+ return m_state == WAITING_FOR_REQUIRED_INSTANTIATED;
+ }
+
+ public List getDependencies() {
+ return m_deps;
+ }
+
+ public synchronized String toString() {
+ if (m_stringValue == null) {
+ // we only need to determine this once, but we do it lazily
+ StringBuffer buf = new StringBuffer();
+ buf.append("State[" + STATES[m_state]);
+ List deps = m_deps;
+ for (int i = 0; i < deps.size(); i++) {
+ if (i == 0) {
+ buf.append("|");
+ }
+ Dependency dep = (Dependency) deps.get(i);
+ buf.append("(" + (dep.isRequired() ? "Req " : " ") + (dep.isAvailable() ? "Avl " : " ") + (dep.isInstanceBound() ? "InB " : " ") + (dep.isPropagated() ? "Prp " : " ") + dep + ")");
+ }
+ buf.append("]");
+ m_stringValue = buf.toString();
+ }
+ return m_stringValue;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,501 @@
+/*
+ * 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.dm.impl.dependencies;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.dm.BundleDependency;
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.impl.DefaultNullObject;
+import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.tracker.BundleTracker;
+import org.apache.felix.dm.tracker.BundleTrackerCustomizer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleDependencyImpl extends DependencyBase implements BundleDependency, BundleTrackerCustomizer, ComponentDependencyDeclaration {
+ private final BundleContext m_context;
+ private BundleTracker m_tracker;
+ private int m_stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
+ private List m_services = new ArrayList();
+ private boolean m_isAvailable;
+ private Object m_callbackInstance;
+ private String m_callbackAdded;
+ private String m_callbackChanged;
+ private String m_callbackRemoved;
+ private boolean m_autoConfig;
+ private Bundle m_bundleInstance;
+ private Filter m_filter;
+ private long m_bundleId = -1;
+ private String m_autoConfigInstance;
+ private Object m_nullObject;
+ private boolean m_autoConfigInvoked;
+ private boolean m_propagate;
+ private Object m_propagateCallbackInstance;
+ private String m_propagateCallbackMethod;
+
+ public BundleDependencyImpl(BundleContext context, Logger logger) {
+ super(logger);
+ m_context = context;
+ m_autoConfig = true;
+ }
+
+ public BundleDependencyImpl(BundleDependencyImpl prototype) {
+ super(prototype);
+ m_context = prototype.m_context;
+ m_autoConfig = prototype.m_autoConfig;
+ m_stateMask = prototype.m_stateMask;
+ m_nullObject = prototype.m_nullObject;
+ m_bundleInstance = prototype.m_bundleInstance;
+ m_filter = prototype.m_filter;
+ m_bundleId = prototype.m_bundleId;
+ m_propagate = prototype.m_propagate;
+ m_callbackInstance = prototype.m_callbackInstance;
+ m_callbackAdded = prototype.m_callbackAdded;
+ m_callbackChanged = prototype.m_callbackChanged;
+ m_callbackRemoved = prototype.m_callbackRemoved;
+ m_autoConfigInstance = prototype.m_autoConfigInstance;
+ }
+
+ public Dependency createCopy() {
+ return new BundleDependencyImpl(this);
+ }
+
+ public BundleDependency setInstanceBound(boolean isInstanceBound) {
+ setIsInstanceBound(isInstanceBound);
+ return this;
+ }
+
+ public synchronized boolean isAvailable() {
+ return m_isAvailable;
+ }
+
+ public void start(DependencyService service) {
+ boolean needsStarting = false;
+ synchronized (this) {
+ m_services.add(service);
+ if (!m_isStarted) {
+ m_tracker = new BundleTracker(m_context, m_stateMask, this);
+ m_isStarted = true;
+ needsStarting = true;
+ }
+ }
+ if (needsStarting) {
+ m_tracker.open();
+ }
+ }
+
+ public void stop(DependencyService service) {
+ boolean needsStopping = false;
+ synchronized (this) {
+ if (m_services.size() == 1 && m_services.contains(service)) {
+ m_isStarted = false;
+ needsStopping = true;
+ }
+ }
+ if (needsStopping) {
+ m_tracker.close();
+ m_tracker = null;
+ m_services.remove(service);
+ }
+ }
+
+ public String getName() {
+ StringBuilder sb = new StringBuilder();
+ if ((m_stateMask & Bundle.ACTIVE) != 0) {
+ sb.append("active ");
+ }
+ if ((m_stateMask & Bundle.INSTALLED) != 0) {
+ sb.append("installed ");
+ }
+ if ((m_stateMask & Bundle.RESOLVED) != 0) {
+ sb.append("resolved ");
+ }
+ if (m_filter != null) {
+ sb.append(m_filter.toString());
+ }
+ if (m_bundleId != -1) {
+ sb.append("bundle.id=" + m_bundleId);
+ }
+ return sb.toString();
+ }
+
+ public String getType() {
+ return "bundle";
+ }
+
+ public Object addingBundle(Bundle bundle, BundleEvent event) {
+ // if we don't like a bundle, we could reject it here by returning null
+ long bundleId = bundle.getBundleId();
+ if (m_bundleId >= 0 && m_bundleId != bundleId) {
+ return null;
+ }
+ Filter filter = m_filter;
+ if (filter != null) {
+ Dictionary headers = bundle.getHeaders();
+ if (!m_filter.match(headers)) {
+ return null;
+ }
+ }
+ return bundle;
+ }
+
+ public void addedBundle(Bundle bundle, BundleEvent event, Object object) {
+ boolean makeAvailable = makeAvailable();
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ if (makeAvailable) {
+ ds.dependencyAvailable(this);
+ if (!isRequired()) {
+ invokeAdded(ds, bundle);
+ }
+ }
+ else {
+ ds.dependencyChanged(this);
+ invokeAdded(ds, bundle);
+ }
+ }
+ }
+
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ ds.dependencyChanged(this);
+ if (ds.isRegistered()) {
+ invokeChanged(ds, bundle);
+ }
+ }
+ }
+
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+ boolean makeUnavailable = makeUnavailable();
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ if (makeUnavailable) {
+ ds.dependencyUnavailable(this);
+ if (!isRequired()) {
+ invokeRemoved(ds, bundle);
+ }
+ }
+ else {
+ ds.dependencyChanged(this);
+ invokeRemoved(ds, bundle);
+ }
+ }
+ }
+
+ private synchronized boolean makeAvailable() {
+ if (!isAvailable()) {
+ m_isAvailable = true;
+ return true;
+ }
+ return false;
+ }
+
+ private synchronized boolean makeUnavailable() {
+ if ((isAvailable()) && (m_tracker.getTrackingCount() == 0)) {
+ m_isAvailable = false;
+ return true;
+ }
+ return false;
+ }
+
+ public void invokeAdded(DependencyService dependencyService, Bundle service) {
+ invoke(dependencyService, service, m_callbackAdded);
+ }
+
+ public void invokeChanged(DependencyService dependencyService, Bundle service) {
+ invoke(dependencyService, service, m_callbackChanged);
+ }
+
+ public void invokeRemoved(DependencyService dependencyService, Bundle service) {
+ invoke(dependencyService, service, m_callbackRemoved);
+ }
+
+ public void invoke(DependencyService dependencyService, Bundle service, String name) {
+ if (name != null) {
+ dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
+ new Class[][] {{Bundle.class}, {Object.class}, {}},
+ new Object[][] {{service}, {service}, {}}
+ );
+ }
+ }
+
+ private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
+ if (m_callbackInstance == null) {
+ return dependencyService.getCompositionInstances();
+ }
+ else {
+ return new Object[] { m_callbackInstance };
+ }
+ }
+
+ /**
+ * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+ * dependency is added or removed. When you specify callbacks, the auto configuration
+ * feature is automatically turned off, because we're assuming you don't need it in this
+ * case.
+ *
+ * @param added the method to call when a service was added
+ * @param removed the method to call when a service was removed
+ * @return this service dependency
+ */
+ public synchronized BundleDependency setCallbacks(String added, String removed) {
+ return setCallbacks(null, added, null, removed);
+ }
+
+ /**
+ * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+ * dependency is added, changed or removed. When you specify callbacks, the auto
+ * configuration feature is automatically turned off, because we're assuming you don't
+ * need it in this case.
+ *
+ * @param added the method to call when a service was added
+ * @param changed the method to call when a service was changed
+ * @param removed the method to call when a service was removed
+ * @return this service dependency
+ */
+ public synchronized BundleDependency setCallbacks(String added, String changed, String removed) {
+ return setCallbacks(null, added, changed, removed);
+ }
+
+ /**
+ * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+ * dependency is added or removed. They are called on the instance you provide. When you
+ * specify callbacks, the auto configuration feature is automatically turned off, because
+ * we're assuming you don't need it in this case.
+ *
+ * @param instance the instance to call the callbacks on
+ * @param added the method to call when a service was added
+ * @param removed the method to call when a service was removed
+ * @return this service dependency
+ */
+ public synchronized BundleDependency setCallbacks(Object instance, String added, String removed) {
+ return setCallbacks(instance, added, null, removed);
+ }
+
+ /**
+ * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+ * dependency is added, changed or removed. They are called on the instance you provide. When you
+ * specify callbacks, the auto configuration feature is automatically turned off, because
+ * we're assuming you don't need it in this case.
+ *
+ * @param instance the instance to call the callbacks on
+ * @param added the method to call when a service was added
+ * @param changed the method to call when a service was changed
+ * @param removed the method to call when a service was removed
+ * @return this service dependency
+ */
+ public synchronized BundleDependency setCallbacks(Object instance, String added, String changed, String removed) {
+ ensureNotActive();
+ // if at least one valid callback is specified, we turn off auto configuration
+ if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
+ setAutoConfig(false);
+ }
+ m_callbackInstance = instance;
+ m_callbackAdded = added;
+ m_callbackChanged = changed;
+ m_callbackRemoved = removed;
+ return this;
+ }
+
+ private void ensureNotActive() {
+ if (m_tracker != null) {
+ throw new IllegalStateException("Cannot modify state while active.");
+ }
+ }
+ public synchronized BundleDependency setAutoConfig(boolean autoConfig) {
+ ensureNotActive();
+ m_autoConfig = autoConfig;
+ m_autoConfigInvoked = true;
+ return this;
+ }
+
+ public synchronized BundleDependency setAutoConfig(String instanceName) {
+ ensureNotActive();
+ m_autoConfig = (instanceName != null);
+ m_autoConfigInstance = instanceName;
+ m_autoConfigInvoked = true;
+ return this;
+ }
+
+ public synchronized BundleDependency setRequired(boolean required) {
+ ensureNotActive();
+ setIsRequired(required);
+ return this;
+ }
+
+ public BundleDependency setBundle(Bundle bundle) {
+ m_bundleId = bundle.getBundleId();
+ return this;
+ }
+
+ public BundleDependency setFilter(String filter) throws IllegalArgumentException {
+ if (filter != null) {
+ try {
+ m_filter = m_context.createFilter(filter);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+ return this;
+ }
+
+ public BundleDependency setStateMask(int mask) {
+ m_stateMask = mask;
+ return this;
+ }
+
+ public synchronized boolean isAutoConfig() {
+ return m_autoConfig;
+ }
+
+ public Bundle getBundle() {
+ Bundle[] bundles = m_tracker.getBundles();
+ if (bundles != null && bundles.length > 0) {
+ return bundles[0];
+ }
+ return null;
+ }
+
+ public Object getAutoConfigInstance() {
+ return lookupBundle();
+ }
+
+ public Bundle lookupBundle() {
+ Bundle service = null;
+ if (m_isStarted) {
+ service = getBundle();
+ }
+ else {
+ Bundle[] bundles = m_context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if ((bundles[i].getState() & m_stateMask) > 0) {
+ Filter filter = m_filter;
+ if (filter == null) {
+ service = bundles[i];
+ break;
+ }
+ else if (filter.match(bundles[i].getHeaders())) {
+ service = bundles[i];
+ break;
+ }
+ }
+ }
+ }
+ if (service == null && isAutoConfig()) {
+ // TODO does it make sense to add support for custom bundle impls?
+// service = getDefaultImplementation();
+ if (service == null) {
+ service = getNullObject();
+ }
+ }
+ return service;
+ }
+
+ private Bundle getNullObject() {
+ if (m_nullObject == null) {
+ try {
+ m_nullObject = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Bundle.class }, new DefaultNullObject());
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not create null object for Bundle.", e);
+ }
+ }
+ return (Bundle) m_nullObject;
+ }
+
+ public String getAutoConfigName() {
+ return m_autoConfigInstance;
+ }
+
+ public Class getAutoConfigType() {
+ return Bundle.class;
+ }
+
+ public void invokeAdded(DependencyService service) {
+ // we remember these for future reference, needed for required service callbacks
+ m_bundleInstance = lookupBundle();
+ invokeAdded(service, m_bundleInstance);
+ }
+
+ public void invokeRemoved(DependencyService service) {
+ invokeRemoved(service, m_bundleInstance);
+ m_bundleInstance = null;
+ }
+
+ public BundleDependency setPropagate(boolean propagate) {
+ ensureNotActive();
+ m_propagate = propagate;
+ return this;
+ }
+
+ public BundleDependency setPropagate(Object instance, String method) {
+ setPropagate(instance != null && method != null);
+ m_propagateCallbackInstance = instance;
+ m_propagateCallbackMethod = method;
+ return this;
+ }
+
+ public Dictionary getProperties() {
+ Bundle bundle = lookupBundle();
+ if (bundle != null) {
+ if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+ try {
+ return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Bundle.class }}, new Object[][] {{ bundle }});
+ }
+ catch (InvocationTargetException e) {
+ m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+ }
+ catch (Exception e) {
+ m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+ }
+ throw new IllegalStateException("Could not invoke callback");
+ }
+ else {
+ return bundle.getHeaders();
+ }
+ }
+ else {
+ throw new IllegalStateException("cannot find bundle");
+ }
+ }
+
+ public boolean isPropagated() {
+ return m_propagate;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,401 @@
+/*
+ * 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.dm.impl.dependencies;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.ConfigurationDependency;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyActivation;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.PropertyMetaData;
+import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+/**
+ * Configuration dependency that can track the availability of a (valid) configuration.
+ * To use it, specify a PID for the configuration. The dependency is always required,
+ * because if it is not, it does not make sense to use the dependency manager. In that
+ * scenario, simply register your service as a <code>ManagedService(Factory)</code> and
+ * handle everything yourself. Also, only managed services are supported, not factories.
+ * There are a couple of things you need to be aware of when implementing the
+ * <code>updated(Dictionary)</code> method:
+ * <ul>
+ * <li>Make sure it throws a <code>ConfigurationException</code> when you get a
+ * configuration that is invalid. In this case, the dependency will not change:
+ * if it was not available, it will still not be. If it was available, it will
+ * remain available and implicitly assume you keep working with your old
+ * configuration.</li>
+ * <li>This method will be called before all required dependencies are available.
+ * Make sure you do not depend on these to parse your settings.</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConfigurationDependencyImpl extends DependencyBase implements ConfigurationDependency, ManagedService, ComponentDependencyDeclaration, DependencyActivation {
+ private BundleContext m_context;
+ private String m_pid;
+ private ServiceRegistration m_registration;
+ protected List m_services = new ArrayList();
+ private Dictionary m_settings;
+ private String m_callback;
+ private final Set m_updateInvokedCache = new HashSet();
+ private MetaTypeProviderImpl m_metaType;
+ private boolean m_propagate;
+ private Object m_propagateCallbackInstance;
+ private String m_propagateCallbackMethod;
+
+ public ConfigurationDependencyImpl(BundleContext context, Logger logger) {
+ super(logger);
+ m_context = context;
+ }
+
+ public ConfigurationDependencyImpl(ConfigurationDependencyImpl prototype) {
+ super(prototype);
+ m_context = prototype.m_context;
+ m_pid = prototype.m_pid;
+ m_propagate = prototype.m_propagate;
+ m_callback = prototype.m_callback;
+ }
+
+ public Dependency createCopy() {
+ return new ConfigurationDependencyImpl(this);
+ }
+
+ public synchronized boolean isAvailable() {
+ return m_settings != null;
+ }
+
+ /**
+ * Will always return <code>true</code> as optional configuration dependencies
+ * do not make sense. You might as well just implement <code>ManagedService</code>
+ * yourself in those cases.
+ */
+ public boolean isRequired() {
+ return true;
+ }
+
+ /**
+ * Returns <code>true</code> when configuration properties should be propagated
+ * as service properties.
+ */
+ public boolean isPropagated() {
+ return m_propagate;
+ }
+
+ public ConfigurationDependency setInstanceBound(boolean isInstanceBound) {
+ setIsInstanceBound(isInstanceBound);
+ return this;
+ }
+
+
+ public Dictionary getConfiguration() {
+ return m_settings;
+ }
+
+ public void start(DependencyService service) {
+ boolean needsStarting = false;
+ synchronized (this) {
+ m_services.add(service);
+ if (!m_isStarted) {
+ m_isStarted = true;
+ needsStarting = true;
+ }
+ }
+ if (needsStarting) {
+ Properties props = new Properties();
+ props.put(Constants.SERVICE_PID, m_pid);
+ ManagedService ms = this;
+ if (m_metaType != null) {
+ ms = m_metaType;
+ }
+ m_registration = m_context.registerService(ManagedService.class.getName(), ms, props);
+ }
+ }
+
+ public void stop(DependencyService service) {
+ boolean needsStopping = false;
+ synchronized (this) {
+ if (m_services.size() == 1 && m_services.contains(service)) {
+ m_isStarted = false;
+ needsStopping = true;
+ }
+ }
+ if (needsStopping) {
+ m_registration.unregister();
+ m_registration = null;
+ m_services.remove(service);
+ }
+ }
+
+ public ConfigurationDependency setCallback(String callback) {
+ m_callback = callback;
+ return this;
+ }
+
+ public void updated(Dictionary settings) throws ConfigurationException {
+ synchronized (m_updateInvokedCache) {
+ m_updateInvokedCache.clear();
+ }
+ Dictionary oldSettings = null;
+ synchronized (this) {
+ oldSettings = m_settings;
+ }
+
+ if (oldSettings == null && settings == null) {
+ // CM has started but our configuration is not still present in the CM database: ignore
+ return;
+ }
+
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ // if non-null settings come in, we have to instantiate the service and
+ // apply these settings
+ ds.initService();
+ Object service = ds.getService();
+
+ if (service != null) {
+ invokeUpdate(ds, service, settings);
+ }
+ else {
+ m_logger.log(Logger.LOG_ERROR, "Service " + ds + " with configuration dependency " + this + " could not be instantiated.");
+ return;
+ }
+ }
+
+ synchronized (this) {
+ m_settings = settings;
+ }
+
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ // If these settings did not cause a configuration exception, we determine if they have
+ // caused the dependency state to change
+ if ((oldSettings == null) && (settings != null)) {
+ ds.dependencyAvailable(this);
+ }
+ if ((oldSettings != null) && (settings == null)) {
+ ds.dependencyUnavailable(this);
+ }
+ if ((oldSettings != null) && (settings != null)) {
+ ds.dependencyChanged(this);
+ }
+ }
+ }
+
+ public void invokeUpdate(DependencyService ds, Object service, Dictionary settings) throws ConfigurationException {
+ boolean wasAdded;
+ synchronized (m_updateInvokedCache) {
+ wasAdded = m_updateInvokedCache.add(ds);
+ }
+ if (wasAdded) {
+ String callback = (m_callback == null) ? "updated" : m_callback;
+ try {
+ // if exception is thrown here, what does that mean for the
+ // state of this dependency? how smart do we want to be??
+ // it's okay like this, if the new settings contain errors, we
+ // remain in the state we were, assuming that any error causes
+ // the "old" configuration to stay in effect.
+ // CM will log any thrown exceptions.
+ InvocationUtil.invokeCallbackMethod(service, callback, new Class[][] {{ Dictionary.class }}, new Object[][] {{ settings }});
+ }
+ catch (InvocationTargetException e) {
+ // The component has thrown an exception during it's callback invocation.
+ if (e.getTargetException() instanceof ConfigurationException) {
+ // the callback threw an OSGi ConfigurationException: just re-throw it.
+ throw (ConfigurationException) e.getTargetException();
+ }
+ else {
+ // wrap the callback exception into a ConfigurationException.
+ throw new ConfigurationException(null, "Service " + ds + " with " + this.toString() + " could not be updated", e.getTargetException());
+ }
+ }
+ catch (NoSuchMethodException e) {
+ // if the method does not exist, ignore it
+ }
+ catch (Throwable t) {
+ // wrap any other exception as a ConfigurationException.
+ throw new ConfigurationException(null, "Service " + ds + " with " + this.toString() + " could not be updated", t);
+ }
+ }
+ }
+
+ /**
+ * Sets the <code>service.pid</code> of the configuration you
+ * are depending on.
+ */
+ public ConfigurationDependency setPid(String pid) {
+ ensureNotActive();
+ m_pid = pid;
+ return this;
+ }
+
+ /**
+ * Sets propagation of the configuration properties to the service
+ * properties. Any additional service properties specified directly
+ * are merged with these.
+ */
+ public ConfigurationDependency setPropagate(boolean propagate) {
+ ensureNotActive();
+ m_propagate = propagate;
+ return this;
+ }
+
+ private void ensureNotActive() {
+ if (m_services != null && m_services.size() > 0) {
+ throw new IllegalStateException("Cannot modify state while active.");
+ }
+ }
+
+ public String toString() {
+ return "ConfigurationDependency[" + m_pid + "]";
+ }
+
+ public String getName() {
+ return m_pid;
+ }
+
+ public String getType() {
+ return "configuration";
+ }
+
+ public Object getAutoConfigInstance() {
+ return getConfiguration();
+ }
+
+ public String getAutoConfigName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Class getAutoConfigType() {
+ return Dictionary.class;
+ }
+
+ public void invokeAdded(DependencyService service) {
+ try {
+ invokeUpdate(service, service.getService(), getConfiguration());
+ }
+ catch (ConfigurationException e) {
+ // if this happens, it's definitely an inconsistency, since we
+ // asked the instance the same question before (if this is a
+ // valid configuration) and then it was
+ e.printStackTrace();
+ }
+ }
+
+ public void invokeRemoved(DependencyService service) {
+ synchronized (m_updateInvokedCache) {
+ m_updateInvokedCache.remove(service);
+ }
+ }
+
+ public boolean isAutoConfig() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public ConfigurationDependency setPropagate(Object instance, String method) {
+ setPropagate(instance != null && method != null);
+ m_propagateCallbackInstance = instance;
+ m_propagateCallbackMethod = method;
+ return this;
+ }
+
+ public Dictionary getProperties() {
+ Dictionary config = getConfiguration();
+ if (config != null) {
+ if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+ try {
+ return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Dictionary.class }, {}}, new Object[][] {{ config }, {}});
+ }
+ catch (InvocationTargetException e) {
+ m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+ }
+ catch (Exception e) {
+ m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+ }
+ throw new IllegalStateException("Could not invoke callback");
+ }
+ else {
+ return config;
+ }
+ }
+ else {
+ throw new IllegalStateException("cannot find configuration");
+ }
+ }
+
+ public BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ public Logger getLogger() {
+ return m_logger;
+ }
+
+ public ConfigurationDependency add(PropertyMetaData properties)
+ {
+ createMetaTypeImpl();
+ m_metaType.add(properties);
+ return this;
+ }
+
+ public ConfigurationDependency setDescription(String description)
+ {
+ createMetaTypeImpl();
+ m_metaType.setDescription(description);
+ return this;
+ }
+
+ public ConfigurationDependency setHeading(String heading)
+ {
+ createMetaTypeImpl();
+ m_metaType.setName(heading);
+ return this;
+ }
+
+ public ConfigurationDependency setLocalization(String path)
+ {
+ createMetaTypeImpl();
+ m_metaType.setLocalization(path);
+ return this;
+ }
+
+ private synchronized void createMetaTypeImpl() {
+ if (m_metaType == null) {
+ m_metaType = new MetaTypeProviderImpl(getName(), getBundleContext(), getLogger(), this, null);
+ }
+ }
+}