blob: 59fecbf8f7671b823c4c176418ad7f70157f7c76 [file] [log] [blame]
/*
* 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.tuscany.sca.war;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.io.PrintWriter;
import org.apache.tuscany.sca.tomcat.TuscanyLifecycleListener;
import org.codehaus.swizzle.stream.DelimitedTokenReplacementInputStream;
import org.codehaus.swizzle.stream.StringTokenHandler;
public class Installer {
private static boolean restartRequired;
private static boolean tuscanyHookRunning;
static {
try {
tuscanyHookRunning = TuscanyLifecycleListener.isRunning();
} catch (Throwable e) {
tuscanyHookRunning = false;
}
}
public static boolean isTuscanyHookRunning() {
return tuscanyHookRunning;
}
public static boolean isRestartRequired() {
return restartRequired;
}
private File tuscanyWAR;
private File catalinaBase;
private String status = "";
public Installer(File tuscanyWAR, File catalinaBase) {
this.tuscanyWAR = tuscanyWAR;
this.catalinaBase = catalinaBase;
}
public static boolean isInstalled() {
return false;
}
public String getStatus() {
return status;
}
public boolean install() {
try {
doInstall();
status = "Install successful, Tomcat restart required.";
restartRequired = true;
return true;
} catch (Throwable e) {
status = "Exception during install\n";
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(os);
e.printStackTrace(pw);
pw.close();
status += new String(os.toByteArray());
return false;
}
}
public boolean uninstall() {
try {
doUnintsall();
status = "Tuscany removed from server.xml, please restart Tomcat and manually remove Tuscany jars from Tomcat lib";
restartRequired = true;
return true;
} catch (Throwable e) {
status = "Exception during install";
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(os);
e.printStackTrace(pw);
status += "/n" + new String(os.toByteArray());
return false;
}
}
private void doUnintsall() {
File serverXml = new File(catalinaBase, "/conf/server.xml");
if (!(serverXml.exists())) {
throw new IllegalStateException("conf/server.xml not found: " + serverXml.getAbsolutePath());
}
removeServerXml(serverXml);
removeHostConfigXml(serverXml);
removeContextXml();
}
private boolean doInstall() {
// First verify all the file locations are as expected
if (!tuscanyWAR.exists()) {
throw new IllegalStateException("Tuscany war missing: " + tuscanyWAR.getAbsolutePath());
}
if (!catalinaBase.exists()) {
throw new IllegalStateException("Catalina base does not exist: " + catalinaBase.getAbsolutePath());
}
File serverLib = new File(catalinaBase, "/lib");
if (!(serverLib.exists())) {
// try Tomcat 5 server/lib
if (new File(catalinaBase, "/server").exists()) {
serverLib = new File(new File(catalinaBase, "/server"), "/lib");
}
}
if (!(serverLib.exists())) {
throw new IllegalStateException("Tomcat lib not found: " + serverLib.getAbsolutePath());
}
File serverXml = new File(catalinaBase, "/conf/server.xml");
if (!(serverXml.exists())) {
throw new IllegalStateException("conf/server.xml not found: " + serverXml.getAbsolutePath());
}
File tuscanyTomcatJar = findTuscanyTomcatJar(tuscanyWAR);
if (tuscanyTomcatJar == null || !tuscanyTomcatJar.exists()) {
throw new IllegalStateException("Can't find tuscany-tomcat-*.jar in: " + tuscanyWAR.getAbsolutePath());
}
// Copy tuscany-tomcat jar from the tuscany webapp web-inf/lib to Tomcat server/lib
copyFile(tuscanyTomcatJar, new File(serverLib, tuscanyTomcatJar.getName()));
// Add Tuscany LifecycleListener to Tomcat server.xml
updateServerXml(serverXml);
// Add Tuscany HostConfig to Hosts definitions in server.xml
updateHostConfigXml(serverXml);
// Add Tuscany specific default web.xml and context.xml definitions
addTuscanyWebXml();
addTuscanyContextXml();
return true;
}
private static final String tuscanyWebXML =
"\r\n\r\n" + " <!-- Tuscany Listener and Filter definitions -->\r\n" +
" <listener>\r\n" +
" <listener-class>org.apache.tuscany.sca.host.webapp.TuscanyContextListener</listener-class>\r\n" +
" </listener>\r\n" +
"\r\n" +
" <filter>\r\n" +
" <filter-name>tuscany</filter-name>\r\n" +
" <filter-class>org.apache.tuscany.sca.host.webapp.TuscanyServletFilter</filter-class>\r\n" +
" </filter>\r\n" +
"\r\n" +
" <filter-mapping>\r\n" +
" <filter-name>tuscany</filter-name>\r\n" +
" <url-pattern>/*</url-pattern>\r\n" +
" </filter-mapping>";
private void addTuscanyWebXml() {
File tuscanyWebXmlFile = new File(catalinaBase, "/conf/tuscany-web.xml");
if (!(tuscanyWebXmlFile.exists())) {
File webXmlFile = new File(catalinaBase, "/conf/web.xml");
if (!(webXmlFile.exists())) {
throw new IllegalStateException("conf/web.xml not found: " + webXmlFile.getAbsolutePath());
}
String webXML = readAll(webXmlFile);
String newWebXml = replace(webXML, "<web-app", "<web-app", ">", ">" + tuscanyWebXML);
writeAll(tuscanyWebXmlFile, newWebXml);
}
}
private static final String tuscanyContextXML =
"\r\n\r\n <!-- The Tuscany SCA default domain URI.\r\n" +
" Individual contributions may used different domains by having their \r\n" +
" context.xml files overriding this parameter. -->\r\n" +
" <Parameter name=\"org.apache.tuscany.sca.defaultDomainURI\" value=\"default\"/>";
private void addTuscanyContextXml() {
File contextXmlFile = new File(catalinaBase, "/conf/context.xml");
if ((contextXmlFile.exists())) {
String contextXML = readAll(contextXmlFile);
String newcontextXml = replace(contextXML, "<Context>", "<Context>" + tuscanyContextXML, "<", "<");
backup(contextXmlFile);
writeAll(contextXmlFile, newcontextXml);
}
}
private void removeContextXml() {
File contextXmlFile = new File(catalinaBase, "/conf/context.xml");
if ((contextXmlFile.exists())) {
String contextXML = readAll(contextXmlFile);
String oldContextXml = replace(contextXML, "<Context>" + tuscanyContextXML, "<Context>", "<", "<");
writeAll(contextXmlFile, oldContextXml);
}
}
private File findTuscanyTomcatJar(File tuscanyWAR) {
File lib = new File(tuscanyWAR, "/tomcat-lib");
for (File f : lib.listFiles()) {
if (f.getName().startsWith("tuscany-tomcat-hook-") && f.getName().endsWith(".jar")) {
return f;
}
}
return null;
}
private static final String tuscanyListener =
"\r\n" + " <!-- Tuscany plugin for Tomcat -->\r\n"
+ " <Listener className=\"org.apache.tuscany.sca.tomcat.TuscanyLifecycleListener\" />";
private void updateServerXml(File serverXmlFile) {
String serverXML = readAll(serverXmlFile);
if (!serverXML.contains(tuscanyListener)) {
String newServerXml = replace(serverXML, "<Server", "<Server", ">", ">" + tuscanyListener);
backup(serverXmlFile);
writeAll(serverXmlFile, newServerXml);
}
}
private void removeServerXml(File serverXmlFile) {
String serverXML = readAll(serverXmlFile);
if (serverXML.contains(tuscanyListener)) {
String newServerXml = replace(serverXML, "<Server", "<Server", ">" + tuscanyListener, ">");
writeAll(serverXmlFile, newServerXml);
}
}
static final String tuscanyHostConfig = " hostConfigClass=\"org.apache.tuscany.sca.tomcat.TuscanyHostConfig\" >";
private void updateHostConfigXml(File serverXmlFile) {
String serverXML = readAll(serverXmlFile);
String newServerXml = replace(serverXML, "<Host", "<Host", ">", tuscanyHostConfig);
backup(serverXmlFile);
writeAll(serverXmlFile, newServerXml);
}
private void removeHostConfigXml(File serverXmlFile) {
String serverXML = readAll(serverXmlFile);
if (serverXML.contains(tuscanyHostConfig)) {
String newServerXml = replace(serverXML, "<Host", "<Host", tuscanyHostConfig, ">");
writeAll(serverXmlFile, newServerXml);
}
}
private String replace(String inputText, String begin, String newBegin, String end, String newEnd) {
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) {
File backupFile = new File(source.getParent(), source.getName() + ".b4Tuscany");
if (!backupFile.exists()) {
copyFile(source, backupFile);
}
return true;
}
private String readAll(File file) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
String text = readAll(in);
return text;
} catch (Exception e) {
return null;
} finally {
close(in);
}
}
private String readAll(InputStream in) {
try {
// 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();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private void copyFile(File source, File destination) {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(source);
out = new FileOutputStream(destination);
writeAll(in, out);
} catch (IOException e) {
throw new IllegalStateException(e);
} 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) {
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 void close(Closeable thing) {
if (thing != null) {
try {
thing.close();
} catch (Exception ignored) {
}
}
}
private 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;
}
}
}