001// Copyright 2011, 2013 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.test;
016
017import org.apache.catalina.connector.Connector;
018import org.apache.catalina.core.StandardContext;
019import org.apache.catalina.startup.Tomcat;
020
021import java.io.File;
022
023/**
024 * Launches an instance of Tomcat.
025 *
026 * @since 5.3
027 */
028public class TomcatRunner implements ServletContainerRunner
029{
030    private final String description;
031    private final int port;
032    private final int sslPort;
033    private Tomcat tomcatServer;
034
035    public TomcatRunner(String webappFolder, String contextPath, int port, int sslPort) throws Exception
036    {
037        this.port = port;
038
039        this.sslPort = sslPort;
040
041        final String expandedPath = expand(webappFolder);
042
043        description = String.format("<TomcatRunner:%s:%s/%s (%s)", contextPath, port, sslPort, expandedPath);
044
045        tomcatServer = new Tomcat();
046
047        // Tomcat creates a folder, try to put it in an OS agnostic tmp dir
048        String tmpDir = System.getProperty("java.io.tmpdir");
049        String fileSeparator = System.getProperty("file.separator");
050        if (!tmpDir.endsWith(fileSeparator))
051            tmpDir = tmpDir + fileSeparator;
052        tomcatServer.setBaseDir(tmpDir + "tomcat");
053
054        tomcatServer.addWebapp("/", expandedPath);
055
056        tomcatServer.getConnector().setAllowTrace(true);
057
058        // SSL support
059        final File keystoreFile = new File(TapestryRunnerConstants.MODULE_BASE_DIR, "src/test/conf/keystore");
060
061        if (keystoreFile.exists())
062        {
063            final Connector https = new Connector();
064            https.setPort(sslPort);
065            https.setProperty("keystore", keystoreFile.getPath());
066            https.setProperty("keypass", "tapestry");
067            tomcatServer.getService().addConnector(https);
068        }
069
070        tomcatServer.start();
071    }
072
073    /**
074     * Immediately shuts down the server instance.
075     */
076    @Override
077    public void stop()
078    {
079        System.out.printf("Stopping Tomcat instance on port %d/%d\n", port, sslPort);
080
081        try
082        {
083            // Stop immediately and not gracefully.
084            tomcatServer.stop();
085        }
086        catch (Exception ex)
087        {
088            throw new RuntimeException("Error stopping Tomcat instance: " + ex.toString(), ex);
089        }
090
091        System.out.println("Tomcat instance has stopped.");
092    }
093
094    @Override
095    public String toString()
096    {
097        return description;
098    }
099
100    /**
101     * Needed inside Maven multi-projects to expand a path relative to the module to a complete
102     * path. If the path already is absolute and points to an existing directory, it will be used
103     * unchanged.
104     *
105     * @param moduleLocalPath
106     * @return expanded path
107     * @see TapestryRunnerConstants#MODULE_BASE_DIR
108     */
109    protected String expand(String moduleLocalPath)
110    {
111        File path = new File(moduleLocalPath);
112
113        // Don't expand if the path provided already exists.
114        if (path.isAbsolute() && path.isDirectory())
115            return moduleLocalPath;
116
117        return new File(TapestryRunnerConstants.MODULE_BASE_DIR, moduleLocalPath).getPath();
118    }
119
120}