blob: d1f143613beda7cf6116fc287af84b3d1af357ea [file] [log] [blame]
/*******************************************************************************
* 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);
}
}