/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.test.integration.ee.appclient.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
/**
* @author Dominik Pospisil <dpospisi@redhat.com>
* @author Stuart Douglas
*/
public class AppClientWrapper implements Runnable {
private String appClientCommand = null;
private static final String outThreadHame = "APPCLIENT-out";
private static final String errThreadHame = "APPCLIENT-err";
private Process appClientProcess;
private PrintWriter writer;
private BufferedReader outputReader;
private BufferedReader errorReader;
private BlockingQueue<String> outputQueue = new LinkedBlockingQueue<String>();
private Thread shutdownThread;
private final Archive<?> archive;
private final String clientArchiveName;
private final String appClientArgs;
private File archiveOnDisk;
private final String args;
/**
* Creates new CLI wrapper. If the connect parameter is set to true the CLI
* will connect to the server using <code>connect</code> command.
*
*
* @param archive
* @param clientArchiveName
* @param args
* @throws Exception
*/
public AppClientWrapper(final Archive<?> archive,final String appClientArgs, final String clientArchiveName, final String args) throws Exception {
this.archive = archive;
this.clientArchiveName = clientArchiveName;
this.args = args;
this.appClientArgs = appClientArgs;
init();
}
/**
* Consumes all available output from App Client.
*
* @param timeout number of milliseconds to wait for each subsequent line
* @return array of App Client output lines
*/
public String[] readAll(final long timeout) {
Vector<String> lines = new Vector<String>();
String line = null;
do {
try {
line = outputQueue.poll(timeout, TimeUnit.MILLISECONDS);
if (line != null) lines.add(line);
} catch (InterruptedException ioe) {
}
} while (line != null);
return lines.toArray(new String[]{});
}
/**
* Consumes all available output from CLI.
*
* @param timeout number of milliseconds to wait for each subsequent line
* @return array of CLI output lines
*/
public String readAllUnformated(long timeout) {
String[] lines = readAll(timeout);
StringBuilder buf = new StringBuilder();
for (String line : lines) buf.append(line + "\n");
return buf.toString();
}
/**
* Kills the app client
*
* @throws Exception
*/
public synchronized void quit() throws Exception {
appClientProcess.destroy();
try {
appClientProcess.waitFor();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Runtime.getRuntime().removeShutdownHook(shutdownThread);
if (archiveOnDisk != null) {
archiveOnDisk.delete();
}
}
private void init() throws Exception {
shutdownThread = new Thread(new Runnable() {
@Override
public void run() {
if (appClientProcess != null) {
appClientProcess.destroy();
if (archiveOnDisk != null) {
archiveOnDisk.delete();
}
try {
appClientProcess.waitFor();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Runtime.getRuntime().addShutdownHook(shutdownThread);
appClientProcess = Runtime.getRuntime().exec(getAppClientCommand());
writer = new PrintWriter(appClientProcess.getOutputStream());
outputReader = new BufferedReader(new InputStreamReader(appClientProcess.getInputStream()));
errorReader = new BufferedReader(new InputStreamReader(appClientProcess.getErrorStream()));
final Thread readOutputThread = new Thread(this, outThreadHame);
readOutputThread.start();
final Thread readErrorThread = new Thread(this, errThreadHame);
readErrorThread.start();
}
private String getAppClientCommand() throws Exception {
if (appClientCommand != null) return appClientCommand;
final String tempDir = System.getProperty("java.io.tmpdir");
archiveOnDisk = new File(tempDir + File.separator + archive.getName());
if(archiveOnDisk.exists()) {
archiveOnDisk.delete();
}
final ZipExporter exporter = archive.as(ZipExporter.class);
exporter.exportTo(archiveOnDisk);
final String archiveArg;
if(clientArchiveName == null) {
archiveArg = archiveOnDisk.getAbsolutePath();
} else {
archiveArg = archiveOnDisk.getAbsolutePath() + "#" + clientArchiveName;
}
// TODO: Move to a self-test.
System.out.println("*** System properties: ***");
Properties props = System.getProperties();
//props.list( System.out );
Enumeration en = props.propertyNames();
while( en.hasMoreElements() ){
String name = (String) en.nextElement();
System.out.println( "\t" + name + " = " + System.getProperty(name) );
}
// TODO: Move to a shared testsuite lib.
String asDist = System.getProperty("jboss.dist");
if( asDist == null ) throw new Exception("'jboss.dist' property is not set.");
if( ! new File(asDist).exists() ) throw new Exception("AS dir from 'jboss.dist' doesn't exist: " + asDist + " user.dir: " + System.getProperty("user.dir"));
// TODO: Move to a shared testsuite lib.
String asInst = System.getProperty("jboss.inst");
if( asInst == null ) throw new Exception("'jboss.inst' property is not set. Perhaps this test is in a multi-node tests group but runs outside container?");
if( ! new File(asInst).exists() ) throw new Exception("AS dir from 'jboss.inst' doesn't exist: " + asInst + " user.dir: " + System.getProperty("user.dir"));
String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
appClientCommand = java +
" -Djboss.modules.dir="+ asDist + "/modules" +
" -Djline.WindowsTerminal.directConsole=false" +
TestSuiteEnvironment.getIpv6Args() +
"-Djboss.bind.address=" + TestSuiteEnvironment.getServerAddress() +
" -jar "+ asDist + "/jboss-modules.jar" +
" -mp "+ asDist + "/modules" +
" org.jboss.as.appclient" +
" -Djboss.server.base.dir="+ asInst + "/appclient" +
" -Djboss.home.dir="+ asInst +
" " + this.appClientArgs + " " + archiveArg + " " + args;
return appClientCommand;
}
/**
*
*/
public void run() {
final String threadName = Thread.currentThread().getName();
final BufferedReader reader = threadName.equals(outThreadHame) ? outputReader : errorReader;
try {
String line = reader.readLine();
while (line != null) {
if (threadName.equals(outThreadHame))
outputLineReceived(line);
else
errorLineReceived(line);
line = reader.readLine();
}
} catch (Exception e) {
} finally {
synchronized (this) {
if (threadName.equals(outThreadHame))
outputReader = null;
else
errorReader = null;
}
}
}
private synchronized void outputLineReceived(String line) {
System.out.println("[" + outThreadHame + "] " + line);
outputQueue.add(line);
}
private synchronized void errorLineReceived(String line) {
System.out.println("[" + outThreadHame + "] " + line);
}
}