Package org.apache.openejb.tomcat.installer

Source Code of org.apache.openejb.tomcat.installer.Installer

/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.openejb.tomcat.installer;

import org.codehaus.swizzle.stream.DelimitedTokenReplacementInputStream;
import org.codehaus.swizzle.stream.StringTokenHandler;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.jar.JarFile;

public class Installer {
    public enum Status {
        NONE, INSTALLED, REBOOT_REQUIRED
    }

    private final Paths paths;
    private Status status = Status.NONE;

    private final boolean listenerInstalled;
    private final boolean agentInstalled;

    // Thi may need to be redesigned but the goal is to provide some feedback on what happened
    private final List<String> errors = new ArrayList<String>();
    private final List<String> warnings = new ArrayList<String>();
    private final List<String> infos = new ArrayList<String>();

    public Installer(Paths paths) {
        this.paths = paths;

        // is the OpenEJB listener installed
        Boolean listenerInstalled = (Boolean) invokeStaticNoArgMethod("org.apache.openejb.loader.OpenEJBListener", "isInstalled");
        if (listenerInstalled == null) listenerInstalled = false;
        this.listenerInstalled = listenerInstalled;

        // is the OpenEJB javaagent installed
        agentInstalled = invokeStaticNoArgMethod("org.apache.openejb.javaagent.Agent", "getInstrumentation") != null;

        if (listenerInstalled && agentInstalled) {
            status = Status.INSTALLED;
        }
    }


    public boolean isListenerInstalled() {
        return listenerInstalled;
    }

    public boolean isAgentInstalled() {
        return agentInstalled;
    }

    public Status getStatus() {
        return status;
    }

    protected void install() {
        installListener();

        installJavaagent();

        installConfigFiles();
       
        if (!hasErrors()) {
            status = Status.REBOOT_REQUIRED;
        }
    }

    private void installListener() {
        if (listenerInstalled) {
//            addInfo("OpenEJB Listener already installed");
            return;
        }

        boolean copyOpenEJBLoader = true;

        // copy loader jar to lib
        File destination = new File(paths.getCatalinaLibDir(), paths.getOpenEJBLoaderJar().getName());
        if (destination.exists()) {
            if (paths.getOpenEJBLoaderJar().length() != destination.length()) {
                // md5 diff the files
            } else {
//                addInfo("OpenEJB loader jar already installed in Tomcat lib directory.");
                copyOpenEJBLoader = false;
            }
        }

        if (copyOpenEJBLoader) {
            try {
                copyFile(paths.getOpenEJBLoaderJar(), destination);
                addInfo("Copy " + paths.getOpenEJBLoaderJar().getName() + " to lib");
            } catch (IOException e) {
                addError("Unable to copy OpenEJB loader jar to Tomcat lib directory.  This will need to be performed manually.", e);
            }
        }

        // read server.xml
        String serverXmlOriginal = readAll(paths.getServerXmlFile());

        // server xml will be null if we couldn't read the file
        if (serverXmlOriginal == null) {
            return;
        }

        // does the server.xml contain our listener name... it is possible that they commented out our listener, but that would be a PITA to detect
        if (serverXmlOriginal.contains("org.apache.openejb.loader.OpenEJBListener")) {
            addWarning("OpenEJB Listener already declared in Tomcat server.xml file.");
            return;
        }

        // if we can't backup the file, do not modify it
        if (!backup(paths.getServerXmlFile())) {
            return;
        }

        // add our listener
        String newServerXml = null;
        try {
            newServerXml = replace(serverXmlOriginal,
                    "<Server",
                    "<Server",
                    ">",
                    ">\r\n" +
                            "  <!-- OpenEJB plugin for Tomcat -->\r\n" +
                            "  <Listener className=\"org.apache.openejb.loader.OpenEJBListener\" />");
        } catch (IOException e) {
            addError("Error while adding listener to server.xml file", e);
        }

        // overwrite server.xml
        if (writeAll(paths.getServerXmlFile(), newServerXml)) {
            addInfo("Add OpenEJB listener to server.xml");
        }
    }

    private void installJavaagent() {
        if (agentInstalled) {
//            addInfo("OpenEJB Agent already installed");
            return;
        }

        //
        // bin/catalina.sh
        //

        // read the catalina sh file
        String catalinaShOriginal = readAll(paths.getCatalinaShFile());

        // catalina sh will be null if we couldn't read the file
        if (catalinaShOriginal == null) {
            return;
        }

        // does the catalina sh contain our comment... it is possible that they commented out the magic script code, but there is no way to detect that
        if (catalinaShOriginal.contains("Add OpenEJB javaagent")) {
            addWarning("OpenEJB javaagent already declared in Tomcat catalina.sh file.");
            return;
        }

        // if we can't backup the file, do not modify it
        if (!backup(paths.getCatalinaShFile())) {
            return;
        }

        // add our magic bits to the catalina sh file
        String openejbJavaagentPath = paths.getCatalinaBaseDir().toURI().relativize(paths.getOpenEJBJavaagentJar().toURI()).getPath();
        String updatedAnnotationApiPath = paths.getCatalinaBaseDir().toURI().relativize(paths.getUpdatedAnnotationApiJar().toURI()).getPath();
        String newCatalinaSh = catalinaShOriginal.replace("# ----- Execute The Requested Command",
                "# Update non-compliant Tomcat annotation-api.jar\n" +
                "if [ -r \"$CATALINA_BASE\"/" + updatedAnnotationApiPath + " ]; then\n" +
                "  cp \"$CATALINA_BASE\"/" + updatedAnnotationApiPath + "  \"$CATALINA_HOME\"/lib/annotations-api.jar \n" +
                "fi\n" +
                "\n" +
                "# Add OpenEJB javaagent\n" +
                "if [ -r \"$CATALINA_BASE\"/" + openejbJavaagentPath + " ]; then\n" +
                "  JAVA_OPTS=\"\"-javaagent:$CATALINA_BASE/" + openejbJavaagentPath + "\" $JAVA_OPTS\"\n" +
                "fi\n" +
                "\n" +
                "# ----- Execute The Requested Command");

        // overwrite the catalina.sh file
        if (writeAll(paths.getCatalinaShFile(), newCatalinaSh)) {
            addInfo("Add OpenEJB JavaAgent to catalina.sh");
        }

        //
        // bin/catalina.bat
        //

        // read the catalina bat file
        String catalinaBatOriginal = readAll(paths.getCatalinaBatFile());

        // catalina bat will be null if we couldn't read the file
        if (catalinaBatOriginal == null) {
            return;
        }

        // does the catalina bat contain our comment... it is possible that they commented out the magic script code, but there is no way to detect that
        if (catalinaBatOriginal.contains("Add OpenEJB javaagent")) {
            addWarning("OpenEJB javaagent already declared in Tomcat catalina.bat file.");
            return;
        }

        // if we can't backup the file, do not modify it
        if (!backup(paths.getCatalinaBatFile())) {
            return;
        }

        // add our magic bits to the catalina bat file
        openejbJavaagentPath = openejbJavaagentPath.replace('/', '\\');
        updatedAnnotationApiPath = updatedAnnotationApiPath.replace('/', '\\');
        String newCatalinaBat = catalinaBatOriginal.replace("rem ----- Execute The Requested Command",
                "rem Update non-compliant Tomcat annotation-api.jar\r\n" +
                "if not exist \"%CATALINA_BASE%\\" + updatedAnnotationApiPath + "\" goto noUpdatedAnnotationJar\r\n" +
                "copy /Y \"%CATALINA_BASE%\\" + updatedAnnotationApiPath + "\" \"%CATALINA_HOME%\\lib\\annotations-api.jar\"\r\n" +
                ":noUpdatedAnnotationJar\r\n" +
                "\r\n" +
                "rem Add OpenEJB javaagent\r\n" +
                "if not exist \"%CATALINA_BASE%\\" + openejbJavaagentPath + "\" goto noOpenEJBJavaagent\r\n" +
                "set JAVA_OPTS=\"-javaagent:%CATALINA_BASE%\\" + openejbJavaagentPath + "\" %JAVA_OPTS%\r\n" +
                ":noOpenEJBJavaagent\r\n" +
                "\r\n" +
                "rem ----- Execute The Requested Command");

        // overwrite the catalina.bat file
        if (writeAll(paths.getCatalinaBatFile(), newCatalinaBat)) {
            addInfo("Add OpenEJB JavaAgent to catalina.bat");
//            addInfo("Added OpenEJB javaagent to Tomcat catalina.bat file.");
        }
    }

    private void installConfigFiles() {
        if (paths.getOpenEJBCoreJar() == null) {
            // the core jar contains the config files
            return;
        }
        JarFile coreJar = null;
        try {
            coreJar = new JarFile(paths.getOpenEJBCoreJar());
        } catch (IOException e) {
            return;
        }

        //
        // conf/openejb.xml
        //
        File openEjbXmlFile = new File(paths.getCatalinaConfDir(), "openejb.xml");
        if (!openEjbXmlFile.exists()) {
            // read in the openejb.xml file from the openejb core jar
            String openEjbXml = readEntry(coreJar, "default.openejb.conf");
            if (openEjbXml != null) {
                if (writeAll(openEjbXmlFile, openEjbXml)) {
                    addInfo("Copy openejb.xml to conf");
                }
            }
        }


        //
        // conf/logging.properties
        //
        String openejbLoggingProps = readEntry(coreJar, "logging.properties");
        if (openejbLoggingProps != null) {
            File loggingPropsFile = new File(paths.getCatalinaConfDir(), "logging.properties");
            String newLoggingProps = null;
            if (!loggingPropsFile.exists()) {
                newLoggingProps = openejbLoggingProps;
            } else {
                String loggingPropsOriginal = readAll(loggingPropsFile);
                if (!loggingPropsOriginal.contains("OpenEJB")) {
                    // strip off license header
                    String[] strings = openejbLoggingProps.split("## --*", 3);
                    if (strings.length == 3) {
                        openejbLoggingProps = strings[2];
                    }
                    // append our properties
                    newLoggingProps = loggingPropsOriginal +
                            "\r\n" +
                            "############################################################\r\n" +
                            "# OpenEJB Logging Configuration.\r\n" +
                            "############################################################\r\n" +
                            openejbLoggingProps + "\r\n";
                }
            }
            if (newLoggingProps != null) {
                if (writeAll(loggingPropsFile, newLoggingProps)) {
                    addInfo("Append OpenEJB config to logging.properties");
                }
            }
        }
    }

    private String readEntry(JarFile jarFile, String name) {
        ZipEntry entry = jarFile.getEntry(name);
        if (entry == null) return null;
        InputStream in = null;
        try {
            in = jarFile.getInputStream(entry);
            String text = readAll(in);
            return text;
        } catch (Exception e) {
            addError("Unable to read " + name + " from " + jarFile.getName());
            return null;
        } finally {
            close(in);
        }
    }

    private String replace(String inputText, String begin, String newBegin, String end, String newEnd) throws IOException {
        BeginEndTokenHandler tokenHandler = new BeginEndTokenHandler(newBegin, newEnd);

        ByteArrayInputStream in = new ByteArrayInputStream(inputText.getBytes());

        InputStream replacementStream = new DelimitedTokenReplacementInputStream(in, begin, end, tokenHandler, true);
        String newServerXml = readAll(replacementStream);
        close(replacementStream);
        return newServerXml;
    }

    private boolean backup(File source) {
        try {
            File backupFile = new File(source.getParent(), source.getName() + ".original");
            if (!backupFile.exists()) {
                copyFile(source, backupFile);
            }
            return true;
        } catch (IOException e) {
            addError("Unable to backup " + source.getAbsolutePath() + "; No changes will be made to this file");
            return false;
        }
    }

    private void copyFile(File source, File destination) throws IOException {
        File destinationDir = destination.getParentFile();
        if (!destinationDir.exists() && !destinationDir.mkdirs()) {
            throw new java.io.IOException("Cannot create directory : " + destinationDir);
        }

        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(source);
            out = new FileOutputStream(destination);
            writeAll(in, out);
        } finally {
            close(in);
            close(out);
        }
    }

    private boolean writeAll(File file, String text) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file);
            writeAll(new ByteArrayInputStream(text.getBytes()), fileOutputStream);
            return true;
        } catch (Exception e) {
            addError("Unable to write to " + file.getAbsolutePath(), e);
            return false;
        } finally {
            close(fileOutputStream);
        }
    }

    private void writeAll(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[4096];
        int count;
        while ((count = in.read(buffer)) > 0) {
            out.write(buffer, 0, count);
        }
        out.flush();
    }

    private String readAll(File file) {
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            String text = readAll(in);
            return text;
        } catch (Exception e) {
            addError("Unable to read " + file.getAbsolutePath());
            return null;
        } finally {
            close(in);
        }
    }

    private String readAll(InputStream in) throws IOException {
        // SwizzleStream block read methods are broken so read byte at a time
        StringBuilder sb = new StringBuilder();
        int i = in.read();
        while (i != -1) {
            sb.append((char) i);
            i = in.read();
        }
        return sb.toString();
    }

//    private String getTomcatVersion() {
//        String tomcatVersion = null;
//        try {
//            Properties properties = new Properties();
//            properties.load(getClass().getClassLoader().getResourceAsStream("org/apache/catalina/util/ServerInfo.properties"));
//            tomcatVersion = properties.getProperty("server.number");
//        } catch (IOException e) {
//        }
//        return tomcatVersion;
//    }

    private Object invokeStaticNoArgMethod(String className, String propertyName) {
        try {
            Class<?> clazz = loadClass(className, getClass().getClassLoader());
            Method method = clazz.getMethod(propertyName);
            Object result = method.invoke(null, (Object[]) null);
            return result;
        } catch (Exception e) {
            return null;
        }
    }

    private Class<?> loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
        LinkedList<ClassLoader> loaders = new LinkedList<ClassLoader>();
        for (ClassLoader loader = classLoader; loader != null; loader = loader.getParent()) {
            loaders.addFirst(loader);
        }
        for (ClassLoader loader : loaders) {
            try {
                Class<?> clazz = Class.forName(className, true, loader);
                return clazz;
            } catch (ClassNotFoundException e) {
            }
        }
        return null;
    }

    private void close(Closeable thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch (Exception ignored) {
            }
        }
    }

    private static class BeginEndTokenHandler extends StringTokenHandler {
        private final String begin;
        private final String end;

        public BeginEndTokenHandler(String begin, String end) {
            this.begin = begin;
            this.end = end;
        }

        public String handleToken(String token) throws IOException {
            String result = begin + token + end;
            return result;
        }
    }

    public void reset() {
        errors.clear();
        warnings.clear();
        infos.clear();
    }

    public boolean hasErrors() {
        return !errors.isEmpty();
    }


    public List<String> getErrors() {
        return errors;
    }

    private void addError(String message) {
        errors.add(message);
    }

    @SuppressWarnings({"UnusedDeclaration"})
    private void addError(String message, Exception e) {
        // todo add exception somehow
        System.out.println(message);
    }

    public boolean hasWarnings() {
        return !warnings.isEmpty();
    }


    public List<String> getWarnings() {
        return warnings;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    private void addWarning(String message) {
        System.out.println(message);
    }

    public boolean hasInfos() {
        return !infos.isEmpty();
    }


    public List<String> getInfos() {
        return infos;
    }

    private void addInfo(String message) {
        infos.add(message);
    }

}
TOP

Related Classes of org.apache.openejb.tomcat.installer.Installer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.