/* * Copyright 2011 Harald Wellmann. * * Licensed 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.ops4j.pax.swissbox.tracker; import java.util.Map; import java.util.Map.Entry; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; /** * A utility class for looking up services from the OSGi registry. The methods of this class wait * for the service for a given timeout (default 10 seconds) and throw a * {@code TestContainerException} when no matching service becomes available during this period. * <p> * NOTE: Prefixing some method calls with our own class name is a workaround for a bug in the Oracle * Java compiler, which does not occur when compiling in Eclipse. * * @author Harald Wellmann * */ public class ServiceLookup { /** * Default timeout used for service lookup when no explicit timeout is specified. */ public static final long DEFAULT_TIMEOUT = 10000; /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param className name of class implemented or extended by the service * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, String className ) { return ServiceLookup.<T> getService( bc, className, DEFAULT_TIMEOUT, "" ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param type class implemented or extended by the service * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, Class<T> type ) { return getService( bc, type, DEFAULT_TIMEOUT ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param type class implemented or extended by the service * @param props properties to be matched by the service * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, Class<T> type, Map<String, String> props ) { return getService( bc, type, DEFAULT_TIMEOUT, props ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param type class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @param props properties to be matched by the service * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, Class<T> type, long timeout, Map<String, String> props ) { return ServiceLookup.<T> getService( bc, type.getName(), timeout, props ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param type class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, Class<T> type, long timeout ) { return ServiceLookup.<T> getService( bc, type.getName(), timeout, "" ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param type class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @param filter LDAP filter to be matched by the service. The class name will be added to the * filter. * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static <T> T getService( BundleContext bc, Class<T> type, long timeout, String filter ) { return ServiceLookup.<T> getService( bc, type.getName(), timeout, filter ); } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param className name of class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @param props properties to be matched by the service * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ @SuppressWarnings( "unchecked" ) public static <T> T getService( BundleContext bc, String className, long timeout, Map<String, String> props ) { ServiceTracker tracker = createServiceTracker( bc, className, props ); try { tracker.open(); Object svc = tracker.waitForService( timeout ); if( svc == null ) { throw new ServiceLookupException( "gave up waiting for service " + className ); } // increment the service use count to keep it valid after the ServiceTracker is closed return (T) bc.getService( tracker.getServiceReference() ); } catch ( InterruptedException exc ) { throw new ServiceLookupException( exc ); } finally { tracker.close(); } } /** * Returns a service matching the given criteria. * * @param <T> class implemented or extended by the service * @param bc bundle context for accessing the OSGi registry * @param className name of class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @param filter LDAP filter to be matched by the service. The class name will be added to the * filter. * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ @SuppressWarnings( "unchecked" ) public static <T> T getService( BundleContext bc, String className, long timeout, String filter ) { ServiceTracker tracker = createServiceTracker( bc, className, filter ); try { tracker.open(); Object svc = tracker.waitForService( timeout ); if( svc == null ) { throw new ServiceLookupException( "gave up waiting for service " + className ); } // increment the service use count to keep it valid after the ServiceTracker is closed return (T) bc.getService( tracker.getServiceReference() ); } catch ( InterruptedException exc ) { throw new ServiceLookupException( exc ); } finally { tracker.close(); } } /** * Returns a service reference matching the given criteria. * * @param bc bundle context for accessing the OSGi registry * @param className name of class implemented or extended by the service * @param timeout maximum wait period in milliseconds * @param filter LDAP filter to be matched by the service. The class name will be added to the * filter. * @return matching service reference (not null) * @throws ServiceLookupException */ public static ServiceReference getServiceReference( BundleContext bc, String className, long timeout, String filter ) { ServiceTracker tracker = createServiceTracker( bc, className, filter ); try { tracker.open(); Object svc = tracker.waitForService( timeout ); if( svc == null ) { throw new ServiceLookupException( "gave up waiting for service " + className ); } return tracker.getServiceReference(); } catch ( InterruptedException exc ) { throw new ServiceLookupException( exc ); } finally { tracker.close(); } } private static ServiceTracker createServiceTracker( BundleContext bc, String className, Map<String, String> props ) { if( props == null || props.isEmpty() ) { return new ServiceTracker( bc, className, null ); } StringBuilder builder = new StringBuilder( "(&(objectClass=" ); builder.append( className ); builder.append( ')' ); for( Entry<String, String> entry : props.entrySet() ) { builder.append( '(' ); builder.append( entry.getKey() ); builder.append( '=' ); builder.append( entry.getValue() ); builder.append( ')' ); } builder.append( ')' ); return createServiceTrackerWithFilter( bc, builder.toString() ); } private static ServiceTracker createServiceTrackerWithFilter( BundleContext bc, String ldapFilter ) { try { Filter filter; filter = bc.createFilter( ldapFilter ); ServiceTracker tracker = new ServiceTracker( bc, filter, null ); return tracker; } catch ( InvalidSyntaxException exc ) { throw new ServiceLookupException( exc ); } } private static ServiceTracker createServiceTracker( BundleContext bc, String className, String filterString ) { StringBuilder builder = new StringBuilder( "(&(objectClass=" ); builder.append( className ); builder.append( ')' ); if( filterString != null ) { builder.append( filterString ); } builder.append( ')' ); return createServiceTrackerWithFilter( bc, builder.toString() ); } /** * Returns a service matching the given filter. * * @param bc bundle context for accessing the OSGi registry * @param ldapFilter LDAP filter to be matched by the service. The class name must be part of the * filter. * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the default * timeout */ public static Object getServiceByFilter( BundleContext bc, String ldapFilter ) { return getServiceByFilter( bc, ldapFilter, DEFAULT_TIMEOUT ); } /** * Returns a service matching the given filter. * * @param bc bundle context for accessing the OSGi registry * @param ldapFilter LDAP filter to be matched by the service. The class name must be part of the * filter. * @param timeout maximum wait period in milliseconds * @return matching service (not null) * @throws ServiceLookupException when no matching service has been found after the timeout */ public static Object getServiceByFilter( BundleContext bc, String ldapFilter, long timeout ) { try { Filter filter = bc.createFilter( ldapFilter ); ServiceTracker tracker = new ServiceTracker( bc, filter, null ); tracker.open(); Object svc = tracker.waitForService( timeout ); if( svc == null ) { throw new ServiceLookupException( "gave up waiting for service " + ldapFilter ); } // increment the service use count to keep it valid after the ServiceTracker is closed return bc.getService( tracker.getServiceReference() ); } catch ( InvalidSyntaxException exc ) { throw new ServiceLookupException( exc ); } catch ( InterruptedException exc ) { throw new ServiceLookupException( exc ); } } }