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 [3/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/AbstractDecorator.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,275 @@
+/*
+ * 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.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbstractDecorator {
+ protected volatile DependencyManager m_manager;
+ private final Map m_services = new HashMap();
+
+ public abstract Component createService(Object[] properties);
+
+ /**
+ * Catches our DependencyManager handle from our component init method.
+ */
+ public void init(Component c) {
+ m_manager = c.getDependencyManager();
+ }
+
+ /**
+ * Extra method, which may be used by sub-classes, when adaptee has changed.
+ * For now, it's only used by the FactoryConfigurationAdapterImpl class,
+ * but it might also make sense to use this for Resource Adapters ...
+ */
+ public void updateService(Object[] properties) {
+ throw new NoSuchMethodError("Method updateService not implemented");
+ }
+
+ /**
+ * Set some service properties to all already instantiated services.
+ */
+ public void setServiceProperties(Dictionary serviceProperties) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).setServiceProperties(serviceProperties);
+ }
+ }
+
+ /**
+ * Remove a StateListener from all already instantiated services.
+ */
+ public void addStateListener(ComponentStateListener listener) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).addStateListener(listener);
+ }
+ }
+
+ /**
+ * Remove a StateListener from all already instantiated services.
+ */
+ public void removeStateListener(ComponentStateListener listener) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).removeStateListener(listener);
+ }
+ }
+
+ /**
+ * Add a Dependency to all already instantiated services.
+ */
+ public void addDependency(Dependency d) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).add(d);
+ }
+ }
+
+ /**
+ * Add a Dependency to all already instantiated services.
+ */
+ public void addDependencies(List dependencies) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).add(dependencies);
+ }
+ }
+
+ /**
+ * Remove a Dependency from all instantiated services.
+ */
+ public void removeDependency(Dependency d) {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ }
+ for (int i = 0; i < components.length; i++) {
+ ((Component) components[i]).remove(d);
+ }
+ }
+
+ // callbacks for FactoryConfigurationAdapterImpl
+ public void updated(String pid, Dictionary properties) throws ConfigurationException {
+ try {
+ Component service;
+ synchronized (m_services) {
+ service = (Component) m_services.get(pid);
+ }
+ if (service == null) {
+ service = createService(new Object[] { properties });
+ synchronized (m_services) {
+ m_services.put(pid, service);
+ }
+ m_manager.add(service);
+ }
+ else {
+ updateService(new Object[] { properties, service });
+ }
+ }
+ catch (Throwable t) {
+ if (t instanceof ConfigurationException) {
+ throw (ConfigurationException) t;
+ }
+ else if (t.getCause() instanceof ConfigurationException) {
+ throw (ConfigurationException) t.getCause();
+ }
+ else {
+ throw new ConfigurationException(null, "Could not create service for ManagedServiceFactory Pid " + pid, t);
+ }
+ }
+ }
+
+ public void deleted(String pid) {
+ Component service = null;
+ synchronized (m_services) {
+ service = (Component) m_services.remove(pid);
+ }
+ if (service != null) {
+ m_manager.remove(service);
+ }
+ }
+
+ // callbacks for resources
+ public void added(URL resource) {
+ Component newService = createService(new Object[] { resource });
+ synchronized (m_services) {
+ m_services.put(resource, newService);
+ }
+ m_manager.add(newService);
+ }
+
+ public void removed(URL resource) {
+ Component newService;
+ synchronized (m_services) {
+ newService = (Component) m_services.remove(resource);
+ }
+ if (newService == null) {
+ throw new IllegalStateException("Service should not be null here.");
+ }
+ m_manager.remove(newService);
+ }
+
+ // callbacks for services
+ public void added(ServiceReference ref, Object service) {
+ Component newService = createService(new Object[] { ref, service });
+ synchronized (m_services) {
+ m_services.put(ref, newService);
+ }
+ m_manager.add(newService);
+ }
+
+ public void removed(ServiceReference ref, Object service) {
+ Component newService;
+ synchronized (m_services) {
+ newService = (Component) m_services.remove(ref);
+ }
+ if (newService == null) {
+ throw new IllegalStateException("Service should not be null here.");
+ }
+ m_manager.remove(newService);
+ }
+
+ public void swapped(ServiceReference oldRef, Object oldService, ServiceReference newRef, Object newService) {
+ synchronized (m_services) {
+ Component service = (Component) m_services.remove(oldRef);
+ m_services.put(newRef, service);
+ }
+ }
+
+ // callbacks for bundles
+ public void added(Bundle bundle) {
+ Component newService = createService(new Object[] { bundle });
+ synchronized (m_services) {
+ m_services.put(bundle, newService);
+ }
+ m_manager.add(newService);
+ }
+
+ public void removed(Bundle bundle) {
+ Component newService;
+ synchronized (m_services) {
+ newService = (Component) m_services.remove(bundle);
+ }
+ if (newService == null) {
+ throw new IllegalStateException("Service should not be null here.");
+ }
+ m_manager.remove(newService);
+ }
+
+ public void stop() {
+ Object[] components;
+ synchronized (m_services) {
+ components = m_services.values().toArray();
+ m_services.clear();
+ }
+ for (int i = 0; i < components.length; i++) {
+ m_manager.remove((Component) components[i]);
+ }
+ }
+
+ public void configureAutoConfigState(Component target, Component source) {
+ configureAutoConfigState(target, source, BundleContext.class);
+ configureAutoConfigState(target, source, ServiceRegistration.class);
+ configureAutoConfigState(target, source, DependencyManager.class);
+ configureAutoConfigState(target, source, Component.class);
+ }
+
+ private void configureAutoConfigState(Component target, Component source, Class clazz) {
+ String name = source.getAutoConfigInstance(clazz);
+ if (name != null) {
+ target.setAutoConfig(clazz, name);
+ }
+ else {
+ target.setAutoConfig(clazz, source.getAutoConfig(clazz));
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,143 @@
+/*
+ * 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.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.ServiceDependency;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * 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 AdapterServiceImpl extends FilterService {
+ /**
+ * Creates a new Adapter Service implementation.
+ *
+ * @param dm the dependency manager used to create our internal adapter service
+ * @param adapteeInterface the service interface to apply the adapter to
+ * @param adapteeFilter the filter condition to use with the service interface
+ * @param add
+ * @param change
+ * @param remove
+ */
+ public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, swap))
+ .add(dm.createServiceDependency()
+ .setService(adapteeInterface, adapteeFilter)
+ .setAutoConfig(false)
+ .setCallbacks("added", null, "removed", "swapped"));
+ }
+
+ public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, null))
+ .add(dm.createServiceDependency()
+ .setService(adapteeInterface, adapteeFilter)
+ .setAutoConfig(false)
+ .setCallbacks("added", null, "removed", "swapped"));
+ }
+
+ public class AdapterImpl extends AbstractDecorator {
+ private final Class m_adapteeInterface;
+ private final String m_adapteeFilter;
+ private final String m_add;
+ private final String m_change;
+ private final String m_remove;
+ private final String m_swap;
+ private final String m_autoConfig;
+
+ public AdapterImpl(Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+ m_adapteeInterface = adapteeInterface;
+ m_adapteeFilter = adapteeFilter;
+ m_autoConfig = autoConfig;
+ m_add = add;
+ m_change = change;
+ m_swap = swap;
+ m_remove = remove;
+ }
+
+ public Component createService(Object[] properties) {
+ ServiceReference ref = (ServiceReference) properties[0];
+ Properties props = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
+ // do not copy these
+ }
+ else {
+ props.put(key, ref.getProperty(key));
+ }
+ }
+ 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();
+ dependencies.remove(0);
+ ServiceDependency dependency = m_manager.createServiceDependency()
+ // create a dependency on both the service id we're adapting and possible aspects for this given service id
+ .setService(m_adapteeInterface, "(|(" + Constants.SERVICE_ID + "=" + ref.getProperty(Constants.SERVICE_ID)
+ + ")(" + DependencyManager.ASPECT + "=" + ref.getProperty(Constants.SERVICE_ID) + "))")
+ .setRequired(true);
+ if (m_autoConfig != null) {
+ dependency.setAutoConfig(m_autoConfig);
+ }
+ if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
+ dependency.setCallbacks(m_add, m_change, m_remove, m_swap);
+ }
+
+ 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(dependency);
+
+ 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;
+ }
+ public String toString() {
+ return "Adapter for " + m_adapteeInterface + ((m_adapteeFilter != null) ? " with filter " + m_adapteeFilter : "");
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,166 @@
+/*
+ * 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.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.ServiceDependency;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Aspect Service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual aspect service implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AspectServiceImpl extends FilterService {
+ public AspectServiceImpl(DependencyManager dm, Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove)
+ {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_component.setImplementation(new AspectImpl(aspectInterface, aspectFilter, ranking, autoConfig, add, change, remove))
+ .add(dm.createServiceDependency()
+ .setService(aspectInterface, createDependencyFilterForAspect(aspectFilter))
+ .setAutoConfig(false)
+ .setCallbacks("added", "removed"));
+ }
+
+ private String createDependencyFilterForAspect(String filter) {
+ // we only want to match services which are not themselves aspects
+ if (filter == null || filter.length() == 0) {
+ return "(!(" + DependencyManager.ASPECT + "=*))";
+ }
+ else {
+ return "(&(!(" + DependencyManager.ASPECT + "=*))" + filter + ")";
+ }
+ }
+
+ /**
+ * This class is the Aspect Implementation. It will create the actual Aspect Service, and
+ * will use the Aspect Service parameters provided by our enclosing class.
+ */
+ class AspectImpl extends AbstractDecorator {
+ private final Class m_aspectInterface; // the service decorated by this aspect
+ private final String m_aspectFilter; // the service filter decorated by this aspect
+ private final int m_ranking; // the aspect ranking
+ private final String m_autoConfig; // the aspect impl field name where to inject decorated service
+ private final String m_add;
+ private final String m_change;
+ private final String m_remove;
+
+ public AspectImpl(Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove) {
+ m_aspectInterface = aspectInterface;
+ m_aspectFilter = aspectFilter;
+ m_ranking = ranking;
+ m_autoConfig = autoConfig;
+ m_add = add;
+ m_change = change;
+ m_remove = remove;
+ }
+
+ public Component createService(Object[] params) {
+ List dependencies = m_component.getDependencies();
+ // remove our internal dependency
+ dependencies.remove(0);
+ // replace it with one that points to the specific service that just was passed in
+ Properties serviceProperties = getServiceProperties(params);
+ String[] serviceInterfaces = getServiceInterfaces();
+ ServiceReference ref = (ServiceReference) params[0];
+ ServiceDependency dependency = m_manager.createServiceDependency().setService(m_aspectInterface, createAspectFilter(ref)).setRequired(true);
+ if (m_autoConfig != null) {
+ dependency.setAutoConfig(m_autoConfig);
+ }
+ if (m_add != null || m_change != null || m_remove != null) {
+ dependency.setCallbacks(m_add, m_change, m_remove);
+ }
+ Component service = m_manager.createComponent()
+ .setInterface(serviceInterfaces, serviceProperties)
+ .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(dependency);
+
+ 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;
+ }
+
+ private Properties getServiceProperties(Object[] params) {
+ ServiceReference ref = (ServiceReference) params[0];
+ Properties props = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
+ // do not copy these
+ }
+ else {
+ props.put(key, ref.getProperty(key));
+ }
+ }
+ if (m_serviceProperties != null) {
+ Enumeration e = m_serviceProperties.keys();
+ while (e.hasMoreElements()) {
+ Object key = e.nextElement();
+ props.put(key, m_serviceProperties.get(key));
+ }
+ }
+ // finally add our aspect property
+ props.put(DependencyManager.ASPECT, ref.getProperty(Constants.SERVICE_ID));
+ // and the ranking
+ props.put(Constants.SERVICE_RANKING, Integer.valueOf(m_ranking));
+ return props;
+ }
+
+ private String[] getServiceInterfaces() {
+ List serviceNames = new ArrayList();
+ // Of course, we provide the aspect interface.
+ serviceNames.add(m_aspectInterface.getName());
+ // But also append additional aspect implementation interfaces.
+ if (m_serviceInterfaces != null) {
+ for (int i = 0; i < m_serviceInterfaces.length; i ++) {
+ if (!m_serviceInterfaces[i].equals(m_aspectInterface.getName())) {
+ serviceNames.add(m_serviceInterfaces[i]);
+ }
+ }
+ }
+ return (String[]) serviceNames.toArray(new String[serviceNames.size()]);
+ }
+
+ private String createAspectFilter(ServiceReference ref) {
+ Long sid = (Long) ref.getProperty(Constants.SERVICE_ID);
+ return "(&(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=" + (m_ranking - 1) + "))(|(" + Constants.SERVICE_ID + "=" + sid + ")(" + DependencyManager.ASPECT + "=" + sid + ")))";
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,102 @@
+/*
+ * 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.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.osgi.framework.Bundle;
+
+/**
+ * Bundle 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 BundleAdapterServiceImpl extends FilterService
+{
+ /**
+ * Creates a new Bundle Adapter Service implementation.
+ */
+ public BundleAdapterServiceImpl(DependencyManager dm, int bundleStateMask, String bundleFilter, boolean propagate)
+ {
+ super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+ m_component.setImplementation(new BundleAdapterImpl(bundleStateMask, bundleFilter, propagate))
+ .add(dm.createBundleDependency()
+ .setFilter(bundleFilter)
+ .setStateMask(bundleStateMask)
+ .setCallbacks("added", "removed"));
+ }
+
+ public class BundleAdapterImpl extends AbstractDecorator {
+ private final boolean m_propagate;
+ private final int m_bundleStateMask;
+ private final String m_bundleFilter;
+
+ public BundleAdapterImpl(int bundleStateMask, String bundleFilter, boolean propagate) {
+ m_bundleStateMask = bundleStateMask;
+ m_bundleFilter = bundleFilter;
+ m_propagate = propagate;
+ }
+
+ public Component createService(Object[] properties) {
+ Bundle bundle = (Bundle) 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 bundle, which
+ // will be replaced with a more specific dependency below
+ dependencies.remove(0);
+ 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(m_manager.createBundleDependency()
+ .setBundle(bundle)
+ .setStateMask(m_bundleStateMask)
+ .setPropagate(m_propagate)
+ .setCallbacks(null, "changed", null)
+ .setAutoConfig(true)
+ .setRequired(true));
+
+ 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));
+ }
+ configureAutoConfigState(service, m_component);
+ return service;
+ }
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,1165 @@
+/*
+ * 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.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+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.DependencyActivation;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Component implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentImpl implements Component, DependencyService, ComponentDeclaration, Comparable {
+ private static final Class[] VOID = new Class[] {};
+ private static final ServiceRegistration NULL_REGISTRATION;
+ private static final ComponentStateListener[] SERVICE_STATE_LISTENER_TYPE = new ComponentStateListener[] {};
+ private static long HIGHEST_ID = 0;
+
+ private final Object SYNC = new Object();
+ private final BundleContext m_context;
+ private final DependencyManager m_manager;
+ private final long m_id;
+
+ // configuration (static)
+ private String m_callbackInit;
+ private String m_callbackStart;
+ private String m_callbackStop;
+ private String m_callbackDestroy;
+ private Object m_serviceName;
+ private Object m_implementation;
+ private Object m_callbackInstance;
+
+ // configuration (dynamic, but does not affect state)
+ private Dictionary m_serviceProperties;
+
+ // configuration (dynamic, and affects state)
+ private ArrayList m_dependencies = new ArrayList();
+
+ // runtime state (calculated from dependencies)
+ private State m_state;
+
+ // runtime state (changes because of state changes)
+ private Object m_serviceInstance;
+ private volatile ServiceRegistration m_registration;
+ private boolean m_isBound;
+ private boolean m_isInstantiated;
+
+ // service state listeners
+ private final List m_stateListeners = new ArrayList();
+
+ // work queue
+ private final SerialExecutor m_executor = new SerialExecutor();
+
+ // instance factory
+ private Object m_instanceFactory;
+ private String m_instanceFactoryCreateMethod;
+
+ // composition manager
+ private Object m_compositionManager;
+ private String m_compositionManagerGetMethod;
+ private Object m_compositionManagerInstance;
+
+ // internal logging
+ private final Logger m_logger;
+
+ private Map m_autoConfig = new HashMap();
+ private Map m_autoConfigInstance = new HashMap();
+
+ private boolean m_isStarted = false;
+
+ public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
+ synchronized (VOID) {
+ m_id = HIGHEST_ID++;
+ }
+ m_logger = logger;
+ m_state = new State((List) m_dependencies.clone(), false, false, false);
+ m_context = context;
+ m_manager = manager;
+ m_callbackInit = "init";
+ m_callbackStart = "start";
+ m_callbackStop = "stop";
+ m_callbackDestroy = "destroy";
+ m_implementation = null;
+ m_autoConfig.put(BundleContext.class, Boolean.TRUE);
+ m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
+ m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
+ m_autoConfig.put(Component.class, Boolean.TRUE);
+ }
+
+ private void calculateStateChanges() {
+ // see if any of the things we did caused a further change of state
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ }
+
+ private void calculateStateChanges(final State oldState, final State newState) {
+ if (oldState.isInactive() && (newState.isTrackingOptional())) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ activateService(newState);
+ }});
+ }
+ if (oldState.isInactive() && (newState.isWaitingForRequired())) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ startTrackingRequired(newState);
+ }});
+ }
+ if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ activateService(newState);
+ }});
+ }
+ if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ stopTrackingRequired(oldState);
+ }});
+ }
+ if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ // TODO as far as I can see there is nothing left to do here
+ // unbindService(newState);
+ }});
+ }
+ if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ deactivateService(oldState);
+ }});
+ }
+ if (oldState.isTrackingOptional() && newState.isBound()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ bindService(newState);
+ }});
+ }
+ if (oldState.isTrackingOptional() && newState.isInactive()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ deactivateService(oldState);
+ stopTrackingRequired(oldState);
+ }});
+ }
+ if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ deactivateService(oldState);
+ }});
+ }
+ if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ deactivateService(oldState);
+ stopTrackingRequired(oldState);
+ }});
+ }
+ if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ bindService(newState);
+ }});
+ }
+ if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ unbindService(oldState);
+ }});
+ }
+ if (oldState.isBound() && newState.isWaitingForRequired()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ unbindService(oldState);
+ deactivateService(oldState);
+ }});
+ }
+ if (oldState.isBound() && newState.isInactive()) {
+ m_executor.enqueue(new Runnable() {
+ public void run() {
+ unbindService(oldState);
+ deactivateService(oldState);
+ stopTrackingRequired(oldState);
+ }});
+ }
+ m_executor.execute();
+ }
+
+ // TODO fix code duplication between add(Dependency) and add(List)
+ public Component add(final Dependency dependency) {
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ m_dependencies.add(dependency);
+ }
+
+ // if we're inactive, don't do anything, otherwise we might want to start
+ // the dependency
+ if (!oldState.isInactive()) {
+ // if the dependency is required, it should be started regardless of the state
+ // we're in
+ if (dependency.isRequired()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ else {
+ // if the dependency is optional, it should only be started if we're in
+ // bound state
+ if (oldState.isBound()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ }
+ }
+
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ // starting the dependency above might have triggered another state change, so
+ // we have to fetch the current state again
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ return this;
+ }
+
+ public Component add(List dependencies) {
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ for (int i = 0; i < dependencies.size(); i++) {
+ m_dependencies.add(dependencies.get(i));
+ }
+ }
+
+ // if we're inactive, don't do anything, otherwise we might want to start
+ // the dependencies
+ if (!oldState.isInactive()) {
+ for (int i = 0; i < dependencies.size(); i++) {
+ Dependency dependency = (Dependency) dependencies.get(i);
+ // if the dependency is required, it should be started regardless of the state
+ // we're in
+ if (dependency.isRequired()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ else {
+ // if the dependency is optional, it should only be started if we're in
+ // bound state
+ if (oldState.isBound()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ }
+ }
+ }
+
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ // starting the dependency above might have triggered another state change, so
+ // we have to fetch the current state again
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ return this;
+ }
+
+ public Component remove(Dependency dependency) {
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ m_dependencies.remove(dependency);
+ }
+ if (oldState.isAllRequiredAvailable() || ((oldState.isWaitingForRequired() || oldState.isWaitingForRequiredInstantiated()) && dependency.isRequired())) {
+ ((DependencyActivation) dependency).stop(this);
+ }
+ synchronized (m_dependencies) {
+ // starting the dependency above might have triggered another state change, so
+ // we have to fetch the current state again
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ return this;
+ }
+
+ public List getDependencies() {
+ synchronized (m_dependencies) {
+ return (List) m_dependencies.clone();
+ }
+ }
+
+ public ServiceRegistration getServiceRegistration() {
+ return m_registration;
+ }
+
+ public Object getService() {
+ return m_serviceInstance;
+ }
+
+ public Component getServiceInterface() {
+ return this;
+ }
+
+ public void dependencyAvailable(final Dependency dependency) {
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
+ updateInstance(dependency);
+ }
+ calculateStateChanges(oldState, newState);
+ }
+
+ public void dependencyChanged(final Dependency dependency) {
+ State state;
+ synchronized (m_dependencies) {
+ state = m_state;
+ }
+ if (state.isAllRequiredAvailable()) {
+ updateInstance(dependency);
+ }
+ }
+
+ public void dependencyUnavailable(final Dependency dependency) {
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ if (newState.isAllRequiredAvailable()) {
+ updateInstance(dependency);
+ }
+ calculateStateChanges(oldState, newState);
+ }
+
+ public synchronized void start() {
+ if (!m_isStarted) {
+ m_isStarted = true;
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ }
+ }
+
+ public synchronized void stop() {
+ if (m_isStarted) {
+ m_isStarted = false;
+ State oldState, newState;
+ synchronized (m_dependencies) {
+ oldState = m_state;
+ newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
+ m_state = newState;
+ }
+ calculateStateChanges(oldState, newState);
+ }
+ }
+
+ public synchronized Component setInterface(String serviceName, Dictionary properties) {
+ ensureNotActive();
+ m_serviceName = serviceName;
+ m_serviceProperties = properties;
+ return this;
+ }
+
+ public synchronized Component setInterface(String[] serviceName, Dictionary properties) {
+ ensureNotActive();
+ m_serviceName = serviceName;
+ m_serviceProperties = properties;
+ return this;
+ }
+
+ public synchronized Component setCallbacks(String init, String start, String stop, String destroy) {
+ ensureNotActive();
+ m_callbackInit = init;
+ m_callbackStart = start;
+ m_callbackStop = stop;
+ m_callbackDestroy = destroy;
+ return this;
+ }
+
+ public synchronized Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
+ ensureNotActive();
+ m_callbackInstance = instance;
+ m_callbackInit = init;
+ m_callbackStart = start;
+ m_callbackStop = stop;
+ m_callbackDestroy = destroy;
+ return this;
+ }
+
+ public synchronized Component setImplementation(Object implementation) {
+ ensureNotActive();
+ m_implementation = implementation;
+ return this;
+ }
+
+ public synchronized Component setFactory(Object factory, String createMethod) {
+ ensureNotActive();
+ m_instanceFactory = factory;
+ m_instanceFactoryCreateMethod = createMethod;
+ return this;
+ }
+
+ public synchronized Component setFactory(String createMethod) {
+ return setFactory(null, createMethod);
+ }
+
+ public synchronized Component setComposition(Object instance, String getMethod) {
+ ensureNotActive();
+ m_compositionManager = instance;
+ m_compositionManagerGetMethod = getMethod;
+ return this;
+ }
+
+ public synchronized Component setComposition(String getMethod) {
+ return setComposition(null, getMethod);
+ }
+
+ public String toString() {
+ return this.getClass().getSimpleName() + "[" + m_serviceName + " " + m_implementation + "]";
+ }
+
+ public synchronized Dictionary getServiceProperties() {
+ if (m_serviceProperties != null) {
+ return (Dictionary) ((Hashtable) m_serviceProperties).clone();
+ }
+ return null;
+ }
+
+ public synchronized Component setServiceProperties(Dictionary serviceProperties) {
+ m_serviceProperties = serviceProperties;
+ if ((m_registration != null) && (m_serviceName != null)) {
+ m_registration.setProperties(calculateServiceProperties());
+ }
+ return this;
+ }
+
+ // service state listener methods
+ public void addStateListener(ComponentStateListener listener) {
+ synchronized (m_stateListeners) {
+ m_stateListeners.add(listener);
+ }
+ // when we register as a listener and the service is already started
+ // make sure we invoke the right callbacks so the listener knows
+ State state;
+ synchronized (m_dependencies) {
+ state = m_state;
+ }
+ if (state.isBound()) {
+ listener.starting(this);
+ listener.started(this);
+ }
+ }
+
+ public void removeStateListener(ComponentStateListener listener) {
+ synchronized (m_stateListeners) {
+ m_stateListeners.remove(listener);
+ }
+ }
+
+ public void removeStateListeners() {
+ synchronized (m_stateListeners) {
+ m_stateListeners.clear();
+ }
+ }
+
+ private void stateListenersStarting() {
+ ComponentStateListener[] list = getListeners();
+ for (int i = 0; i < list.length; i++) {
+ try {
+ list[i].starting(this);
+ }
+ catch (Throwable t) {
+ m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
+ }
+ }
+ }
+
+ private void stateListenersStarted() {
+ ComponentStateListener[] list = getListeners();
+ for (int i = 0; i < list.length; i++) {
+ try {
+ list[i].started(this);
+ }
+ catch (Throwable t) {
+ m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
+ }
+ }
+ }
+
+ private void stateListenersStopping() {
+ ComponentStateListener[] list = getListeners();
+ for (int i = 0; i < list.length; i++) {
+ try {
+ list[i].stopping(this);
+ }
+ catch (Throwable t) {
+ m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
+ }
+ }
+ }
+
+ private void stateListenersStopped() {
+ ComponentStateListener[] list = getListeners();
+ for (int i = 0; i < list.length; i++) {
+ try {
+ list[i].stopped(this);
+ }
+ catch (Throwable t) {
+ m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
+ }
+ }
+ }
+
+ private ComponentStateListener[] getListeners() {
+ synchronized (m_stateListeners) {
+ return (ComponentStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
+ }
+ }
+
+ private void activateService(State state) {
+ String init;
+ synchronized (this) {
+ init = m_callbackInit;
+ }
+ // service activation logic, first we initialize the service instance itself
+ // meaning it is created if necessary and the bundle context is set
+ initService();
+ // now is the time to configure the service, meaning all required
+ // dependencies will be set and any callbacks called
+ configureService(state);
+ // flag that our instance has been created
+ m_isInstantiated = true;
+ // then we invoke the init callback so the service can further initialize
+ // itself
+ invoke(init);
+ // see if any of this caused further state changes
+ calculateStateChanges();
+ }
+
+ private void bindService(State state) {
+ String start;
+ synchronized (this) {
+ start = m_callbackStart;
+ }
+
+ // configure service with extra-dependencies which might have been added from init() method.
+ configureServiceWithExtraDependencies(state);
+ // inform the state listeners we're starting
+ stateListenersStarting();
+ // invoke the start callback, since we're now ready to be used
+ invoke(start);
+ // start tracking optional services
+ startTrackingOptional(state);
+ // register the service in the framework's service registry
+ registerService();
+ // inform the state listeners we've started
+ stateListenersStarted();
+ }
+
+ private void configureServiceWithExtraDependencies(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (dependency.isAutoConfig() && dependency.isInstanceBound()) {
+ configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+ }
+ }
+ }
+
+ private void unbindService(State state) {
+ String stop;
+ synchronized (this) {
+ stop = m_callbackStop;
+ }
+ // service deactivation logic, first inform the state listeners
+ // we're stopping
+ stateListenersStopping();
+ // then, unregister the service from the framework
+ unregisterService();
+ // stop tracking optional services
+ stopTrackingOptional(state);
+ // invoke the stop callback
+ invoke(stop);
+ // inform the state listeners we've stopped
+ stateListenersStopped();
+ }
+
+ private void deactivateService(State state) {
+ String destroy;
+ synchronized (this) {
+ destroy = m_callbackDestroy;
+ }
+ // flag that our instance was destroyed
+ m_isInstantiated = false;
+ // invoke the destroy callback
+ invoke(destroy);
+ // destroy the service instance
+ destroyService(state);
+ }
+
+ private void invoke(String name) {
+ if (name != null) {
+ // if a callback instance was specified, look for the method there, if not,
+ // ask the service for its composition instances
+ Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance } : getCompositionInstances();
+ invokeCallbackMethod(instances, name,
+ new Class[][] {{ Component.class }, {}},
+ new Object[][] {{ this }, {}});
+ }
+ }
+
+ public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
+ for (int i = 0; i < instances.length; i++) {
+ try {
+ InvocationUtil.invokeCallbackMethod(instances[i], methodName, signatures, parameters);
+ }
+ catch (NoSuchMethodException e) {
+ // if the method does not exist, ignore it
+ }
+ catch (InvocationTargetException e) {
+ // the method itself threw an exception, log that
+ m_logger.log(Logger.LOG_WARNING, "Invocation of '" + methodName + "' failed.", e.getCause());
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_WARNING, "Could not invoke '" + methodName + "'.", e);
+ }
+ }
+ }
+
+ private void startTrackingOptional(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (!dependency.isRequired()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ }
+ }
+
+ private void stopTrackingOptional(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (!dependency.isRequired()) {
+ ((DependencyActivation) dependency).stop(this);
+ }
+ }
+ }
+
+ private void startTrackingRequired(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (dependency.isRequired()) {
+ ((DependencyActivation) dependency).start(this);
+ }
+ }
+ }
+
+ private void stopTrackingRequired(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (dependency.isRequired()) {
+ ((DependencyActivation) dependency).stop(this);
+ }
+ }
+ }
+
+ private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ Constructor constructor = clazz.getConstructor(VOID);
+ constructor.setAccessible(true);
+ return constructor.newInstance(null);
+ }
+
+ public void initService() {
+ if (m_serviceInstance == null) {
+ if (m_implementation instanceof Class) {
+ // instantiate
+ try {
+ m_serviceInstance = createInstance((Class) m_implementation);
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
+ }
+ }
+ else {
+ if (m_instanceFactoryCreateMethod != null) {
+ Object factory = null;
+ if (m_instanceFactory != null) {
+ if (m_instanceFactory instanceof Class) {
+ try {
+ factory = createInstance((Class) m_instanceFactory);
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
+ }
+ }
+ else {
+ factory = m_instanceFactory;
+ }
+ }
+ else {
+ // TODO review if we want to try to default to something if not specified
+ // for now the JavaDoc of setFactory(method) reflects the fact that we need
+ // to review it
+ }
+ if (factory == null) {
+ m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
+ }
+ else {
+ try {
+ m_serviceInstance = InvocationUtil.invokeMethod(factory, factory.getClass(), m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
+ }
+ }
+ }
+ if (m_serviceInstance == null) {
+ if (m_implementation == null) {
+ m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
+ }
+ m_serviceInstance = m_implementation;
+ }
+ }
+ // configure the bundle context
+ if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
+ configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
+ }
+ if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+ configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+ }
+ if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
+ configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
+ }
+ if (((Boolean) m_autoConfig.get(Component.class)).booleanValue()) {
+ configureImplementation(Component.class, this, (String) m_autoConfigInstance.get(Component.class));
+ }
+ }
+ }
+
+ public synchronized Component setAutoConfig(Class clazz, boolean autoConfig) {
+ m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
+ return this;
+ }
+
+ public synchronized Component setAutoConfig(Class clazz, String instanceName) {
+ m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
+ m_autoConfigInstance.put(clazz, instanceName);
+ return this;
+ }
+
+ public boolean getAutoConfig(Class clazz) {
+ Boolean result = (Boolean) m_autoConfig.get(clazz);
+ return (result != null && result.booleanValue());
+ }
+
+ public String getAutoConfigInstance(Class clazz) {
+ return (String) m_autoConfigInstance.get(clazz);
+ }
+
+ private void configureService(State state) {
+ // configure all services (the optional dependencies might be configured
+ // as null objects but that's what we want at this point)
+ configureServices(state);
+ }
+
+ private void destroyService(State state) {
+ unconfigureServices(state);
+ m_serviceInstance = null;
+ }
+
+ private void registerService() {
+ if (m_serviceName != null) {
+ ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
+ m_registration = wrapper;
+ if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+ configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+ }
+
+ // service name can either be a string or an array of strings
+ ServiceRegistration registration;
+
+ // determine service properties
+ Dictionary properties = calculateServiceProperties();
+
+ // register the service
+ try {
+ if (m_serviceName instanceof String) {
+ registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
+ }
+ else {
+ registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
+ }
+ wrapper.setServiceRegistration(registration);
+ }
+ catch (IllegalArgumentException iae) {
+ m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
+ // set the registration to an illegal state object, which will make all invocations on this
+ // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
+ wrapper.setIllegalState();
+ }
+ }
+ m_isBound = true;
+ }
+
+ private Dictionary calculateServiceProperties() {
+ Dictionary properties = new Properties();
+ addTo(properties, m_serviceProperties);
+ for (int i = 0; i < m_dependencies.size(); i++) {
+ Dependency d = (Dependency) m_dependencies.get(i);
+ if (d.isPropagated() && d.isAvailable()) {
+ Dictionary dict = d.getProperties();
+ addTo(properties, dict);
+ }
+ }
+ if (properties.size() == 0) {
+ properties = null;
+ }
+ return properties;
+ }
+
+ private void addTo(Dictionary properties, Dictionary additional) {
+ if (properties == null) {
+ throw new IllegalArgumentException("Dictionary to add to cannot be null.");
+ }
+ if (additional != null) {
+ Enumeration e = additional.keys();
+ while (e.hasMoreElements()) {
+ Object key = e.nextElement();
+ properties.put(key, additional.get(key));
+ }
+ }
+ }
+
+ private void unregisterService() {
+ m_isBound = false;
+ if (m_serviceName != null) {
+ m_registration.unregister();
+ configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
+ m_registration = null;
+ }
+ }
+
+ private void updateInstance(Dependency dependency) {
+ if (dependency.isAutoConfig()) {
+ configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+ if (dependency.isPropagated() && m_registration != null) {
+ m_registration.setProperties(calculateServiceProperties());
+ }
+ }
+ }
+
+ /**
+ * Configure a field in the service implementation. The service implementation
+ * is searched for fields that have the same type as the class that was specified
+ * and for each of these fields, the specified instance is filled in.
+ *
+ * @param clazz the class to search for
+ * @param instance the instance to fill in
+ * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
+ */
+ private void configureImplementation(Class clazz, Object instance, String instanceName) {
+ Object[] instances = getCompositionInstances();
+ if (instances != null) {
+ for (int i = 0; i < instances.length; i++) {
+ Object serviceInstance = instances[i];
+ Class serviceClazz = serviceInstance.getClass();
+ if (Proxy.isProxyClass(serviceClazz)) {
+ serviceInstance = Proxy.getInvocationHandler(serviceInstance);
+ serviceClazz = serviceInstance.getClass();
+ }
+ while (serviceClazz != null) {
+ Field[] fields = serviceClazz.getDeclaredFields();
+ for (int j = 0; j < fields.length; j++) {
+ Field field = fields[j];
+ Class type = field.getType();
+ if ((instanceName == null && type.equals(clazz))
+ || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
+ try {
+ field.setAccessible(true);
+ // synchronized makes sure the field is actually written to immediately
+ synchronized (SYNC) {
+ field.set(serviceInstance, instance);
+ }
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
+ return;
+ }
+ }
+ }
+ serviceClazz = serviceClazz.getSuperclass();
+ }
+ }
+ }
+ }
+
+ public Object[] getCompositionInstances() {
+ Object[] instances = null;
+ if (m_compositionManagerGetMethod != null) {
+ if (m_compositionManager != null) {
+ m_compositionManagerInstance = m_compositionManager;
+ }
+ else {
+ m_compositionManagerInstance = m_serviceInstance;
+ }
+ if (m_compositionManagerInstance != null) {
+ try {
+ instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
+ }
+ catch (Exception e) {
+ m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
+ instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
+ }
+ }
+ }
+ else {
+ instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
+ }
+ return instances;
+ }
+
+ private void configureImplementation(Class clazz, Object instance) {
+ configureImplementation(clazz, instance, null);
+ }
+
+ private void configureServices(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (dependency.isAutoConfig()) {
+ configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+ }
+ if (dependency.isRequired()) {
+ dependency.invokeAdded(this);
+ }
+ }
+ }
+
+ private void unconfigureServices(State state) {
+ Iterator i = state.getDependencies().iterator();
+ while (i.hasNext()) {
+ Dependency dependency = (Dependency) i.next();
+ if (dependency.isRequired()) {
+ dependency.invokeRemoved(this);
+ }
+ }
+ }
+
+ protected void ensureNotActive() {
+ State state;
+ synchronized (m_dependencies) {
+ state = m_state;
+ }
+ if (!state.isInactive()) {
+ throw new IllegalStateException("Cannot modify state while active.");
+ }
+ }
+
+ public boolean isRegistered() {
+ State state;
+ synchronized (m_dependencies) {
+ state = m_state;
+ }
+ return (state.isAllRequiredAvailable());
+ }
+
+ public boolean isInstantiated() {
+ State state;
+ synchronized (m_dependencies) {
+ state = m_state;
+ }
+ return (state.isTrackingOptional() || state.isBound() || state.isWaitingForRequiredInstantiated());
+ }
+
+ // ServiceComponent interface
+
+ static class SCDImpl implements ComponentDependencyDeclaration {
+ private final String m_name;
+ private final int m_state;
+ private final String m_type;
+
+ public SCDImpl(String name, int state, String type) {
+ m_name = name;
+ m_state = state;
+ m_type = type;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public int getState() {
+ return m_state;
+ }
+
+ public String getType() {
+ return m_type;
+ }
+ }
+
+ public ComponentDependencyDeclaration[] getComponentDependencies() {
+ List deps = getDependencies();
+ if (deps != null) {
+ ComponentDependencyDeclaration[] result = new ComponentDependencyDeclaration[deps.size()];
+ for (int i = 0; i < result.length; i++) {
+ Dependency dep = (Dependency) deps.get(i);
+ if (dep instanceof ComponentDependencyDeclaration) {
+ result[i] = (ComponentDependencyDeclaration) dep;
+ }
+ else {
+ result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
+ }
+ }
+ return result;
+ }
+ return null;
+ }
+
+ public String getName() {
+ Object serviceName = m_serviceName;
+ if (serviceName instanceof String[]) {
+ StringBuffer sb = new StringBuffer();
+ String[] names = (String[]) serviceName;
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(names[i]);
+ }
+ sb.append('(');
+ sb.append(propertiesToString());
+ sb.append(')');
+ return sb.toString();
+ }
+ else if (serviceName instanceof String) {
+ return serviceName.toString() + "(" + propertiesToString() + ")";
+ }
+ else {
+ Object implementation = m_implementation;
+ if (implementation != null) {
+ return implementation.toString();
+ }
+ else {
+ return super.toString();
+ }
+ }
+ }
+
+ private String propertiesToString() {
+ StringBuffer result = new StringBuffer();
+ Dictionary properties = calculateServiceProperties();
+ if (properties != null) {
+ Enumeration enumeration = properties.keys();
+ while (enumeration.hasMoreElements()) {
+ Object key = enumeration.nextElement();
+ if (result.length() > 0) {
+ result.append(',');
+ }
+ result.append(key.toString());
+ result.append('=');
+ Object value = properties.get(key);
+ if (value instanceof String[]) {
+ String[] values = (String[]) value;
+ result.append('{');
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ result.append(',');
+ }
+ result.append(values[i].toString());
+ }
+ result.append('}');
+ }
+ else {
+ result.append(value.toString());
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ public int getState() {
+ return (isRegistered() ? 1 : 0);
+ }
+
+ public DependencyManager getDependencyManager() {
+ return m_manager;
+ }
+
+ static {
+ NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ComponentImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
+ }
+
+ public BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ public int compareTo(Object object) {
+ if (object instanceof ComponentImpl) {
+ ComponentImpl other = (ComponentImpl) object;
+ long id1 = this.getBundleContext().getBundle().getBundleId();
+ long id2 = ((ComponentImpl) other).getBundleContext().getBundle().getBundleId();
+ if (id1 == id2) {
+ return (int)(this.m_id - other.m_id);
+ }
+ return (int)(id1 - id2);
+ }
+ return -1;
+ }
+}
Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,71 @@
+/*
+ * 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.InvocationHandler;
+import java.lang.reflect.Method;
+
+
+/**
+ * Default null object implementation. Uses a dynamic proxy. Null objects are used
+ * as placeholders for services that are not available.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class DefaultNullObject implements InvocationHandler {
+ private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
+ private static final Byte DEFAULT_BYTE = new Byte((byte) 0);
+ private static final Short DEFAULT_SHORT = new Short((short) 0);
+ private static final Integer DEFAULT_INT = new Integer(0);
+ private static final Long DEFAULT_LONG = new Long(0);
+ private static final Float DEFAULT_FLOAT = new Float(0.0f);
+ private static final Double DEFAULT_DOUBLE = new Double(0.0);
+
+ /**
+ * Invokes a method on this null object. The method will return a default
+ * value without doing anything.
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Class returnType = method.getReturnType();
+ if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) {
+ return DEFAULT_BOOLEAN;
+ }
+ else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) {
+ return DEFAULT_BYTE;
+ }
+ else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) {
+ return DEFAULT_SHORT;
+ }
+ else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) {
+ return DEFAULT_INT;
+ }
+ else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) {
+ return DEFAULT_LONG;
+ }
+ else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) {
+ return DEFAULT_FLOAT;
+ }
+ else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) {
+ return DEFAULT_DOUBLE;
+ }
+ else {
+ return null;
+ }
+ }
+}
\ No newline at end of file