org.eclipse.wb.tests.designer.core.TestBundle.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wb.tests.designer.core.TestBundle.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Google, 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:
 *    Google, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.wb.tests.designer.core;

import com.google.common.collect.Lists;

import org.eclipse.wb.internal.core.utils.IOUtils2;
import org.eclipse.wb.internal.core.utils.check.Assert;
import org.eclipse.wb.internal.core.utils.external.ExternalFactoriesHelper;
import org.eclipse.wb.tests.designer.TestUtils;
import org.eclipse.wb.tests.designer.tests.Activator;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Helper for creating temporary {@link Bundle}.
 * 
 * @author scheglov_ke
 */
public final class TestBundle {
    private final BundleContext m_context = Activator.getDefault().getBundle().getBundleContext();
    private final String m_id;
    private final File m_bundleFolder;
    private File m_bundleFile;
    private boolean m_created;
    private Bundle m_bundle;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public TestBundle() throws Exception {
        this("org.eclipse.wb.tests.testBundle");
    }

    public TestBundle(String id) throws Exception {
        m_id = id;
        m_bundleFolder = IOUtils2.createTempDirectory("wbpTestBundle", "");
        m_bundleFile = m_bundleFolder;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Configuring
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Creates in this {@link TestBundle} same class as it exists in given {@link ClassLoader}. Note,
     * that {@link ClassLoader} should be able to provide <code>*.class</code> resource.
     */
    public void addClass(Class<?> clazz) throws Exception {
        ClassLoader classLoader = clazz.getClassLoader();
        String name = clazz.getName();
        // add main class
        addClass(classLoader, name);
        // add anonymous inner classes
        try {
            for (int i = 1;; i++) {
                addClass(classLoader, name + "$" + i);
            }
        } catch (Throwable e) {
        }
    }

    /**
     * Creates in this {@link TestBundle} same class as it exists in given {@link ClassLoader}. Note,
     * that {@link ClassLoader} should be able to provide <code>*.class</code> resource.
     */
    public void addClass(ClassLoader classLoader, String name) throws Exception {
        addClass(name, getClassBytes(classLoader, name));
    }

    public void addClass(String name, InputStream inputStream) throws Exception {
        assertNotCreated();
        File classFile = getFileInExistingFolder(name.replace('.', '/') + ".class");
        IOUtils2.writeBytes(classFile, inputStream);
    }

    public void setFile(String path, String content) throws Exception {
        setFile(path, content.getBytes());
    }

    public void setFile(String path, byte[] content) throws Exception {
        assertNotCreated();
        File file = getFileInExistingFolder(path);
        IOUtils2.writeBytes(file, content);
    }

    public ZipFileFactory addJar(String path) throws Exception {
        assertNotCreated();
        File jarFile = getFileInExistingFolder(path);
        return new ZipFileFactory(new FileOutputStream(jarFile));
    }

    private void assertNotCreated() {
        Assert.isTrue(!m_created, "Bundle %s is already created.", m_id);
    }

    private File getFileInExistingFolder(String path) {
        File file = new File(m_bundleFolder, path);
        file.getParentFile().mkdirs();
        return file;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // plugin.xml
    //
    ////////////////////////////////////////////////////////////////////////////
    private static class ExtensionDeclaration {
        String m_pointId;
        String m_id;
        String m_qualifiedId;
        String[] m_lines;

        boolean isInstalled() {
            return ExternalFactoriesHelper.getExtension(m_pointId, m_qualifiedId) != null;
        }
    }

    private static int m_nextExtensionId = 0;
    private final List<ExtensionDeclaration> m_extensions = Lists.newArrayList();

    public void addExtension(String pointId, String... lines) {
        ExtensionDeclaration extension = new ExtensionDeclaration();
        extension.m_pointId = pointId;
        extension.m_id = "test_" + m_nextExtensionId++;
        extension.m_qualifiedId = m_id + "." + extension.m_id;
        extension.m_lines = lines;
        m_extensions.add(extension);
    }

    public void setPluginExtensions() throws Exception {
        String content = "";
        content += "<plugin>\n";
        for (ExtensionDeclaration extension : m_extensions) {
            content += "\t<extension point='" + extension.m_pointId + "' id='" + extension.m_id + "'>\n";
            content += "\t\t" + StringUtils.join(extension.m_lines, "\n\t\t");
            content += "\n";
            content += "\t</extension>\n";
        }
        content += "</plugin>";
        setFile("plugin.xml", content);
    }

    private void waitForExtensionsInstalled() {
        while (!areAllExtensionsInstalled()) {
            TestUtils.waitEventLoop(1);
        }
    }

    private void waitForExtensionsUnInstalled() {
        while (!areAllExtensionsUnInstalled()) {
            TestUtils.waitEventLoop(1);
        }
    }

    private boolean areAllExtensionsInstalled() {
        for (ExtensionDeclaration extension : m_extensions) {
            if (!extension.isInstalled()) {
                return false;
            }
        }
        return true;
    }

    private boolean areAllExtensionsUnInstalled() {
        for (ExtensionDeclaration extension : m_extensions) {
            if (extension.isInstalled()) {
                return false;
            }
        }
        return true;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Class utils
    //
    ////////////////////////////////////////////////////////////////////////////
    public static InputStream getClassBytes(Class<?> clazz) {
        return getClassBytes(clazz.getClassLoader(), clazz.getName());
    }

    public static InputStream getClassBytes(ClassLoader classLoader, String className) {
        String bytesPath = className.replace('.', '/') + ".class";
        InputStream inputStream = classLoader.getResourceAsStream(bytesPath);
        Assert.isNotNull(inputStream, "Unable to find %s bytes.", className);
        return inputStream;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Control
    //
    ////////////////////////////////////////////////////////////////////////////
    public void install() throws Exception {
        install(false);
    }

    public void install(boolean pack2jar) throws Exception {
        if (!m_extensions.isEmpty()) {
            setPluginExtensions();
        }
        install0(pack2jar);
        waitForExtensionsInstalled();
    }

    private void install0(boolean pack2jar) throws Exception, BundleException {
        doCreate(pack2jar);
        doInstall();
        m_bundle.start();
    }

    private void doCreate(boolean pack2jar) throws Exception {
        setFile("META-INF/MANIFEST.MF",
                StringUtils.join(new String[] { "Manifest-Version: 1.0", "Bundle-ManifestVersion: 2",
                        MessageFormat.format("Bundle-SymbolicName: {0};singleton:=true", m_id),
                        "Bundle-Version: 1.0.0", "Bundle-ClassPath: .",
                        "Require-Bundle: org.eclipse.wb.core,org.eclipse.wb.core.java,org.eclipse.wb.core.xml",
                        "Bundle-ActivationPolicy: lazy" }, "\n"));
        if (pack2jar) {
            pack2jar();
        }
        m_created = true;
    }

    private void pack2jar() throws Exception {
        File bundleJarFile = new File(m_bundleFolder.getParent(), m_id + ".jar");
        // pack into JAR file
        {
            ZipFileFactory jarFile = new ZipFileFactory(new FileOutputStream(bundleJarFile));
            pack2jar(m_bundleFolder, jarFile, StringUtils.EMPTY);
            jarFile.close();
        }
        // use JAR file instead of folder (already deleted)
        m_bundleFile = bundleJarFile;
    }

    private void pack2jar(File folder, ZipFileFactory jar, String root) throws Exception {
        for (File file : folder.listFiles()) {
            if (file.isFile()) {
                jar.add(root + file.getName(), new FileInputStream(file));
            }
            if (file.isDirectory()) {
                pack2jar(file, jar, root + file.getName() + "/");
            }
            file.delete();
        }
        folder.delete();
    }

    private void doInstall() throws Exception {
        m_bundle = m_context.installBundle(m_bundleFile.toURI().toURL().toExternalForm());
    }

    public void uninstall() throws Exception {
        Assert.isNotNull(m_bundle, "Bundle %s is not installed.", m_id);
        // we should wait until OSGi framework notifies all listeners that Bundle was uninstalled
        final AtomicBoolean uninstallEventProcessed = new AtomicBoolean();
        m_context.addBundleListener(new BundleListener() {
            public void bundleChanged(BundleEvent event) {
                if (event.getType() == BundleEvent.UNINSTALLED && event.getBundle() == m_bundle) {
                    uninstallEventProcessed.set(true);
                    m_context.removeBundleListener(this);
                }
            }
        });
        // request uninstalling
        m_bundle.uninstall();
        // wait for Bundle uninstalling event
        while (!uninstallEventProcessed.get()) {
            try {
                Thread.sleep(0);
            } catch (Throwable e) {
            }
        }
        // wait for uninstalling extensions
        waitForExtensionsUnInstalled();
        // done, we can clear reference now
        m_bundle = null;
    }

    public void dispose() throws Exception {
        // uninstall, if not yet
        if (m_bundle != null) {
            uninstall();
        }
        // remove folder or file
        FileUtils.deleteDirectory(m_bundleFolder);
        m_bundleFile.delete();
    }

    public void waitForExtension(String pointId, String extensionId) throws Exception {
        String qualifiedExtensionId = m_id + "." + extensionId;
        while (ExternalFactoriesHelper.getExtension(pointId, qualifiedExtensionId) == null) {
            TestUtils.waitEventLoop(0);
        }
    }

    public void waitForNoExtension(String pointId, String extensionId) throws Exception {
        String qualifiedExtensionId = m_id + "." + extensionId;
        while (ExternalFactoriesHelper.getExtension(pointId, qualifiedExtensionId) != null) {
            TestUtils.waitEventLoop(0);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Access
    //
    ////////////////////////////////////////////////////////////////////////////
    public String getId() {
        return m_id;
    }

    public Bundle getBundle() {
        return m_bundle;
    }
}