blob: 73da1213c887e6898c2735551bfdaa99a9dd3228 [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.karaf.kittests;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.felix.utils.properties.InterpolationHelper;
import org.apache.karaf.util.process.PumpStreamHandler;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public final class Helper {
private Helper() {
}
public static class Instance {
public static final String STOPPED = "Stopped";
public static final String STARTING = "Starting";
public static final String STARTED = "Started";
public static final String ERROR = "Error";
private static final String CONFIG_PROPERTIES_FILE_NAME = "config.properties";
private static final String KARAF_SHUTDOWN_PORT = "karaf.shutdown.port";
private static final String KARAF_SHUTDOWN_HOST = "karaf.shutdown.host";
private static final String KARAF_SHUTDOWN_PORT_FILE = "karaf.shutdown.port.file";
private static final String KARAF_SHUTDOWN_COMMAND = "karaf.shutdown.command";
private static final String KARAF_SHUTDOWN_PID_FILE = "karaf.shutdown.pid.file";
private static final String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN";
private String location;
private Process process;
public Instance(String location, Process process) {
this.location = location;
this.process = process;
}
public boolean exists() {
return new File(location).isDirectory();
}
public int getSshPort() {
InputStream is = null;
try {
File f = new File(location, "etc/org.apache.karaf.shell.cfg");
is = new FileInputStream(f);
Properties props = new Properties();
props.load(is);
String loc = props.getProperty("sshPort");
return Integer.parseInt(loc);
} catch (Exception e) {
return 0;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// Ignore
}
}
}
}
public synchronized String getState() {
int port = getSshPort();
if (!exists() || port <= 0) {
return ERROR;
}
checkProcess();
if (this.process == null) {
return STOPPED;
} else {
try {
Socket s = new Socket("localhost", port);
s.close();
return STARTED;
} catch (Exception e) {
// ignore
}
return STARTING;
}
}
protected void checkProcess() {
if (this.process != null) {
try {
this.process.exitValue();
this.process = null;
} catch (IllegalThreadStateException e) {
}
}
}
private static String getProperty(Map<String,String> props, String key, String deflt) {
String res = props.get(key);
if (res == null) {
res = deflt;
}
return res;
}
public void stop() throws Exception {
checkProcess();
if (this.process != null) {
// Try a clean shutdown
cleanShutdown();
if (this.process != null) {
this.process.destroy();
}
}
}
protected void cleanShutdown() {
try {
File file = new File(new File(location, "etc"), CONFIG_PROPERTIES_FILE_NAME);
URL configPropURL = file.toURI().toURL();
Map<String,String> props = loadPropertiesFile(configPropURL);
props.put("karaf.base", new File(location).getCanonicalPath());
props.put("karaf.home", new File(location).getCanonicalPath());
props.put("karaf.data", new File(new File(location), "data").getCanonicalPath());
InterpolationHelper.performSubstitution(props);
int port = Integer.parseInt(getProperty(props, KARAF_SHUTDOWN_PORT, "0"));
String host = getProperty(props, KARAF_SHUTDOWN_HOST, "localhost");
String portFile = props.get(KARAF_SHUTDOWN_PORT_FILE);
String shutdown = getProperty(props, KARAF_SHUTDOWN_COMMAND, DEFAULT_SHUTDOWN_COMMAND);
if (port == 0 && portFile != null) {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(portFile)));
String portStr = r.readLine();
port = Integer.parseInt(portStr);
r.close();
}
// We found the port, try to send the command
if (port > 0) {
Socket s = new Socket(host, port);
s.getOutputStream().write(shutdown.getBytes());
s.close();
long t = System.currentTimeMillis() + 5000;
do {
Thread.sleep(100);
checkProcess();
} while (System.currentTimeMillis() < t && process != null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected static Map<String,String> loadPropertiesFile(URL configPropURL) throws Exception {
// Read the properties file.
Properties configProps = new Properties();
InputStream is = null;
try {
is = configPropURL.openConnection().getInputStream();
configProps.load(is);
is.close();
}
catch (Exception ex) {
System.err.println(
"Error loading config properties from " + configPropURL);
System.err.println("Main: " + ex);
try {
if (is != null) is.close();
}
catch (IOException ex2) {
// Nothing we can do.
}
return null;
}
return (Map) configProps;
}
}
protected static final boolean IS_WINDOWS_OS = System.getProperty("os.name").toLowerCase().contains("windows");
public static void extractKit(File targetDir) throws Exception {
if (isWindowsOs()) {
extractWindowsKit(targetDir);
} else {
extractUnixKit(targetDir);
}
}
public static boolean isWindowsOs() {
return IS_WINDOWS_OS;
}
protected static void extractWindowsKit(File targetDir) throws Exception {
InputStream is = Helper.class.getResourceAsStream("/karaf.zip");
extract(new ZipArchiveInputStream(is), targetDir);
}
protected static void extractUnixKit(File targetDir) throws Exception {
InputStream is = Helper.class.getResourceAsStream("/karaf.tar.gz");
extract(new TarArchiveInputStream(new GzipCompressorInputStream(is)), targetDir);
File bin = new File(targetDir, "bin");
String[] files = bin.list();
List<String> args = new ArrayList();
Collections.addAll(args, "chmod", "+x");
Collections.addAll(args, files);
Process chmod = new ProcessBuilder()
.directory(new File(targetDir, "bin"))
.command(args)
.start();
PumpStreamHandler pump = new PumpStreamHandler(System.in, System.out, System.err);
pump.attach(chmod);
pump.start();
waitForProcessEnd(chmod, 5000);
}
protected static void extract(ArchiveInputStream is, File targetDir) throws IOException {
try {
if (targetDir.exists()) {
FileUtils.forceDelete(targetDir);
}
targetDir.mkdirs();
ArchiveEntry entry = is.getNextEntry();
while (entry != null) {
String name = entry.getName();
name = name.substring(name.indexOf("/") + 1);
File file = new File(targetDir, name);
if (entry.isDirectory()) {
file.mkdirs();
} else {
file.getParentFile().mkdirs();
OutputStream os = new FileOutputStream(file);
try {
IOUtils.copy(is, os);
} finally {
IOUtils.closeQuietly(os);
}
}
entry = is.getNextEntry();
}
} finally {
is.close();
}
}
public static Process launchScript(File homeDir, String script, String args) throws IOException {
ProcessBuilder builder = new ProcessBuilder();
builder.directory(homeDir);
if (isWindowsOs()) {
builder.command("cmd.exe", "/c", new File(homeDir, "bin\\" + script + ".bat").getAbsolutePath(), args);
} else {
builder.command("/bin/sh", new File(homeDir, "bin/" + script).getAbsolutePath(), args);
}
builder.redirectErrorStream(true);
Process process = builder.start();
PumpStreamHandler pump = new PumpStreamHandler(System.in, System.out, System.err);
pump.attach(process);
pump.start();
return process;
}
public static Instance startKaraf(File home) throws Exception {
Process karaf = launchScript(home, "karaf", "server");
return new Instance(home.getAbsolutePath(), karaf);
// InstanceImpl instance = new InstanceImpl(null, "root", home.getAbsolutePath(), null, true);
// instance.attach(karaf.getPid());
// return instance;
}
public static void waitForKarafStarted(Instance karaf, long timeout) throws Exception {
for (int i = 0; i < timeout / 100; i++) {
if (Instance.STARTING.equals(karaf.getState())) {
Thread.sleep(100);
} else {
break;
}
}
if (!Instance.STARTED.equals(karaf.getState())) {
throw new Exception("Karaf did not start correctly");
}
}
public static void waitForKarafStopped(Instance karaf, long timeout) throws Exception {
waitForProcessEnd(karaf.process, timeout);
}
public static void waitForProcessEnd(Process process, long timeout) throws Exception {
for (int i = 0; i < timeout / 100; i++) {
try {
process.exitValue();
return;
} catch (IllegalThreadStateException e) {
}
Thread.sleep(100);
}
throw new Exception("Process is still running");
}
public static void kill(Process process) {
try {
process.destroy();
} catch (Throwable e) {
}
}
public static void kill(Instance instance) {
try {
instance.stop();
} catch (Throwable e) {
}
}
}