com.googlecode.jeeunit.jboss7.EmbeddedJBoss7Container.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.jeeunit.jboss7.EmbeddedJBoss7Container.java

Source

/*
 * Copyright 2011 Harald Wellmann
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.googlecode.jeeunit.jboss7;

import static com.googlecode.jeeunit.impl.Constants.*;
import static com.googlecode.jeeunit.impl.Constants.JEEUNIT_CONTEXT_ROOT;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

import org.apache.commons.io.FileUtils;
import org.glassfish.embeddable.archive.ScatteredArchive;
import org.glassfish.embeddable.archive.ScatteredArchive.Type;
import org.jboss.as.embedded.EmbeddedServerFactory;
import org.jboss.as.embedded.ServerStartException;
import org.jboss.as.embedded.StandaloneServer;

import com.googlecode.jeeunit.impl.ClasspathFilter;
import com.googlecode.jeeunit.impl.Configuration;
import com.googlecode.jeeunit.impl.ConfigurationLoader;
import com.googlecode.jeeunit.impl.ZipExploder;
import com.googlecode.jeeunit.spi.ContainerLauncher;

/**
 * Singleton implementing the {@link ContainerLauncher} functionality for Embedded Tomcat 7. The
 * configuration file for the deployed web app is expected in
 * {@code src/test/resources/META-INF/context.xml}.
 * <p>
 * {@link Tomcat} does not let us start the server first and then deploy apps, so we actually
 * start the container and deploy the application in {@code autodeploy()}.
 * <p>
 * For configuring the Tomcat 7 container provide a properties file {@code jeeunit.properties}
 * in the classpath root. You can set the following properties:
 * <ul>
 * <li>{@code jeeunit.tomcat7.http.port} port for the embedded HTTP server (default: 8080)</li>
 * <li>{@code jeeunit.tomcat7.weld.listener} add Weld listener to web.xml? (default: false)</li>
 * </ul>
 *  
 * @author hwellmann
 * 
 */
public class EmbeddedJBoss7Container implements ContainerLauncher {

    private static EmbeddedJBoss7Container instance;

    private FileFilter classpathFilter;

    private String applicationName;
    private String contextRoot;
    private File configuration;
    private boolean isDeployed;

    private List<File> metadataFiles = new ArrayList<File>();

    private File tempDir;

    private File webappsDir;

    private File jeeunitWar;

    /**
     * Default filter suppressing Tomcat and Eclipse components from the classpath when building the
     * ad hoc WAR.
     * 
     * @author hwellmann
     * 
     */
    private static String[] excludes = { "jboss", "xnio", "jandex", ".cp", "servlet-", "geronimo-servlet_",
            "shrinkwrap-", };

    private Configuration config;

    private StandaloneServer server;

    private EmbeddedJBoss7Container() {
        tempDir = createTempDir();

        setApplicationName(JEEUNIT_APPLICATION_NAME);
        setContextRoot(JEEUNIT_CONTEXT_ROOT);
        setClasspathFilter(new ClasspathFilter(excludes));

        createDefaultMetadata();
    }

    private void createDefaultMetadata() {
        File webInf = new File("src/main/webapp/WEB-INF");
        metadataFiles.add(new File(webInf, "web.xml"));
        File beansXml = new File(webInf, "beans.xml");
        if (!beansXml.exists()) {
            beansXml = new File(tempDir, "beans.xml");
            try {
                beansXml.createNewFile();
            } catch (IOException exc) {
                throw new RuntimeException("cannot create " + beansXml);
            }
        }
        metadataFiles.add(beansXml);
    }

    public static synchronized EmbeddedJBoss7Container getInstance() {
        if (instance == null) {
            instance = new EmbeddedJBoss7Container();
        }
        return instance;
    }

    private void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                shutdown();
            }
        });
    }

    protected String getApplicationName() {
        return applicationName;
    }

    /**
     * Sets the Java EE application name.
     * 
     * @param applicationName
     */
    protected void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }

    protected String getContextRoot() {
        return contextRoot;
    }

    /**
     * Sets the context root for the deployed test application.
     * 
     * @param contextRoot
     */
    protected void setContextRoot(String contextRoot) {
        this.contextRoot = contextRoot;
    }

    protected File getConfiguration() {
        return configuration;
    }

    /**
     * Sets the configuration file for the embedded server.
     * 
     * @param configuration
     */
    protected void setConfiguration(File configuration) {
        this.configuration = configuration;
    }

    public void setClasspathFilter(FileFilter classpathFilter) {
        this.classpathFilter = classpathFilter;
    }

    public synchronized void launch() {
        if (server != null) {
            return;
        }

        config = new ConfigurationLoader().load();
        prepareDirectories();

        System.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager");
        String jbossHome = config.getServerHome();
        if (jbossHome == null)
            throw new IllegalStateException("Cannot find configuration property " + KEY_SERVER_HOME);

        File jbossHomeDir = new File(jbossHome);

        server = EmbeddedServerFactory.create(jbossHomeDir, System.getProperties(), System.getenv());

        /*
         * Running under "Run as JUnit test" from Eclipse in a separate process, we do not get
         * notified when Eclipse is finished running the test suite. The shutdown hook is just to be
         * on the safe side.
         */
        addShutdownHook();

        try {
            server.start();
        } catch (ServerStartException exc) {
            throw new RuntimeException(exc);
        }

    }

    private void prepareDirectories() {
        webappsDir = new File(tempDir, "webapps");
        webappsDir.mkdirs();
    }

    private URI buildWar() throws IOException {
        ScatteredArchive sar;
        File webResourceDir = getWebResourceDir();
        if (webResourceDir.exists() && webResourceDir.isDirectory()) {
            sar = new ScatteredArchive("jeeunit-autodeploy", Type.WAR, webResourceDir);
        } else {
            sar = new ScatteredArchive("jeeunit-autodeploy", Type.WAR);
        }
        String classpath = System.getProperty("java.class.path");
        String[] pathElems = classpath.split(File.pathSeparator);

        for (String pathElem : pathElems) {
            File file = new File(pathElem);
            if (file.exists() && classpathFilter.accept(file)) {
                sar.addClassPath(file);
            }
        }
        for (File metadata : metadataFiles) {
            if (metadata.exists()) {
                sar.addMetadata(metadata);
            }
        }
        URI warUri = sar.toURI();
        File war = new File(warUri);
        jeeunitWar = new File(webappsDir, "jeeunit.war");
        FileUtils.copyFile(war, jeeunitWar);
        return warUri;
    }

    private File getWebResourceDir() throws IOException {
        File webResourceDir;
        String warBase = config.getWarBase();
        if (warBase == null) {
            webResourceDir = new File("src/main/webapp");
        } else {
            ZipExploder exploder = new ZipExploder();
            webResourceDir = new File(tempDir, "exploded");
            webResourceDir.mkdir();
            exploder.processFile(new File(warBase).getAbsolutePath(), webResourceDir.getAbsolutePath());
        }
        return webResourceDir;
    }

    public void shutdown() {
        server.stop();
    }

    public URI autodeploy() {
        if (!isDeployed) {
            try {
                buildWar();
                // TODO This method is deprecated, but what's the alternative?
                server.deploy(jeeunitWar);
                isDeployed = true;
            } catch (IOException exc) {
                throw new RuntimeException(exc);
            } catch (ExecutionException exc) {
                throw new RuntimeException(exc);
            } catch (InterruptedException exc) {
                throw new RuntimeException(exc);
            }
        }
        return getContextRootUri();
    }

    public URI getContextRootUri() {
        try {
            return new URI(String.format("http://localhost:%d/%s/", config.getHttpPort(), getContextRoot()));
        } catch (URISyntaxException exc) {
            throw new RuntimeException(exc);
        }
    }

    public void addMetadata(File file) {
        metadataFiles.add(file);
    }

    private File createTempDir() {
        File tmpRoot = FileUtils.getTempDirectory();
        File tmpDir = new File(tmpRoot, UUID.randomUUID().toString());
        tmpDir.mkdir();
        return tmpDir;
    }

}