/*
* Copyright 2012 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 org.ops4j.pax.exam.tomcat;
import static org.ops4j.pax.exam.spi.container.ContainerConstants.EXAM_APPLICATION_NAME;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Stack;
import javax.servlet.ServletException;
import org.apache.catalina.Container;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.ops4j.io.StreamUtils;
import org.ops4j.pax.exam.ExamSystem;
import org.ops4j.pax.exam.ProbeInvoker;
import org.ops4j.pax.exam.ProbeInvokerFactory;
import org.ops4j.pax.exam.TestAddress;
import org.ops4j.pax.exam.TestContainer;
import org.ops4j.pax.exam.TestContainerException;
import org.ops4j.pax.exam.TestDirectory;
import org.ops4j.pax.exam.TestInstantiationInstruction;
import org.ops4j.pax.exam.options.UrlDeploymentOption;
import org.ops4j.pax.exam.options.WarProbeOption;
import org.ops4j.spi.ServiceProviderFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Harald Wellmann
* @since 3.0.0
*/
public class TomcatTestContainer implements TestContainer {
private static final Logger LOG = LoggerFactory.getLogger(TomcatTestContainer.class);
private Stack<String> deployed = new Stack<String>();
private String probe;
private ExamSystem system;
private TestDirectory testDirectory;
private Tomcat tomcat;
private TomcatHostConfig hostConfig;
private File webappDir;
private File xmlBase;
public TomcatTestContainer(ExamSystem system) {
this.system = system;
this.testDirectory = TestDirectory.getInstance();
}
public synchronized void call(TestAddress address) {
TestInstantiationInstruction instruction = testDirectory.lookup(address);
ProbeInvokerFactory probeInvokerFactory = ServiceProviderFinder
.loadUniqueServiceProvider(ProbeInvokerFactory.class);
ProbeInvoker invoker = probeInvokerFactory.createProbeInvoker(null, instruction.toString());
invoker.call(address.arguments());
}
public synchronized long install(String location, InputStream stream) {
// just make sure we don't get an "option not recognized" warning
system.getOptions(WarProbeOption.class);
deployModule(EXAM_APPLICATION_NAME, stream);
return -1;
}
public synchronized long install(InputStream stream) {
return install("local", stream);
}
public void deployModules() {
UrlDeploymentOption[] deploymentOptions = system.getOptions(UrlDeploymentOption.class);
int numModules = 0;
for (UrlDeploymentOption option : deploymentOptions) {
numModules++;
if (option.getName() == null) {
option.name("app" + numModules);
}
deployModule(option);
}
}
private void deployModule(UrlDeploymentOption option) {
try {
URL applUrl = new URL(option.getURL());
deployModule(option.getName(), applUrl.openStream());
}
catch (MalformedURLException exc) {
throw new TestContainerException("Problem deploying " + option, exc);
}
catch (IOException exc) {
throw new TestContainerException("Problem deploying " + option, exc);
}
}
private void deployModule(String applicationName, InputStream stream) {
try {
File warFile = new File(webappDir, applicationName + ".war");
StreamUtils.copyStream(stream, new FileOutputStream(warFile), true);
tomcat.addWebapp("/" + applicationName, warFile.getAbsolutePath());
deployed.push(applicationName);
}
catch (IOException exc) {
throw new TestContainerException("Problem deploying " + applicationName, exc);
}
catch (ServletException exc) {
throw new TestContainerException("Problem deploying " + applicationName, exc);
}
}
public void cleanup() {
undeployModules();
LOG.info("stopping Tomcat");
try {
tomcat.stop();
tomcat.destroy();
}
catch (LifecycleException exc) {
throw new TestContainerException(exc);
}
}
private void undeployModules() {
Host host = tomcat.getHost();
while (!deployed.isEmpty()) {
String applicationName = deployed.pop();
Container child = host.findChild("/" + applicationName);
tomcat.getHost().removeChild(child);
}
}
public TestContainer start() {
LOG.info("starting Tomcat");
File tempDir = system.getTempFolder();
webappDir = new File(tempDir, "webapps");
webappDir.mkdirs();
tomcat = new PaxExamTomcat();
tomcat.setBaseDir(tempDir.getPath());
tomcat.enableNaming();
Host host = tomcat.getHost();
xmlBase = new File(tempDir, "conf");
xmlBase.mkdirs();
host.setXmlBase(xmlBase.getAbsolutePath());
try {
int httpPort = 9080;
Connector connector = tomcat.getConnector();
connector.setPort(httpPort);
tomcat.start();
testDirectory.setAccessPoint(new URI("http://localhost:" + httpPort
+ "/Pax-Exam-Probe/"));
}
catch (URISyntaxException exc) {
new TestContainerException(exc);
}
catch (LifecycleException exc) {
new TestContainerException(exc);
}
return this;
}
public TestContainer stop() {
cleanup();
system.clear();
return this;
}
@Override
public String toString() {
return "Tomcat";
}
@Override
public long installProbe(InputStream stream) {
install("local", stream);
probe = deployed.pop();
return -1;
}
@Override
public void uninstallProbe() {
hostConfig.unmanageApp("/" + probe);
}
}