You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/03/18 22:42:40 UTC

svn commit: r1579062 - /felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java

Author: pderop
Date: Tue Mar 18 21:42:40 2014
New Revision: 1579062

URL: http://svn.apache.org/r1579062
Log:
added FactoryConfigurationAdapter impl

Added:
    felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java

Added: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java?rev=1579062&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/FactoryConfigurationAdapterImpl.java Tue Mar 18 21:42:40 2014
@@ -0,0 +1,278 @@
+package 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.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;
+
+import dm.Component;
+import dm.ComponentStateListener;
+import dm.Dependency;
+import dm.DependencyManager;
+import dm.PropertyMetaData;
+import dm.context.DependencyContext;
+import dm.impl.metatype.MetaTypeProviderImpl;
+
+/**
+ * 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 FactoryConfigurationAdapterImpl extends FilterComponent {
+    // Our Managed Service Factory PID
+    protected final String m_factoryPid;
+    
+    public FactoryConfigurationAdapterImpl(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.
+        m_factoryPid = factoryPid;
+
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new AdapterImpl(update, propagate))
+            .setCallbacks("init", null, "stop", null);
+    }
+    
+    public FactoryConfigurationAdapterImpl(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.
+        m_factoryPid = factoryPid;
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new MetaTypeAdapterImpl(update, propagate,
+                bctx, logger, heading, description,
+                localization, properyMetaData))
+            .setCallbacks("init", null, "stop", null);
+    }
+    
+    public String getName() {
+        return "Adapter for factory pid " + m_factoryPid;
+    }
+    
+    /**
+     * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
+     */
+    public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {        
+        // The adapter "update" method used to provide the configuration
+        protected final String m_update;
+
+        // Tells if the CM config must be propagated along with the adapter service properties
+        protected final 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 updateMethod, boolean propagate) {
+            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);
+            
+            for (DependencyContext dc : m_component.getDependencies()) {
+                newService.add((Dependency) dc.createCopy());
+            }
+            
+            for (int i = 0; i < m_stateListeners.size(); i ++) {
+                newService.add(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 final MetaTypeProviderImpl m_metaType;
+        
+        public MetaTypeAdapterImpl(String updateMethod, boolean propagate,
+                                   BundleContext bctx, Logger logger, String heading, 
+                                   String description, String localization,
+                                   PropertyMetaData[] properyMetaData) {
+            super(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);
+        }
+    }    
+}