org.eclipse.gemini.blueprint.util.OsgiServiceReferenceUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gemini.blueprint.util.OsgiServiceReferenceUtils.java

Source

/******************************************************************************
 * Copyright (c) 2006, 2010 VMware Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution. 
 * The Eclipse Public License is available at 
 * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
 * is available at http://www.opensource.org/licenses/apache2.0.php.
 * You may elect to redistribute this code under either of these licenses. 
 * 
 * Contributors:
 *   VMware Inc.
 *****************************************************************************/

package org.eclipse.gemini.blueprint.util;

import java.util.Collections;
import java.util.Dictionary;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.gemini.blueprint.util.internal.MapBasedDictionary;
import org.eclipse.gemini.blueprint.util.internal.ServiceReferenceBasedMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * Utility class for retrieving OSGi service references. This class offers a unified filter-based access for OSGi
 * services as well as translation of checked exceptions {@link InvalidSyntaxException} into unchecked ones.
 * 
 * <p/>
 * 
 * This classes uses {@link OsgiFilterUtils} underneath to allow multiple class names to be used for service reference
 * lookup.
 * 
 * @see OsgiFilterUtils
 * @author Costin Leau
 * 
 */
public abstract class OsgiServiceReferenceUtils {

    private static final Log log = LogFactory.getLog(OsgiServiceReferenceUtils.class);

    /**
     * Returns a reference to the <em>best matching</em> service for the given class names.
     * 
     * @param bundleContext OSGi bundle context
     * @param classes array of fully qualified class names
     * @return reference to the <em>best matching</em> service
     */
    public static ServiceReference getServiceReference(BundleContext bundleContext, String[] classes) {
        return getServiceReference(bundleContext, classes, null);
    }

    /**
     * Returns a reference to the <em>best matching</em> service for the given class and OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param clazz fully qualified class name (can be <code>null</code>)
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return reference to the <em>best matching</em> service
     */
    public static ServiceReference getServiceReference(BundleContext bundleContext, String clazz, String filter) {
        ServiceReference[] refs = getServiceReferences(bundleContext, clazz, filter);

        // pick the best service
        return getServiceReference(refs);
    }

    public static ServiceReference getServiceReference(ServiceReference... references) {
        if (ObjectUtils.isEmpty(references)) {
            return null;
        }

        ServiceReference winningReference = references[0];

        if (references.length > 1) {
            long winningId = getServiceId(winningReference);
            int winningRanking = getServiceRanking(winningReference);

            // start iterating in order to find the best match
            for (int i = 1; i < references.length; i++) {
                ServiceReference reference = references[i];
                int serviceRanking = getServiceRanking(reference);
                long serviceId = getServiceId(reference);

                if ((serviceRanking > winningRanking)
                        || (serviceRanking == winningRanking && winningId > serviceId)) {
                    winningReference = reference;
                    winningId = serviceId;
                    winningRanking = serviceRanking;
                }
            }
        }
        return winningReference;
    }

    /**
     * Returns a reference to the <em>best matching</em> service for the given classes and OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param classes array of fully qualified class names
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return reference to the <em>best matching</em> service
     */
    public static ServiceReference getServiceReference(BundleContext bundleContext, String[] classes,
            String filter) {
        // use #getServiceReference(BundleContext, String, String) method to
        // speed the service lookup process by
        // giving one class as a hint to the OSGi implementation

        String clazz = (ObjectUtils.isEmpty(classes) ? null : classes[0]);

        return getServiceReference(bundleContext, clazz, OsgiFilterUtils.unifyFilter(classes, filter));
    }

    /**
     * Returns a reference to the <em>best matching</em> service for the given OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return reference to the <em>best matching</em> service
     */
    public static ServiceReference getServiceReference(BundleContext bundleContext, String filter) {
        return getServiceReference(bundleContext, (String) null, filter);
    }

    /**
     * Returns references to <em>all</em> services matching the given class names.
     * 
     * @param bundleContext OSGi bundle context
     * @param classes array of fully qualified class names
     * @return non-<code>null</code> array of references to matching services
     */
    public static ServiceReference[] getServiceReferences(BundleContext bundleContext, String[] classes) {
        return getServiceReferences(bundleContext, classes, null);
    }

    /**
     * Returns references to <em>all</em> services matching the given class name and OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param clazz fully qualified class name (can be <code>null</code>)
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return non-<code>null</code> array of references to matching services
     */
    public static ServiceReference[] getServiceReferences(BundleContext bundleContext, String clazz,
            String filter) {
        Assert.notNull(bundleContext, "bundleContext should be not null");

        try {
            ServiceReference[] refs = bundleContext.getServiceReferences(clazz, filter);
            return (refs == null ? new ServiceReference[0] : refs);
        } catch (InvalidSyntaxException ise) {
            throw (RuntimeException) new IllegalArgumentException("invalid filter: " + ise.getFilter())
                    .initCause(ise);
        }
    }

    /**
     * Returns references to <em>all</em> services matching the given class names and OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param classes array of fully qualified class names
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return non-<code>null</code> array of references to matching services
     */
    public static ServiceReference[] getServiceReferences(BundleContext bundleContext, String[] classes,
            String filter) {
        // use #getServiceReferences(BundleContext, String, String) method to
        // speed the service lookup process by
        // giving one class as a hint to the OSGi implementation
        // additionally this allows type filtering

        String clazz = (ObjectUtils.isEmpty(classes) ? null : classes[0]);
        return getServiceReferences(bundleContext, clazz, OsgiFilterUtils.unifyFilter(classes, filter));
    }

    /**
     * Returns references to <em>all</em> services matching the OSGi filter.
     * 
     * @param bundleContext OSGi bundle context
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return non-<code>null</code> array of references to matching services
     */
    public static ServiceReference[] getServiceReferences(BundleContext bundleContext, String filter) {
        return getServiceReferences(bundleContext, (String) null, filter);
    }

    /**
     * Returns the service id ({@link Constants#SERVICE_ID}) of the given service reference.
     * 
     * @param reference OSGi service reference
     * @return service id
     */
    public static long getServiceId(ServiceReference reference) {
        Assert.notNull(reference);
        return ((Long) reference.getProperty(Constants.SERVICE_ID)).longValue();
    }

    /**
     * Returns the service ranking ({@link Constants#SERVICE_RANKING}) of the given service reference.
     * 
     * @param reference OSGi service reference
     * @return service ranking
     */
    public static int getServiceRanking(ServiceReference reference) {
        Assert.notNull(reference);

        Object ranking = reference.getProperty(Constants.SERVICE_RANKING);
        // if the property is not supplied or of incorrect type, use a
        // default
        return ((ranking != null && ranking instanceof Integer) ? ((Integer) ranking).intValue() : 0);
    }

    /**
     * Returns the advertised class names ({@link Constants#OBJECTCLASS}) of the given service reference.
     * 
     * @param reference OSGi service reference
     * @return service advertised class names
     */
    public static String[] getServiceObjectClasses(ServiceReference reference) {
        Assert.notNull(reference);
        return (String[]) reference.getProperty(Constants.OBJECTCLASS);
    }

    /**
     * Returns a {@link Map} containing the properties available for the given service reference. This method takes a
     * snapshot of the properties; future changes to the service properties will not be reflected in the returned
     * dictionary.
     * 
     * <p/> Note that the returned type implements the {@link java.util.Map} interface also.
     * 
     * @param reference OSGi service reference
     * @return a <code>Dictionary</code> containing the service reference properties taken as a snapshot
     */
    public static Dictionary getServicePropertiesSnapshot(ServiceReference reference) {
        return new MapBasedDictionary(getServicePropertiesSnapshotAsMap(reference));
    }

    /**
     * Returns a {@link Map} containing the properties available for the given service reference. This method takes a
     * snapshot of the properties; future changes to the service properties will not be reflected in the returned
     * dictionary.
     * 
     * @param reference OSGi service reference
     * @return a <code>Map</code> containing the service reference properties taken as a snapshot
     */
    public static Map getServicePropertiesSnapshotAsMap(ServiceReference reference) {
        Assert.notNull(reference);
        String[] keys = reference.getPropertyKeys();

        Map map = new LinkedHashMap(keys.length);

        for (int i = 0; i < keys.length; i++) {
            map.put(keys[i], reference.getProperty(keys[i]));
        }

        // mark it as read-only
        map = Collections.unmodifiableMap(map);
        return map;
    }

    /**
     * Returns a {@link Dictionary} containing the properties available for the given service reference. The returned
     * object will reflect any updates made to to the <code>ServiceReference</code> through the owning
     * <code>ServiceRegistration</code>.
     * 
     * 
     * <p/> Note that the returned type implements the {@link java.util.Map} interface also.
     * 
     * @param reference OSGi service reference
     * @return a <code>Dictionary</code> containing the latest service reference properties
     */
    public static Dictionary getServiceProperties(ServiceReference reference) {
        return new MapBasedDictionary(getServicePropertiesAsMap(reference));
    }

    /**
     * Returns a {@link Map} containing the properties available for the given service reference. The returned object
     * will reflect any updates made to to the <code>ServiceReference</code> through the owning
     * <code>ServiceRegistration</code>. Consider using {@link #getServiceProperties(ServiceReference)} which returns an
     * object that extends {@link Dictionary} as well as implements the {@link Map} interface.
     * 
     * @param reference OSGi service reference
     * @return a <code>Map</code> containing the latest service reference properties
     * @see #getServiceProperties(ServiceReference)
     */
    public static Map getServicePropertiesAsMap(ServiceReference reference) {
        Assert.notNull(reference);
        return new ServiceReferenceBasedMap(reference);

    }

    /**
     * Checks if the given filter matches at least one OSGi service or not.
     * 
     * @param bundleContext OSGi bundle context
     * @param filter valid OSGi filter (can be <code>null</code>)
     * @return true if the filter matches at least one OSGi service, false otherwise
     */
    public static boolean isServicePresent(BundleContext bundleContext, String filter) {
        return !ObjectUtils.isEmpty(getServiceReferences(bundleContext, filter));
    }
}