All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.felix.ipojo.composite.CompositeServiceContext Maven / Gradle / Ivy

There is a newer version: 1.12.1
Show newest version
/* 
 * 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.ipojo.composite;

import java.io.File;
import java.io.InputStream;
import java.util.*;

import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.IPojoContext;
import org.apache.felix.ipojo.ServiceContext;
import org.apache.felix.ipojo.context.ServiceReferenceImpl;
import org.apache.felix.ipojo.context.ServiceRegistry;
import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
import org.apache.felix.ipojo.util.Tracker;
import org.apache.felix.ipojo.util.TrackerCustomizer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Filter;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

/**
 * CompositeServiceContext Class. This class provides an implementation of the
 * service context for composite.
 * 
 * @author Felix Project Team
 */
public class CompositeServiceContext implements ServiceContext, TrackerCustomizer {

    /**
     * Structure storing the reference, the factory and the registration.
     */
    private class Record {
        /**
         * Reference of the represented factory from the external context.
         */
        private ServiceReference m_ref;
        /**
         * Registration of the factory in the internal context.
         */
        private ServiceRegistration m_reg;
        /**
         * Represented Factory. 
         */
        private FactoryProxy m_fact;
    }

    /**
     * List of imported factories.
     */
    private List m_factories = new ArrayList();
    /**
     * Internal service registry.
     */
    private ServiceRegistry m_registry;

    /**
     * Component Instance who creates this registry.
     */
    private ComponentInstance m_instance;
    
    /**
     * Global service context.
     */
    private BundleContext m_global;
    
    /**
     * Tracker tracking Factories to import.
     */
    private Tracker m_tracker;

    /**
     * Constructor. This constructor instantiate a service registry with the
     * given bundle context.
     * 
     * @param context : the bundle context
     */
    public CompositeServiceContext(BundleContext context) {
        m_registry = new ServiceRegistry(context);
        if (context instanceof IPojoContext) {
            m_global = ((IPojoContext) context).getGlobalContext();
        } else {
            m_global = context; // the parent context is the global context
        }
    }

    /**
     * Constructor.
     * 
     * @param context : the bundle context
     * @param instance : the component instance owning this context
     */
    public CompositeServiceContext(BundleContext context, ComponentInstance instance) {
        this(context);
        m_instance = instance;
    }

    /**
     * Add a service listener.
     * @param arg0 : The service listener to add
     * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener)
     */
    public void addServiceListener(ServiceListener arg0) {
        m_registry.addServiceListener(arg0);
    }

    /**
     * Add a filtered service listener.
     * @param arg0 : the service listener object to add
     * @param arg1 : the LDAP filter for this listener
     * @throws InvalidSyntaxException : occurs if the LDAP filter is malformed
     * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener,
     * java.lang.String)
     */
    public void addServiceListener(ServiceListener arg0, String arg1) throws InvalidSyntaxException {
        m_registry.addServiceListener(arg0, arg1);
    }

    /**
     * Get all service references.
     * @param arg0 : The required service interface.
     * @param arg1 : LDAP filter
     * @return the list of all service reference matching with the query
     * @throws InvalidSyntaxException : occurs when the given filter is malformed
     * @see org.apache.felix.ipojo.ServiceContext#getAllServiceReferences(java.lang.String,
     * java.lang.String)
     */
    public ServiceReference[] getAllServiceReferences(String arg0, String arg1) throws InvalidSyntaxException {
        return m_registry.getAllServiceReferences(arg0, arg1);
    }

    /**
     * Get a service object for the given service reference.
     * @param arg0 : the service reference
     * @return the service object or null if the reference is no more valid or if the object is not accessible
     * @see org.apache.felix.ipojo.ServiceContext#getService(org.osgi.framework.ServiceReference)
     */
    public Object getService(ServiceReference arg0) {
        ServiceReference ref;
        if (arg0 instanceof TransformedServiceReference) {
            ref = ((TransformedServiceReference) arg0).getWrappedReference();
        } else {
            ref = arg0;
        }

        if (ref instanceof ServiceReferenceImpl) {
            return m_registry.getService(m_instance, ref);
        } else {
            throw new RuntimeException("Cannot get a global service from the local registry");
        }
    }

    
    /**
     * Get a service reference for the required interface.
     * @param arg0 : the required interface name
     * @return the service reference or null if no available provider
     * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String)
     */
    public ServiceReference getServiceReference(String arg0) {
        return m_registry.getServiceReference(arg0);
    }

    public  ServiceReference getServiceReference(Class clazz) {
        //noinspection unchecked
        return getServiceReference(clazz.getName());
    }

    @SuppressWarnings("unchecked")
    public  Collection> getServiceReferences(Class clazz, String filter) throws InvalidSyntaxException {
        ServiceReference[] refs = getServiceReferences(clazz.getName(), filter);
        return Arrays.asList(refs);
    }

    /**
     * Get all accessible service reference for the given query.
     * @param clazz : required interface
     * @param filter : LDAP filter
     * @return the list (array) of service reference matching with the query.
     * @throws InvalidSyntaxException : occurs when the LDAP filter is malformed
     * @see org.apache.felix.ipojo.ServiceContext#getServiceReferences(java.lang.String, java.lang.String)
     */
    public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
        return m_registry.getServiceReferences(clazz, filter);
    }


    /**
     * Register a service inside the composite context.
     * @param arg0 : list of interfaces to register.
     * @param arg1 : service object
     * @param arg2 : properties list
     * @return the service registration
     * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
     */
    public ServiceRegistration registerService(String[] arg0, Object arg1, Dictionary arg2) {
        return m_registry.registerService(m_instance, arg0, arg1, arg2);
    }

    /**
     * Register a service inside the composite context.
     * @param arg0 : interface to register.
     * @param arg1 : service object
     * @param arg2 : properties list
     * @return the service registration
     * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
     */
    public ServiceRegistration registerService(String arg0, Object arg1, Dictionary arg2) {
        return m_registry.registerService(m_instance, arg0, arg1, arg2);
    }

    /**
     * Remove a service listener.
     * @param arg0 : the service listener to remove
     * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener)
     */
    public void removeServiceListener(ServiceListener arg0) {
        m_registry.removeServiceListener(arg0);
    }

    /**
     * Unget a service.
     * @param arg0 the service reference to unget
     * @return true
     * @see org.apache.felix.ipojo.ServiceContext#ungetService(org.osgi.framework.ServiceReference)
     */
    public boolean ungetService(ServiceReference arg0) {
        return m_registry.ungetService(m_instance, arg0);
    }

    /**
     * Import a factory form the parent to the internal registry.
     * 
     * @param ref : the reference of the factory to import.
     */
    private void importFactory(ServiceReference ref) {        
        Record rec = new Record();
        m_factories.add(rec);
        Dictionary dict = new Hashtable();
        for (int j = 0; j < ref.getPropertyKeys().length; j++) {
            dict.put(ref.getPropertyKeys()[j], ref.getProperty(ref.getPropertyKeys()[j]));
        }
        rec.m_fact = new FactoryProxy((Factory) m_tracker.getService(ref), this);
        rec.m_reg = registerService(Factory.class.getName(), rec.m_fact, dict);
        rec.m_ref = ref;
    }

    /**
     * Remove a factory of the available factory list.
     * 
     * @param ref : the reference on the factory to remove.
     */
    private void removeFactory(ServiceReference ref) {
        for (int i = 0; i < m_factories.size(); i++) {
            Record rec = m_factories.get(i);
            if (rec.m_ref == ref) {
                if (rec.m_reg != null) {
                    rec.m_reg.unregister();
                    rec.m_fact = null;
                }
                m_tracker.ungetService(rec.m_ref);
                m_factories.remove(rec);
                return;
            }
        }
    }

    /**
     * Start the registry management.
     */
    public void start() {
        m_tracker = new Tracker(m_global, Factory.class.getName(), this);
        m_tracker.open();
    }

    /**
     * Stop the registry management.
     */
    public synchronized void stop() {
        m_tracker.close();
        m_registry.reset();
        List records = new ArrayList(m_factories);
        for (Record rec : records) {
            removeFactory(rec.m_ref);
        }
        m_tracker = null;
    }

    /**
     * Check if the factory list contain the given reference.
     * 
     * @param ref : the reference to find.
     * @return true if the list contains the given reference.
     */
    private boolean containsRef(ServiceReference ref) {
        for (Record rec : m_factories) {
            if (rec.m_ref == ref) {
                return true;
            }
        }
        return false;
    }

    /**
     * Add a bundle listener.
     * Delegate on the global bundle context.
     * @param arg0 : bundle listener to add
     * @see org.osgi.framework.BundleContext#addBundleListener(org.osgi.framework.BundleListener)
     */
    public void addBundleListener(BundleListener arg0) {
        m_global.addBundleListener(arg0);
    }

    /**
     * Add a framework listener.
     * Delegate on the global bundle context.
     * @param arg0 : framework listener to add.
     * @see org.osgi.framework.BundleContext#addFrameworkListener(org.osgi.framework.FrameworkListener)
     */
    public void addFrameworkListener(FrameworkListener arg0) {
        m_global.addFrameworkListener(arg0);
    }

    /**
     * Create a LDAP filter.
     * @param arg0 : String-form of the filter
     * @return the created filter object
     * @throws InvalidSyntaxException : if the given argument is not a valid against the LDAP grammar.
     * @see org.osgi.framework.BundleContext#createFilter(java.lang.String)
     */
    public Filter createFilter(String arg0) throws InvalidSyntaxException {
        return m_global.createFilter(arg0);
    }

    public Bundle getBundle(String location) {
        return m_global.getBundle(location);
    }

    /**
     * Get the current bundle.
     * @return the current bundle
     * @see org.osgi.framework.BundleContext#getBundle()
     */
    public Bundle getBundle() {
        return m_global.getBundle();
    }

    /**
     * Get the bundle object with the given id.
     * @param bundleId : bundle id
     * @return the bundle object
     * @see org.osgi.framework.BundleContext#getBundle(long)
     */
    public Bundle getBundle(long bundleId) {
        return m_global.getBundle(bundleId);
    }

    /**
     * Get installed bundles.
     * @return the list of installed bundles
     * @see org.osgi.framework.BundleContext#getBundles()
     */
    public Bundle[] getBundles() {
        return m_global.getBundles();
    }


    /**
     * Get a data file.
     * @param filename : File name.
     * @return the File object
     * @see org.osgi.framework.BundleContext#getDataFile(java.lang.String)
     */
    public File getDataFile(String filename) {
        return m_global.getDataFile(filename);
    }

    /**
     * Get a property value.
     * @param key : key of the asked property
     * @return the property value (object) or null if no property are associated with the given key
     * @see org.osgi.framework.BundleContext#getProperty(java.lang.String)
     */
    public String getProperty(String key) {
        return m_global.getProperty(key);
    }

    /**
     * Install a bundle.
     * @param location : URL of the bundle to install
     * @return the installed bundle
     * @throws BundleException : if the bundle cannot be installed correctly
     * @see org.osgi.framework.BundleContext#installBundle(java.lang.String)
     */
    public Bundle installBundle(String location) throws BundleException {
        return m_global.installBundle(location);
    }

    /**
     * Install a bundle.
     * @param location : URL of the bundle to install
     * @param input : 
     * @return the installed bundle
     * @throws BundleException : if the bundle cannot be installed correctly
     * @see org.osgi.framework.BundleContext#installBundle(java.lang.String, java.io.InputStream)
     */
    public Bundle installBundle(String location, InputStream input) throws BundleException {
        return m_global.installBundle(location, input);
    }

    /**
     * Remove a bundle listener.
     * @param listener : the listener to remove
     * @see org.osgi.framework.BundleContext#removeBundleListener(org.osgi.framework.BundleListener)
     */
    public void removeBundleListener(BundleListener listener) {
        m_global.removeBundleListener(listener);
    }

    /**
     * Remove a framework listener.
     * @param listener : the listener to remove
     * @see org.osgi.framework.BundleContext#removeFrameworkListener(org.osgi.framework.FrameworkListener)
     */
    public void removeFrameworkListener(FrameworkListener listener) {
        m_global.removeFrameworkListener(listener);
    }

    public  ServiceRegistration registerService(Class clazz, S service, Dictionary properties) {
        return registerService(clazz.getName(), service, properties);
    }

    /**
     * A new factory is detected.
     * @param reference : service reference
     * @return true if not already imported.
     * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
     */
    public boolean addingService(ServiceReference reference) {
        return !containsRef(reference);
    }
    
    /**
     * A matching reference has been added. The import factory can now be imported.
     * @param reference : the added reference.
     * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
     */
    public void addedService(ServiceReference reference) {
        importFactory(reference);
    }

    /**
     * An imported factory is modified.
     * @param reference : modified reference
     * @param service : factory object.
     * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
     */
    public void modifiedService(ServiceReference reference, Object service) {
        for (Record rec : m_factories) {
            if (rec.m_ref == reference) {
                Dictionary dict = new Hashtable();
                for (int j = 0; j < reference.getPropertyKeys().length; j++) {
                    dict.put(reference.getPropertyKeys()[j], reference.getProperty(reference.getPropertyKeys()[j]));
                }
                rec.m_reg.setProperties(dict);
                return;
            }
        }
    }

    /**
     * An imported factory disappears.
     * @param reference : reference
     * @param service : factory object.
     * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
     */
    public void removedService(ServiceReference reference, Object service) {
        if (containsRef(reference)) {
            removeFactory(reference);
        }
        
    }
}