edu.northwestern.bioinformatics.studycalendar.osgi.OsgiLayerIntegratedTestHelper.java Source code

Java tutorial

Introduction

Here is the source code for edu.northwestern.bioinformatics.studycalendar.osgi.OsgiLayerIntegratedTestHelper.java

Source

/*L
 * Copyright Northwestern University.
 *
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.io/psc/LICENSE.txt for details.
 */

package edu.northwestern.bioinformatics.studycalendar.osgi;

import edu.northwestern.bioinformatics.studycalendar.StudyCalendarSystemException;
import edu.northwestern.bioinformatics.studycalendar.core.StaticApplicationContextHelper;
import edu.northwestern.bioinformatics.studycalendar.core.StudyCalendarApplicationContextBuilder;
import edu.northwestern.bioinformatics.studycalendar.tools.osgi.Embedder;
import edu.northwestern.bioinformatics.studycalendar.tools.osgi.EmbedderConfiguration;
import edu.northwestern.bioinformatics.studycalendar.tools.osgi.EmbedderFilesystemConfiguration;
import edu.northwestern.bioinformatics.studycalendar.tools.osgi.FrameworkFactoryFinder;
import edu.northwestern.bioinformatics.studycalendar.tools.spring.ConcreteStaticApplicationContext;
import org.apache.commons.lang.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author Rhett Sutphin
 */
public class OsgiLayerIntegratedTestHelper {
    private static final Logger log = LoggerFactory.getLogger(OsgiLayerIntegratedTestHelper.class);

    private static StaticApplicationContextHelper applicationContextHelper = new ApplicationContextBuilder();
    private static BundleContext bundleContext;
    private static File projectRoot;

    private static final int TIMEOUT_MS = (System.getenv("JOB_NAME") == null ? 60 : 300) * 1000;

    public static synchronized BundleContext getBundleContext() throws IOException {
        if (bundleContext == null) {
            System.setProperty("catalina.base",
                    getModuleRelativeDirectory("osgi-layer:integrated-tests", "tmp").getAbsolutePath());

            EmbedderConfiguration configuration = new EmbedderFilesystemConfiguration(
                    getModuleRelativeDirectory("osgi-layer", "target/test/embedder").getAbsoluteFile());
            Embedder embedder = new Embedder();
            embedder.setConfiguration(configuration);
            embedder.setFrameworkFactory(FrameworkFactoryFinder.getFrameworkFactory());

            bundleContext = embedder.start();
        }
        return bundleContext;
    }

    public static File getModuleRelativeDirectory(String moduleName, String directory) throws IOException {
        File dir = new File(findProjectRootDirectory(), moduleName.replaceAll(":", "/"));
        dir = new File(dir, directory);
        if (dir.exists())
            return dir;

        throw new FileNotFoundException(
                String.format("Could not find directory %s relative to module %s from project directory %s",
                        directory, moduleName, findProjectRootDirectory().getCanonicalPath()));
    }

    private synchronized static File findProjectRootDirectory() throws FileNotFoundException {
        if (projectRoot == null) {
            File buildfile;
            projectRoot = new File(".");
            do {
                buildfile = new File(projectRoot, "buildfile");
                if (buildfile.exists()) {
                    return projectRoot;
                }
                projectRoot = new File(projectRoot, "..");
            } while (projectRoot.exists() && projectRoot.isDirectory());

            projectRoot = null;
            throw new FileNotFoundException(
                    String.format("Could not find project directory.  Started from %s and walked up to %s.",
                            new File("."), projectRoot));
        }
        return projectRoot;
    }

    public static Bundle startBundle(String bundleName) throws IOException, BundleException, InterruptedException {
        Bundle bundle = findBundle(bundleName);
        bundle.start();
        return bundle;
    }

    public static void startBundle(String bundleName, String withService)
            throws BundleException, IOException, InterruptedException {
        waitForService(startBundle(bundleName), withService);
    }

    private static void waitForService(Bundle bundle, String withService) throws InterruptedException {
        log.debug("Beginning wait for {} in {}", withService, bundle);

        long start = System.currentTimeMillis();

        while (!timedOut(start)
                && (bundle.getRegisteredServices() == null || bundle.getRegisteredServices().length == 0)) {
            log.debug("- waiting for any service registration");
            Thread.sleep(100);
        }

        SEARCH: while (!timedOut(start)) {
            for (ServiceReference ref : bundle.getRegisteredServices()) {
                String[] interfaces = (String[]) ref.getProperty("objectClass");
                log.debug("- has service with {}", Arrays.asList(interfaces));
                if (interfaces != null) {
                    if (Arrays.asList(interfaces).contains(withService)) {
                        break SEARCH;
                    }
                }
            }
            log.debug("- waiting for service {} registration", withService);
            Thread.sleep(100);
        }

        log.debug("- {} became available after {}ms", withService, System.currentTimeMillis() - start);
    }

    // side effect is the important bit
    private static boolean timedOut(long startTime) {
        if (System.currentTimeMillis() - startTime > TIMEOUT_MS) {
            throw new StudyCalendarSystemException("Wait for service timed out");
        } else {
            return false;
        }
    }

    public static void waitForService(String bundleName, String withService)
            throws IOException, InterruptedException {
        waitForService(findBundle(bundleName), withService);
    }

    public static void waitForService(String serviceInterface) throws IOException, InterruptedException {
        log.debug("Beginning wait for {} from any bundle", serviceInterface);

        long start = System.currentTimeMillis();

        while (!timedOut(start) && getBundleContext().getServiceReference(serviceInterface) == null) {
            log.debug("- waiting for service {} in any bundle", serviceInterface);
            Thread.sleep(100);
        }

        log.debug("- {} became available after {}ms", serviceInterface, System.currentTimeMillis() - start);
    }

    public static void stopBundle(String bundleName) throws IOException, BundleException {
        findBundle(bundleName).stop();
    }

    public static Bundle findBundle(String bundleName) throws IOException {
        for (Bundle candidate : getBundleContext().getBundles()) {
            if (candidate.getSymbolicName() == null) {
                throw new NullPointerException(
                        String.format("Bundle %s (%s) has no symbolic name", candidate, candidate.getBundleId()));
            }
            if (candidate.getSymbolicName().equals(bundleName)) {
                return candidate;
            }
        }

        List<String> bundles = new ArrayList<String>();
        for (Bundle bundle : getBundleContext().getBundles()) {
            bundles.add(bundle.getSymbolicName());
        }

        throw new StudyCalendarSystemException("No bundle %s in the testing context:\n- %s", bundleName,
                StringUtils.join(bundles.iterator(), ("\n- ")));
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContextHelper.getApplicationContext();
    }

    private static class ApplicationContextBuilder extends StaticApplicationContextHelper {
        private ApplicationContext createBundleContextApplicationContext() {
            try {
                return ConcreteStaticApplicationContext
                        .create(Collections.<String, Object>singletonMap("bundleContext", getBundleContext()));
            } catch (IOException e) {
                throw new RuntimeException("Creating bundle context failed", e);
            }
        }

        @Override
        protected ApplicationContext createApplicationContext() {
            ClassPathXmlApplicationContext ctxt = new ClassPathXmlApplicationContext(
                    createBundleContextApplicationContext());
            ctxt.setConfigLocations(StudyCalendarApplicationContextBuilder.DEPLOYED_CONFIG_LOCATIONS);
            ctxt.refresh();
            return ctxt;
        }
    }
}