/* * 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; import java.io.File; import java.io.InputStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference; 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; /** * The policy service context is a service context aiming to resolve service dependencies * inside different service context according to a policy. * So, the policy service context behavior follows one of the three following policy: * <li> Local : services are only resolved in the local service context.</li> * <li> Global : services are only resolved in the global context (hte OSGi one)</li> * <li> Local and Global : services are resolved inside the local context and inside * the global context</li> * * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class PolicyServiceContext implements ServiceContext { /** * Resolving policy, resolves services only in the composite * context (local). * This policy is the default one for services inherited from * service-level dependencies. */ public static final int LOCAL = 0; /** * Resolving policy, resolves services only in the composite * (local) and in the global context. * This policy is the default one for implementation dependency. */ public static final int LOCAL_AND_GLOBAL = 1; /** * Resolving policy, resolves services inside the global context * only. */ public static final int GLOBAL = 2; /** * The global service registry. * Targets the OSGi service registry. */ public BundleContext m_global; /** * The local (Composite) Service Registry. */ public ServiceContext m_local; /** * The resolving policy to use to resolve * dependencies. */ private int m_policy = LOCAL_AND_GLOBAL; /** * Creates a PolicyServiceContext. * If the local context is null, sets the policy to * {@link PolicyServiceContext#GLOBAL}, else use the * given policy. * @param global the global bundle context * @param local the parent (local) service context * @param policy the resolution policy */ public PolicyServiceContext(BundleContext global, ServiceContext local, int policy) { m_global = global; m_local = local; if (m_local == null) { m_policy = GLOBAL; } else { m_policy = policy; } } /** * Adds a service listener according to the policy. * Be aware, that the listener can be registered both in the local and in the global context * if the {@link PolicyServiceContext#LOCAL_AND_GLOBAL} is used. * @param listener the listener to add * @param filter the LDAP filter * @throws InvalidSyntaxException if the filter is malformed. * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String) */ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException { if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) { m_local.addServiceListener(listener, filter); } if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) { m_global.addServiceListener(listener, filter); } } /** * Adds a service listener according to the policy. * Be aware, that the listener can be registered both in the local and in the global context * if the {@link PolicyServiceContext#LOCAL_AND_GLOBAL} is used. * @param listener the listener to add * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener) */ public void addServiceListener(ServiceListener listener) { if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) { m_local.addServiceListener(listener); } if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) { m_global.addServiceListener(listener); } } /** * Gets all service references. * These references are found inside the local registry, global registry or both according to the policy. * The returned array can contain service references from both context. * @param clazz the required service specification. * @param filter the LDAP filter * @return the array of service reference, <code>null</code> if no service available * @throws InvalidSyntaxException if the LDAP filter is malformed * @see org.apache.felix.ipojo.ServiceContext#getAllServiceReferences(java.lang.String, java.lang.String) */ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException { switch (m_policy) { case LOCAL: return m_local.getAllServiceReferences(clazz, filter); case GLOBAL: return m_global.getAllServiceReferences(clazz, filter); case LOCAL_AND_GLOBAL: ServiceReference[] refLocal = m_local.getAllServiceReferences(clazz, filter); ServiceReference[] refGlobal = m_global.getAllServiceReferences(clazz, filter); return computeServiceReferencesFromBoth(refLocal, refGlobal); default: return null; } } /** * Gets the service object for the given references. * The service is get inside the context according to the policy. * @param ref the service reference * @return the service object * @see org.apache.felix.ipojo.ServiceContext#getService(org.osgi.framework.ServiceReference) */ public Object getService(ServiceReference ref) { if (ref instanceof TransformedServiceReference) { ref = ((TransformedServiceReference) ref).getWrappedReference(); } switch(m_policy) { // NOPMD No break needed as we return in each branch. case LOCAL: // The reference comes from the local scope return m_local.getService(ref); case GLOBAL: // The reference comes from the global registry return m_global.getService(ref); case LOCAL_AND_GLOBAL: if (ref instanceof org.apache.felix.ipojo.context.ServiceReferenceImpl) { return m_local.getService(ref); } else { return m_global.getService(ref); } default : return null; } } /** * Gets a service reference for the required service specification. * The service is looked inside the context according to the policy. * @param clazz the required service specification * @return a service reference or <code>null</code> if no matching service available * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String) */ public ServiceReference getServiceReference(String clazz) { switch (m_policy) { // NOPMD No break needed as we return in each branch. case LOCAL: return m_local.getServiceReference(clazz); case GLOBAL: return m_global.getServiceReference(clazz); case LOCAL_AND_GLOBAL: ServiceReference refLocal = m_local.getServiceReference(clazz); if (refLocal == null) { return m_global.getServiceReference(clazz); } else { return refLocal; } default: return null; } } /** * Gets a service reference. * This method is delegated on PolicyServiceContext#getServiceReference(String) * @param sClass the service interface class * @param <S> the service interface class * @return the service reference of <code>null</code> if not found * @see PolicyServiceContext#getServiceReference(String) */ public <S> ServiceReference<S> getServiceReference(Class<S> sClass) { return (ServiceReference<S>) getServiceReference(sClass.getName()); } /** * Gets a collection of service references * @param clazz the service interface class * @param filter the filter * @param <S> the service interface class * @return the set of service reference * @throws InvalidSyntaxException the filter is invalid * @see PolicyServiceContext#getServiceReferences(String, String) */ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) throws InvalidSyntaxException { ServiceReference<S>[] refs = (ServiceReference<S>[]) getServiceReferences(clazz.getName(), filter); return (refs == null) ? Collections.EMPTY_LIST : (Collection<ServiceReference<S>>) Arrays.asList(refs); } /** * Get a service reference for the required service specification. * The services are looked inside the context according to the policy. * @param clazz the required service specification * @param filter the LDAP filter * @return a service reference array or <code>null</code> if not consistent service available * @throws InvalidSyntaxException if the LDAP filter is malformed * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String) */ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { switch (m_policy) { case LOCAL: return m_local.getServiceReferences(clazz, filter); case GLOBAL: return m_global.getServiceReferences(clazz, filter); case LOCAL_AND_GLOBAL: ServiceReference[] refLocal = m_local.getServiceReferences(clazz, filter); ServiceReference[] refGlobal = m_global.getServiceReferences(clazz, filter); return computeServiceReferencesFromBoth(refLocal, refGlobal); default: return null; } } /** * Computes the service reference array from the two given set of service references * according to the policy. * @param refLocal the set of local references * @param refGlobal the set of global references * @return the set of service references */ private ServiceReference[] computeServiceReferencesFromBoth(ServiceReference[] refLocal, ServiceReference[] refGlobal) { if (refLocal == null) { return refGlobal; // If refGlobal is null, return null, else return refGlobal } else if (refGlobal == null) { // refLocal != null && refGlobal == null return refLocal; } else { // Both refGlobal and refLocal are not null ServiceReference[] refs = new ServiceReference[refLocal.length + refGlobal.length]; System.arraycopy(refLocal, 0, refs, 0, refLocal.length); System.arraycopy(refGlobal, 0, refs, refLocal.length, refGlobal.length); return refs; } } /** * This method is not supported. * This context can only be used to resolve service dependencies. * @param clazzes the specifications * @param service the service object * @param properties the service properties * @return the service registration object * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary) */ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services"); } /** * This method is not supported. * This context can only be used to resolve service dependencies. * @param clazz the specification * @param service the service object * @param properties the service properties to publish * @return the service registration object * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary) */ public ServiceRegistration registerService(String clazz, Object service, Dictionary properties) { throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services"); } /** * Removes a service listener. * @param listener the service listener to remove * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener) */ public void removeServiceListener(ServiceListener listener) { if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) { m_local.removeServiceListener(listener); } if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) { m_global.removeServiceListener(listener); } } /** * Ungets the service reference. * @param reference the service reference to unget. * @return <code>true</code> if the service release if the reference is no more used. * @see org.apache.felix.ipojo.ServiceContext#ungetService(org.osgi.framework.ServiceReference) */ public boolean ungetService(ServiceReference reference) { if (reference instanceof org.apache.felix.ipojo.context.ServiceReferenceImpl) { return m_local.ungetService(reference); } else { return m_global.ungetService(reference); } } /** * Adds 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); } /** * Adds a framework listener. * Delegates 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); } /** * Creates a LDAP filter. * @param arg0 the 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); } /** * Gets a bundle by name * @param s the name * @return the matching bundle or <code>null</code> if not found */ public Bundle getBundle(String s) { return m_global.getBundle(s); } /** * Gets the current bundle. * @return the current bundle * @see org.osgi.framework.BundleContext#getBundle() */ public Bundle getBundle() { return m_global.getBundle(); } /** * Gets the bundle object with the given id. * @param bundleId the bundle id * @return the bundle object * @see org.osgi.framework.BundleContext#getBundle(long) */ public Bundle getBundle(long bundleId) { return m_global.getBundle(bundleId); } /** * Gets installed bundles. * @return the list of installed bundles * @see org.osgi.framework.BundleContext#getBundles() */ public Bundle[] getBundles() { return m_global.getBundles(); } /** * Gets a data file. * @param filename the 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); } /** * Gets a property value. * @param key the key of the asked property * @return the property value (object) or <code>null</code> 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); } /** * Installs a bundle. * @param location the 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); } /** * Installs a bundle. * @param location the URL of the bundle to install * @param input the input stream to load the bundle content * @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); } /** * Removes the 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); } /** * Removes 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); } /** * Registers a service. * Operation not supported. * @param clazz the class object * @param svc the service object * @param properties the properties * @param <S> the type of service * @return the service registration */ public <S> ServiceRegistration<S> registerService(Class<S> clazz, S svc, Dictionary<String, ?> properties) { throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services"); } }