| /******************************************************************************* |
| * Copyright (c) 2008, 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 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * VMware Inc. - initial contribution |
| *******************************************************************************/ |
| |
| package org.eclipse.virgo.test.framework.dmkernel; |
| |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.eclipse.virgo.test.framework.BundleEntry; |
| import org.eclipse.virgo.test.framework.OsgiTestRunner; |
| import org.eclipse.virgo.test.framework.TestFrameworkUtils; |
| import org.eclipse.virgo.util.common.CollectionUtils; |
| import org.eclipse.virgo.util.common.PropertyPlaceholderResolver; |
| import org.junit.runners.model.InitializationError; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.startlevel.FrameworkStartLevel; |
| |
| import javax.management.MalformedObjectNameException; |
| |
| /** |
| * JUnit TestRunner for running OSGi integration tests on the dm Kernel. |
| * <p /> |
| * |
| * <strong>Concurrent Semantics</strong><br /> |
| * |
| * As thread-safe as OsgiTestRunner |
| * |
| */ |
| public class DmKernelTestRunner extends OsgiTestRunner { |
| |
| private static final int DEFAULT_BUNDLE_START_LEVEL = 4; |
| |
| private static final long DEFAULT_USER_REGION_START_WAIT_TIME = 60000; |
| |
| private final long userRegionStartWaitTime; |
| |
| public DmKernelTestRunner(Class<?> klass) throws InitializationError, MalformedObjectNameException { |
| this(klass, DEFAULT_USER_REGION_START_WAIT_TIME); |
| } |
| |
| DmKernelTestRunner(Class<?> klass, long userRegionStartWaitTime) throws InitializationError, MalformedObjectNameException { |
| super(klass); |
| this.userRegionStartWaitTime = userRegionStartWaitTime; |
| } |
| |
| @Override |
| protected BundleContext getTargetBundleContext(BundleContext bundleContext) { |
| Collection<ServiceReference<BundleContext>> serviceReferences = getUserRegionBundleContextServiceReferences(bundleContext); |
| |
| if (serviceReferences != null) { |
| if (serviceReferences.size() != 1) { |
| throw new IllegalStateException("There must be exactly one user region bundle context in the service registry. " |
| + serviceReferences.size() + " were found."); |
| } else { |
| BundleContext targetBundleContext = bundleContext.getService(serviceReferences.iterator().next()); |
| if (targetBundleContext != null) { |
| return targetBundleContext; |
| } |
| } |
| } |
| throw new IllegalStateException("User region's bundle context was not available from the service registry within " |
| + (this.userRegionStartWaitTime / 1000) + " seconds."); |
| } |
| |
| /** |
| * Installs additional user region bundles based on {@link RegionBundleDependencies} |
| */ |
| @Override |
| protected void postProcessTargetBundleContext(BundleContext bundleContext, Properties frameworkConfigurationProperties) throws Exception { |
| |
| /* |
| * Use the same default start level for user region bundles as the user region factory. Program the framework |
| * start level instance defensively to allow for stubs which don't understand adapt. |
| */ |
| FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class); |
| if (frameworkStartLevel != null) { |
| frameworkStartLevel.setInitialBundleStartLevel(DEFAULT_BUNDLE_START_LEVEL); |
| } |
| |
| final Properties configurationProperties = new Properties(frameworkConfigurationProperties); |
| |
| // This list is installed post installation of user region bundle that includes bundles listed in the |
| // user region configuration file as implemented in kernel RegionManager |
| Class<RegionBundleDependencies> annotationType = RegionBundleDependencies.class; |
| Class<?> annotationDeclaringClazz = TestFrameworkUtils.findAnnotationDeclaringClass(annotationType, getTestClass().getJavaClass()); |
| |
| if (annotationDeclaringClazz == null) { |
| // could not find an 'annotation declaring class' for annotation + annotationType + and targetType + |
| // startFromClazz |
| return; |
| } |
| |
| final List<Bundle> bundlesToStart = new ArrayList<>(); |
| |
| List<BundleEntry> bundleEntries = new ArrayList<>(); |
| |
| while (annotationDeclaringClazz != null) { |
| RegionBundleDependencies dependencies = annotationDeclaringClazz.getAnnotation(annotationType); |
| BundleEntry[] entries = dependencies.entries(); |
| |
| bundleEntries.addAll(0, Arrays.asList(entries)); |
| annotationDeclaringClazz = dependencies.inheritDependencies() ? TestFrameworkUtils.findAnnotationDeclaringClass(annotationType, |
| annotationDeclaringClazz.getSuperclass()) : null; |
| } |
| PropertyPlaceholderResolver resolver = new PropertyPlaceholderResolver(); |
| |
| if (!CollectionUtils.isEmpty(bundleEntries)) { |
| |
| for (BundleEntry bundleEntry : bundleEntries) { |
| |
| String path = bundleEntry.value(); |
| boolean autoStart = bundleEntry.autoStart(); |
| |
| String formattedPath = resolver.resolve(path, configurationProperties); |
| Bundle bundle = bundleContext.installBundle(new URI(formattedPath).toString()); |
| |
| if (autoStart && !TestFrameworkUtils.isFragment(bundle)) { |
| bundlesToStart.add(bundle); |
| } |
| } |
| } |
| |
| for (Bundle bundle : bundlesToStart) { |
| try { |
| bundle.start(); |
| } catch (BundleException e) { |
| throw new BundleException("Failed to start bundle " + bundle.getSymbolicName() + " " + bundle.getVersion(), e); |
| } |
| } |
| } |
| |
| private Collection<ServiceReference<BundleContext>> getUserRegionBundleContextServiceReferences(BundleContext bundleContext) { |
| |
| long startTime = System.currentTimeMillis(); |
| |
| Collection<ServiceReference<BundleContext>> serviceReferences = doGetUserRegionBundleContextServiceReferences(bundleContext); |
| |
| while (serviceReferences.size() == 0) { |
| if (System.currentTimeMillis() < (this.userRegionStartWaitTime + startTime)) { |
| try { |
| Thread.sleep(500); |
| serviceReferences = doGetUserRegionBundleContextServiceReferences(bundleContext); |
| } catch (InterruptedException ie) { |
| throw new RuntimeException(ie); |
| } |
| } else { |
| break; |
| } |
| } |
| return serviceReferences; |
| } |
| |
| private Collection<ServiceReference<BundleContext>> doGetUserRegionBundleContextServiceReferences(BundleContext bundleContext) { |
| try { |
| return bundleContext.getServiceReferences(BundleContext.class, "(org.eclipse.virgo.kernel.regionContext=true)"); |
| } catch (InvalidSyntaxException e) { |
| throw new RuntimeException("Unexpected InvalidSyntaxException when looking up the user region's BundleContext", e); |
| } |
| } |
| } |