Package org.apache.felix.dm.impl.dependencies

Source Code of org.apache.felix.dm.impl.dependencies.ConfigurationDependencyImpl

/*
* 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;
      m_metaType = prototype.m_metaType;
      m_propagateCallbackInstance = prototype.m_propagateCallbackInstance;
      m_propagateCallbackMethod = prototype.m_propagateCallbackMethod;
  }
 
  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);
        }
    }
}
TOP

Related Classes of org.apache.felix.dm.impl.dependencies.ConfigurationDependencyImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.