All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bear.plugins.java.TomcatPlugin Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2013 Andrey Chaschev.
 *
 * 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 bear.plugins.java;

import bear.console.AbstractConsole;
import bear.console.ConsoleCallback;
import bear.console.ConsoleCallbackResult;
import bear.context.AbstractContext;
import bear.context.Fun;
import bear.core.GlobalContext;
import bear.core.SessionContext;
import bear.plugins.ConfigureServiceInput;
import bear.plugins.ServerToolPlugin;
import bear.plugins.misc.*;
import bear.session.DynamicVariable;
import bear.session.Variables;
import bear.task.*;
import com.google.common.base.Function;
import org.apache.commons.io.FilenameUtils;

import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static bear.session.BearVariables.joinPath;
import static bear.session.Variables.*;
import static java.lang.Integer.parseInt;
import static java.lang.String.format;
import static org.apache.commons.lang3.StringUtils.substringBetween;

/**
 * https://gist.github.com/alanfranz/6902429 - tomcat6 upstart script
 * http://stackoverflow.com/questions/16110528/tomcat-multiple-instances-simultaneously?answertab=active#tab-top
 * http://kief.com/running-multiple-tomcat-instances-on-one-server.html
 *
 * $CATALINA_HOME represents the root of the Tomcat installation; in CentOS the default value is /usr/share/tomcat6. Under the root you'll find two directories:
 * $CATALINA_BASE is used when Tomcat is configured to run multiple instances. If defined, Tomcat calculates all relative references for files in the following directories on the basis of the value set for CATALINA_BASE instead of CATALINA_HOME:
 *
 * https://github.com/rhunter/capistrano-tomcat/blob/master/lib/capistrano/tomcat.rb
 *
 * @author Andrey Chaschev [email protected]
 */
public class TomcatPlugin extends ServerToolPlugin {
    UpstartPlugin upstart;
    ReleasesPlugin releases;
    JavaPlugin java;

    public final DynamicVariable
        webappsUnix = joinPath(homePath, "webapps"),
        webappsWin = dynamic(""),
        webappsPath = concat(instancePath, "/webapps"),
        confPath = concat(instancePath, "/conf"),
        logsPath = concat(instancePath, "/logs"),
        tempPath = concat(instancePath, "/temp"),
        workPath = concat(instancePath, "/work"),
        warName = strVar("i.e. ROOT.war"),
        instanceWarPath = joinPath(instancePath, warName),
        javaOpts = newVar("-Djava.awt.headless=true"),
        catalinaOpts = newVar("\"-Xms512M -Xmx1024M -server -XX:+UseParallelGC -XX:PermSize=128m -XX:MaxPermSize=256m\""),
        basePort = newVar("8005"),
        ajpPort = newVar("8009"),
        httpPort = newVar("8080"),
        httpsPort = newVar("8443"),
        keystrokePassword = Variables.dynamic(""),
        catalinaHome = equalTo(homePath);


    public TomcatPlugin(GlobalContext global) {
        super(global);

        version.set("6.0.37");
        toolname.set("tomcat");
        toolDistrName.set("apache-tomcat");

        instancePorts.set("8080");
        consoleLogPath.setEqualTo(concat(logsPath, "/", envString, ".log").temp());
//        instanceLogsPath.setEqualTo(concat(logsPath));
//        webapps = condition(cap.isUnix, webappsUnix, webappsWin);

        execPath.setEqualTo(concat(catalinaHome, "/bin/catalina.sh"));

        multiServiceName.setEqualTo(concat(toolname, "-%s"));
        singleServiceName.setEqualTo(toolname);

        groupName.setEqualTo(toolname);

        distrWwwAddress.setDynamic(new Fun() {
            public String apply(AbstractContext $) {
                String version = $.var(TomcatPlugin.this.version);

                switch (version.charAt(0)) {
                    case '6':
                        return MessageFormat.format("http://apache-mirror.rbc.ru/pub/apache/tomcat/tomcat-6/v{0}/bin/apache-tomcat-{0}.tar.gz", version);
                    default:
                        return MessageFormat.format("http://apache-mirror.rbc.ru/pub/apache/tomcat/tomcat-7/v{0}/bin/apache-tomcat-{0}.tar.gz", version);

                }
            }
        });

        configureService.setEqualTo(dynamic(new Fun>() {
            @Override
            public Function apply(SessionContext $) {
                return newBasicUpstartConfigurator($);
            }
        }).temp());


        createScriptText.setEqualTo(dynamic(new Fun>() {
            @Override
            public Function apply(SessionContext $) {
                return newBasicUpstartScriptText($);
            }
        }).temp());
    }

    @Override
    public void initPlugin() {
        super.initPlugin();

        instancePath.setEqualTo(concat(homePath, "/instances/", toolname, "-%s"));
    }


    // copied from NodePlugin!!
    @Override
    protected void spawnStartWatchDogs(final SessionContext $, List ports) {
        final WatchDogGroup watchDogGroup = new WatchDogGroup(ports.size(), watchStartDogGroup);

        for (final String port : ports) {
            String consolePath = consoleLogPath(port, $);

            // to make sure there are no old start entries
            resetConsolePath($, consolePath);

            WatchDogRunnable runnable = new WatchDogRunnable($, watchDog, new WatchDogInput(
                consolePath, false, new ConsoleCallback() {
                @Override
                public ConsoleCallbackResult progress(final AbstractConsole.Terminal console, String buffer, String wholeText) {
                    //todo these parts are all common, extract!!
                    //todo add real crash messages
                    if(buffer.contains("app crashed - waiting for file") ){
                        return notStartedResult($, port);
                    }

                    if (buffer.contains("Server startup in")) {
                        return startedResult($, port);
                    }

                    return ConsoleCallbackResult.CONTINUE;
                }
            })
                .setTimeoutMs($.var(startupTimeoutMs))
            );

            watchDogGroup.add(runnable);
        }

        watchDogGroup.startThreads();

        watchDogGroup.scheduleForcedShutdown($.getGlobal().getScheduler(), $.var(bear.appStartTimeoutSec), TimeUnit.SECONDS);
    }

    public final TaskDef> deployWar = new TaskDef>(new TaskCallable>() {
        @Override
        public TaskResult call(SessionContext $, Task> task) throws Exception {
            String warSourcePath = $.var(releases.activatedRelease).get().path + "/" + $.var(warName);

            for (String port : $.var(portsSplit)) {
                String tomcatPath = path(webappsPath, port, $) + "/" + FilenameUtils.getBaseName($.var(warName));

                $.sys.rm(tomcatPath).sudo().run();
                $.sys.mkdirs(tomcatPath).withUser($.var(user)).run();

                $.sys.unzip(warSourcePath).to(tomcatPath).withUser($.var(user)).run().throwIfError();
            }

            return TaskResult.OK;
        }
    });

    // todo add                         $.sys.rm(RmInput.newRm($(warCacheDirs)).sudo());

    public final InstallationTaskDef install = new ZippedToolTaskDef(new SingleTaskSupplier>() {
        @Override
        public Task> createNewSession(SessionContext $, final Task> parent, final TaskDef> def) {
            return new ZippedTool(parent, (InstallationTaskDef) def, $) {
                @Override
                protected TaskResult exec(SessionRunner runner) {
                    clean();

                    download();

                    extractToHomeDir();

                    shortCut("catalina", "bin/catalina.sh");

                    DependencyResult result = verify();

                    String serverXmlAsString = $.sys.readString($(homePath) + "/conf/server.xml", null);

                    List ports = $.var(portsSplit);

                    int firstPortI = parseInt(ports.get(0));

                    logger.info("creating folder structure for {} instances", ports.size());

                    String userWithGroup = $(TomcatPlugin.this.userWithGroup);

                    for (final String port : ports) {
                        final String instancePath = instancePath(port, $);

                        String[] dirs = {$(webappsPath), $(tempPath), $(logsPath), $(confPath), $(workPath)};

                        for (int i = 0; i < dirs.length; i++) {
                            dirs[i] = format(dirs[i], port);
                        }

                        $.sys.mkdirs(dirs).sudo().withUser(userWithGroup).run();
                        $.sys.copy($(homePath) + "/conf").to(instancePath).sudo().withUser(userWithGroup).run();

                        int portI = parseInt(port);

                        int diff = portI - firstPortI;

                        //todo make links for logs in /var/log

                        String instanceServerXml = serverXmlAsString
                            .replace("port=\"8080\"", "port=\"" + (firstPortI + diff) + "\"")
                            .replace("port=\"8005\"", "port=\"" + (parseInt($(basePort)) + diff) + "\"")
                            .replace("redirectPort=\"8443\"", "redirectPort=\"" + (parseInt($(httpsPort)) + diff) + "\"")
                            .replace("port=\"8009\"", "port=\"" + (parseInt($(ajpPort)) + diff) + "\"")
                            ;

                        $.sys.writeString(instanceServerXml)
                            .toPath(format($(confPath) + "/server.xml", port))
                            .sudo()
                            .withUser(userWithGroup)
                            .run();

                        $.put(configureService, newBasicUpstartConfigurator($));

                        $.put(createScriptText, newBasicUpstartScriptText($));
                    }

                    TaskResult upstartResult = $.runSession(
                        upstart.create.singleTaskSupplier().createNewSession($, parent, upstart.create),
                        $.var(customUpstart)
                    );

                    if(upstartResult.nok()){
                        result.add(upstartResult.toString());
                    }

                    return result;
                }

                @Override
                protected String extractVersion(String output) {
                    return substringBetween(output, "Server version: Apache Tomcat/", "\r");
                }

                @Override
                protected String createVersionCommandLine() {
                    return "catalina version";
                }
            };
        }
    });

    public Function newBasicUpstartScriptText(final SessionContext $) {
        return new Function() {
            @Override
            public String apply(String port) {
                $.sys.rm(path(instanceLogsPath, port, $)).run();
                $.sys.link(path(instanceLogsPath, port, $)).toSource(path(logsPath, port, $));

                final String logPath = consoleLogPath(port, $);

                resetConsolePath($, logPath);

                return "exec su -s /bin/sh -c 'exec \"$0\" \"$@\"' " + $.var(TomcatPlugin.this.user) + " -- " +
                    $.var(execPath) + " run " + logPath + " >" + logPath + " 2>&1";
            }
        };
    }

    public Function newBasicUpstartConfigurator(final SessionContext $) {
        return new Function() {
            @Override
            public Void apply(ConfigureServiceInput in) {
                String tempPath = path(TomcatPlugin.this.tempPath, in.port, $);

                in.service
                    .exportVar("CATALINA_BASE", instancePath(in.port, $))
                    .exportVar("CATALINA_HOME", $.var(homePath))
                    .exportVar("CATALINA_TMPDIR", tempPath)
                ;

                if($.isDefined(javaOpts)){
                    in.service.exportVar("JAVA_OPTS", $.var(javaOpts));
                }

                if($.isDefined(catalinaOpts)){
                    in.service.exportVar("CATALINA_OPTS", $.var(catalinaOpts));
                }

                in.service.setCustom("\n" +
                    "# cleanup temp directory after stop\n" +
                    "post-stop script \n" +
                    "  rm -rf " + tempPath +"/*\n" +
                    "end script");

                return null;
            }
        };
    }

    @Override
    public InstallationTaskDef getInstall() {
        return install;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy