org.glassfish.tyrus.tests.qa.tools.GlassFishToolkit.java Source code

Java tutorial

Introduction

Here is the source code for org.glassfish.tyrus.tests.qa.tools.GlassFishToolkit.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2011-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.tyrus.tests.qa.tools;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.websocket.ClientEndpoint;
import javax.websocket.DeploymentException;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpoint;

import org.glassfish.tyrus.tests.qa.config.AppConfig;

import org.glassfish.embeddable.archive.ScatteredArchive;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

/**
 * @author Michal Conos (michal.conos at oracle.com)
 */
public class GlassFishToolkit implements ServerToolkit {

    private String installRoot;
    private ScatteredArchive deploy;
    private final static Logger logger = Logger.getLogger(GlassFishToolkit.class.getName());
    private static final String glassfishWeb = "<!DOCTYPE glassfish-web-app PUBLIC \"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN\" \"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd\">"
            + "<glassfish-web-app error-url=\"\">" + "<context-root>%s</context-root>"
            + "<class-loader delegate=\"true\"/>" + "<jsp-config>"
            + "<property name=\"keepgenerated\" value=\"true\">"
            + "<description>Keep a copy of the generated servlet class' java code.</description>" + "</property>"
            + "</jsp-config>" + "</glassfish-web-app>";
    private AppConfig config;

    public GlassFishToolkit(AppConfig config) {
        this.config = config;
        this.installRoot = config.getInstallRoot();
    }

    public class Asadmin {

        private final static String ASADMIN_CMD_UNIX = "%s/bin/asadmin %s";
        private final static String ASADMIN_CMD_WINDOWS = "%s/bin/asadmin.bat %s";
        private final static String ASADMIN_DEFAULT_DOMAIN = "domain1";
        private final static String ASADMIN_START_DOMAIN = "start-domain %s";
        private final static String ASADMIN_STOP_DOMAIN = "stop-domain %s";
        private final static String ASADMIN_DEPLOY_WAR = "deploy --force=true %s";
        private final static String ASADMIN_DEPLOY_WAR_PROPS = "deploy --force=true --properties %s=%s %s";
        private final static String ASADMIN_UNDEPLOY_APP = "undeploy --cascade=true %s";
        private final static String ASADMIN_LIST_APPS = "list-applications";

        private boolean onWindows() {
            return System.getProperty("os.name").startsWith("Windows");
        }

        private String getAsadminCommand() {
            if (onWindows()) {
                return ASADMIN_CMD_WINDOWS;
            } else {
                return ASADMIN_CMD_UNIX;
            }
        }

        private String getDomain() {
            final String domain = System.getProperty("glassfish.domain");
            if (domain != null) {
                return domain;
            } else {
                return ASADMIN_DEFAULT_DOMAIN;
            }
        }

        public String getAsadminStartDomain(String domain) {
            return String.format(getAsadminCommand(), installRoot, String.format(ASADMIN_START_DOMAIN, domain));
        }

        public String getAsadminStopDomain(String domain) {
            return String.format(getAsadminCommand(), installRoot, String.format(ASADMIN_STOP_DOMAIN, domain));
        }

        public String getAsadminStartDomain1() {
            return getAsadminStartDomain(getDomain());
        }

        public String getAsadminStopDomain1() {
            return getAsadminStopDomain(getDomain());
        }

        public String getAsadminListApplications() {
            return String.format(getAsadminCommand(), installRoot, ASADMIN_LIST_APPS);
        }

        public String getAsadminDeployCommand(String warfile) {
            return String.format(getAsadminCommand(), installRoot, String.format(ASADMIN_DEPLOY_WAR, warfile));
        }

        public String getAsadminDeployCommand(String warfile, String key, String value) {
            return String.format(getAsadminCommand(), installRoot,
                    String.format(ASADMIN_DEPLOY_WAR_PROPS, key, value, warfile));
        }

        public String getAsadminUnDeployCommand(String appname) {
            return String.format(getAsadminCommand(), installRoot, String.format(ASADMIN_UNDEPLOY_APP, appname));
        }

        public void exec(String cmd) {
            logger.log(Level.INFO, "asadmin.exec: {0}", cmd);
            CommandLine cmdLine = CommandLine.parse(cmd);
            DefaultExecutor executor = new DefaultExecutor();
            try {
                Map<String, String> env = System.getenv();
                //env.put("WEBSOCKET_CONTAINER", "GLASSFISH");
                int exitValue = executor.execute(cmdLine, env);
                logger.log(Level.INFO, "asadmin.exec.rc: {0}", exitValue);
                if (exitValue != 0) {
                    logger.log(Level.SEVERE, "Can't execute:{0}", cmdLine.toString());
                    throw new RuntimeException("Can't start GF server:" + exitValue);
                }

            } catch (ExecuteException ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex.getMessage());
            } catch (IOException ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex.getMessage());
            }
        }

        public void exec(String[] commands) {
            for (String cmd : commands) {
                exec(cmd);
            }
        }
    }

    private File createWebXml(String path) throws IOException {
        File webXml = File.createTempFile("glassfish-web", "xml");
        FileUtils.writeStringToFile(webXml, String.format(glassfishWeb, path));
        return webXml;
    }

    private String getClazzCanonicalName(File clazz) {
        logger.log(Level.FINE, "getClazzCanonicalName:{0}", clazz.toString());
        return FilenameUtils.removeExtension(FilenameUtils.separatorsToUnix(clazz.toString()))
                .replaceFirst("target/classes/", "").replace('/', '.');
    }

    private File getDirname(File clazz) {
        return new File(new File(getClazzCanonicalName(clazz).replace('.', '/')).getParent());
    }

    private Class<?> getClazzForFile(File clazz) throws ClassNotFoundException, MalformedURLException {
        String clazzCanonicalName = getClazzCanonicalName(clazz);
        //URLClassLoader cl = new URLClassLoader(new URL[] {new URL("file://"+clazz.getAbsoluteFile().getParent())});
        logger.log(Level.FINE, "getClazzForFile(): {0}", clazzCanonicalName);
        logger.log(Level.FINE, "getClazzForFile(): {0}", clazz.getAbsolutePath());
        //logger.log(Level.FINE, "getClazzForFile(): classloader:{0}", cl.getURLs());
        return Class.forName(clazzCanonicalName); //, true, cl);
    }

    private boolean isBlackListed(File clazz) throws ClassNotFoundException, MalformedURLException {
        //logger.log(Level.FINE, "File? {0}", clazzCanonicalName);

        Class tryMe = getClazzForFile(clazz);

        logger.log(Level.FINE, "File? {0}", tryMe.getCanonicalName());

        logger.log(Level.FINE, "Interfaces:{0}", tryMe.getInterfaces());
        if (Arrays.asList(tryMe.getInterfaces()).contains((ServerApplicationConfig.class))) {
            logger.log(Level.FINE, "ServerApplicationConfig : {0}", tryMe.getCanonicalName());
            return true;
        }
        if (tryMe.isAnnotationPresent(ServerEndpoint.class)) {
            logger.log(Level.FINE, "Annotated ServerEndpoint: {0}", tryMe.getCanonicalName());
            return true;
        }

        if (tryMe.isAnnotationPresent(ClientEndpoint.class)) {
            logger.log(Level.FINE, "Annotated ClientEndpoint: {0}", tryMe.getCanonicalName());
            return true;
        }
        //Endpoint itself is not blacklisted
        // TYRUS-150
        //if (Endpoint.class.isAssignableFrom(tryMe)) {
        //    logger.log(Level.INFO, "Programmatic Endpoint: {0}", tryMe.getCanonicalName());
        //    return true;
        //}

        return false;
    }

    private File getFileForClazz(Class clazz) {
        logger.log(Level.FINE, "Obtaining file for : {0}", clazz.getCanonicalName());

        String clazzBasename = new File(clazz.getCanonicalName().replace('.', '/')).getName();

        return new File(getDirname(new File(clazz.toString())), clazzBasename);
    }

    public ScatteredArchive makeWar(Class clazz, String path)
            throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
        ScatteredArchive archive = new ScatteredArchive("testapp", ScatteredArchive.Type.WAR);
        String name = clazz.getName();

        //archive.addClassPath(new File("target/classes"));
        List<File> addClasses = new ArrayList<File>();
        File tempDir = FileUtils.getTempDirectory();
        Path dir = Files.createTempDirectory(Paths.get(tempDir.toURI()), null);
        File dstDirectory = new File(dir.toFile(), "lib");
        FileUtils.forceMkdir(dstDirectory);
        logger.log(Level.INFO, "BEFORE: Target WAR: {0}", FileUtils.listFiles(dstDirectory, null, true));
        File source = new File("target/classes");
        Set<File> warFiles = new HashSet<File>();
        for (File addMe : FileUtils.listFiles(source, new String[] { "class" }, true)) {
            String srcClazzCanonicalName = getClazzForFile(addMe).getCanonicalName();
            if (srcClazzCanonicalName != null && srcClazzCanonicalName.equals(clazz.getCanonicalName())) {
                warFiles.add(addMe);
                continue;
            }
            if (!isBlackListed(addMe)) {
                warFiles.add(addMe);
            }
        }
        Misc.copyFiles(warFiles, dstDirectory, "^target/classes", "");
        archive.addClassPath(dstDirectory);
        archive.addMetadata(createWebXml(path), "WEB-INF/glassfish-web.xml");
        logger.log(Level.INFO, "Target WAR: {0}", FileUtils.listFiles(dstDirectory, null, true));
        return archive;
    }

    private String getLocalFileFromURI(URI file) {
        if (file.getScheme().equals("file")) {
            return file.toString().replaceFirst("file:", "");
        }
        return null;
    }

    @Override
    public void startServer() throws DeploymentException {
        try {
            Asadmin asadmin = new Asadmin();
            asadmin.exec(new String[] { asadmin.getAsadminStartDomain1(),
                    asadmin.getAsadminDeployCommand(getLocalFileFromURI(deploy.toURI())),
                    asadmin.getAsadminListApplications() });
            try {
                Thread.sleep(10000);
            } catch (InterruptedException ex) {
                Logger.getLogger(GlassFishToolkit.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }

    @Override
    public void stopServer() {
        try {
            Asadmin asadmin = new Asadmin();
            if (deploy != null) {
                String appname = FilenameUtils
                        .removeExtension(new File(getLocalFileFromURI(deploy.toURI())).getName());
                try {
                    asadmin.exec(asadmin.getAsadminUnDeployCommand(appname));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            asadmin.exec(new String[] { asadmin.getAsadminListApplications(), asadmin.getAsadminStopDomain1() });
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }

    @Override
    public void registerEndpoint(Class<?> endpoint) {
        try {
            this.deploy = makeWar(endpoint, config.getContextPath());
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        } catch (URISyntaxException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }
}