/* * 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 <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ 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<Record> m_factories = new ArrayList<Record>(); /** * 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 <S> ServiceReference<S> getServiceReference(Class<S> clazz) { //noinspection unchecked return getServiceReference(clazz.getName()); } @SuppressWarnings("unchecked") public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) throws InvalidSyntaxException { ServiceReference<S>[] 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<String, Object> dict = new Hashtable<String, Object>(); 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<Record> records = new ArrayList<Record>(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 <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> 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<String, Object> dict = new Hashtable<String, Object>(); 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); } } }