| /******************************************************************************* |
| * Copyright (c) 2010-2014 SAP AG and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * SAP AG - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.skalli.testutil; |
| |
| import java.util.Dictionary; |
| import java.util.Set; |
| import java.util.SortedSet; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.skalli.services.BundleFilter; |
| import org.eclipse.skalli.services.FilterMode; |
| import org.eclipse.skalli.services.Services; |
| import org.eclipse.skalli.services.extension.ExtensionService; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.ServiceRegistration; |
| |
| /** |
| * Utility class to start bundles for plugin tests. |
| * |
| */ |
| public class BundleManager { |
| |
| /** |
| * Starts bundles with a symbolic name matching <tt>org.eclipse.skalli.*</tt> |
| * and all bundles providing an {@link ExtensionService}. |
| * |
| * @param c the class for which to start a bundle |
| * @throws BundleException if starting the bundles failed. |
| */ |
| public static void startBundles() throws BundleException { |
| SortedSet<Bundle> bundles = Services.getBundles(FilterMode.ALL, |
| new BundleFilter.AcceptService(ExtensionService.class), |
| new BundleFilter.AcceptMatching(Services.SKALLI_BUNDLE_PATTERN)); |
| startBundles(bundles); |
| } |
| |
| /** |
| * Starts the bundle containing the given class, as well as all |
| * bundles with a symbolic name matching <tt>org.eclipse.skalli.*</tt> |
| * and all bundles providing an {@link ExtensionService}. |
| * |
| * @param c the class for which to start a bundle |
| * @throws BundleException if starting the bundles failed. |
| */ |
| public static void startBundles(Class<?> c) throws BundleException { |
| Bundle bundle = FrameworkUtil.getBundle(c); |
| startBundle(bundle); |
| startBundles(); |
| } |
| |
| /** |
| * Starts a given set of bundles with {@link #startBundle(Bundle)}. |
| * |
| * @param bundles the bundles to start. |
| * @throws BundleException if starting the bundles failed. |
| */ |
| public static void startBundles(SortedSet<Bundle> bundles) throws BundleException { |
| for (Bundle bundle : bundles) { |
| startBundle(bundle); |
| } |
| } |
| |
| /** |
| * Starts the given bundle unless its symbolic name ends with <tt>.test</tt>, |
| * it is a fragment or it already is started. |
| * |
| * @param bundle the bundle to start. |
| * @throws BundleException if the bundle could not be started. |
| */ |
| public static void startBundle(Bundle bundle) throws BundleException { |
| if (!bundle.getSymbolicName().endsWith(".test") //$NON-NLS-1$ |
| && !isFragment(bundle) |
| && bundle.getState() != Bundle.ACTIVE) { |
| bundle.start(); |
| } |
| } |
| |
| /** |
| * Checks if the given bundle is a fragment. |
| * @param bundle the bundle to check. |
| * @return <code>true</code> if the bundle has a <tt>Fragment-Host</tt> header |
| * in its manifest, <code>false</code> otherwise. |
| */ |
| public static boolean isFragment(Bundle bundle) { |
| Dictionary<String,String> headers = bundle.getHeaders(); |
| return StringUtils.isNotBlank(headers.get("Fragment-Host")); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns an instance of a given service class. Starts all bundles providing |
| * the given service interface, as well as all bundles with a symbolic name |
| * matching <tt>org.eclipse.skalli.*</tt> and all bundles providing |
| * an {@link ExtensionService}. |
| * |
| * @param serviceClass the service to retrieve. |
| * @throws BundleException if starting the bundles failed. |
| * @throws IllegalStateException |
| * if there is none or more than one instance of the service |
| * registered. |
| */ |
| public static <T> T getRequiredService(Class<T> serviceClass) throws BundleException { |
| startBundles(serviceClass); |
| return Services.getRequiredService(serviceClass); |
| } |
| |
| /** |
| * Waits for a dedicated service implementation to appear. |
| * @param serviceClass the service to wait for. |
| * @param implementationClass the expected service implementation. |
| * @param timeout the maximum time to wait in milliseconds. |
| * @return the service instance, or <code>null</code>. |
| * |
| * @throws BundleException if starting the bundles failed. |
| * @throws InterruptedException if the waiting has been interrupted. |
| */ |
| public static <S,T> S waitService(Class<S> serviceClass, Class<T> implementationClass, long timeout) |
| throws BundleException, InterruptedException { |
| startBundles(serviceClass); |
| int waited = 0; |
| S result = null; |
| while (result == null && waited < timeout) { |
| Set<S> services = Services.getServices(serviceClass); |
| for (S service : services) { |
| if (implementationClass == null || implementationClass.getName().equals(service.getClass().getName())) { |
| return service; |
| } |
| } |
| Thread.sleep(100); |
| waited += 100; |
| } |
| return result; |
| } |
| |
| /** |
| * Registers a service for testing purposes. |
| * |
| * @param <S> type of the service. |
| * @param serviceClass the service interface class under which the service instance should be registered. |
| * @param serviceInstance the actual service instance. |
| * @param properties optional properties for this service, or <code>null</code>. |
| * |
| * @param the <code>ServiceRegistration</code> which should be used to unregister the test service |
| * after the test finished. Make sure to unregister the service properly (finally block!), otherwise |
| * other tests might get affected by a messy service registry. |
| * |
| * @throws BundleException if starting the bundles failed. |
| */ |
| public static <S> ServiceRegistration<S> registerService(Class<S> serviceClass, S serviceInstance, |
| Dictionary<String,?> properties) throws BundleException { |
| startBundles(serviceClass); |
| Bundle bundle = FrameworkUtil.getBundle(serviceClass); |
| return bundle.getBundleContext().registerService(serviceClass, serviceInstance, properties); |
| } |
| } |