package net.sf.sahi.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.concurrent.Semaphore;
import net.sf.sahi.util.OSUtils;
import net.sf.sahi.util.Utils;
import org.apache.log4j.Logger;
/**
* Sahi - Web Automation and Test Tool
* <p/>
* Copyright 2006 V Narayan Raman
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.
*/
public class ProcessHelper {
private static final Logger logger = Logger.getLogger(ProcessHelper.class);
private String cmd;
private enum Status {
INITIALIZED, RUNNING, STOPPED
}
private Process process;
private int maxTimeToWaitForPIDs;
private Status status;
private ArrayList<String> pids;
private String imageName;
public ProcessHelper(String cmd, String imageName) {
this.cmd = cmd;
this.imageName = imageName;
}
public ProcessHelper(String cmd, String imageName, int maxTimeToWaitForPIDs) {
this.cmd = cmd;
this.imageName = imageName;
this.maxTimeToWaitForPIDs = maxTimeToWaitForPIDs;
}
static Semaphore lock = new Semaphore(1, true);
static long t;
private static boolean hasProcessStarted;
public void execute() throws Exception {
try {
try {
lock.acquire();
hasProcessStarted = false;
t = System.currentTimeMillis();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
ArrayList<String> allPIDsBefore = getPIDs();
logger.trace("execute: "+ cmd);
String[] tokens = Utils.getCommandTokens(cmd.replaceAll("%20", " "));
process = Utils.executeAndGetProcess(tokens);
new Thread(new PIDGatherer(allPIDsBefore)).start();
} catch (Exception e) {
lock.release();
throw e;
}
}
protected Process getActiveProcess() {
return this.process;
}
class PIDGatherer implements Runnable {
private final ArrayList<String> allPIDsBefore;
PIDGatherer(ArrayList<String> allPIDsBefore) {
this.allPIDsBefore = allPIDsBefore;
}
public void run() {
status = ProcessHelper.Status.INITIALIZED;
int maxTime = maxTimeToWaitForPIDs;
int time = 0;
int interval = 100;
while (!hasProcessStarted && time < maxTime) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
time += interval;
}
try {
ArrayList<String> allPIDsAfter = getPIDs();
pids = getNewlyAdded(allPIDsBefore, allPIDsAfter);
} catch (Exception e) {
}
logger.trace("PIDs: " + pids + "; " + (System.currentTimeMillis() - t) + " ms");
status = ProcessHelper.Status.RUNNING;
lock.release();
}
}
private ArrayList<String> getNewlyAdded(ArrayList<String> oldPIDs, ArrayList<String> newPIDs) {
ArrayList<String> newlyAdded = new ArrayList<String>();
Iterator<String> it1 = newPIDs.iterator();
while (it1.hasNext()) {
String pid = (String) it1.next();
if (!oldPIDs.contains(pid)) {
newlyAdded.add(pid);
}
}
return newlyAdded;
}
ArrayList<String> getPIDs() {
ArrayList<String> ar = new ArrayList<String>();
try {
String listCmd = OSUtils.getPIDListCommand().replaceAll("\\$imageName", imageName);
Process p = Runtime.getRuntime().exec(Utils.getCommandTokens(listCmd));
InputStream in = p.getInputStream();
StringBuffer sb = new StringBuffer();
byte c;
while ((c = (byte) in.read()) != -1) {
sb.append((char) c);
}
String output = sb.toString();
StringTokenizer tokenizer = new StringTokenizer(output, "\r\n");
while (tokenizer.hasMoreTokens()) {
String line = tokenizer.nextToken();
line = line.replaceAll("\\s+", " ").trim();
if (line.equals(""))
break;
StringTokenizer spaceTokenizer = new StringTokenizer(line);
int i = 0;
int colNo = OSUtils.getPIDListColumnNo();
boolean hasCol = false;
String pid = null;
while (spaceTokenizer.hasMoreTokens()) {
i++;
pid = spaceTokenizer.nextToken();
if (i == colNo) {
hasCol = true;
break;
}
}
if (hasCol) {
ar.add(pid);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return ar;
}
public static void main(String[] args) {
}
public void kill() {
logger.trace("Kill: " + pids);
for (int i = 0; i < 4; i++) {
killPIDs();
if (waitTillPIDsGone(pids, 3000)) return;
}
}
private void killPIDs() {
// process.destroy();
Iterator<String> it = pids.iterator();
while (it.hasNext()) {
String pid = (String) it.next();
try {
String killCmd = OSUtils.getPIDKillCommand().replaceAll("\\$pid", pid);
Process killer = Runtime.getRuntime().exec(Utils.getCommandTokens(killCmd));
killer.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean waitTillPIDsGone(ArrayList<String> pids2, int maxTime) {
int time = 0;
int interval = 0;
while (time <= maxTime) {
ArrayList<String> allPIDs = getPIDs();
Iterator<String> it = pids2.iterator();
boolean allDone = true;
while (it.hasNext()) {
String pid = (String) it.next();
if (allPIDs.contains(pid)) {
allDone = false;
}
}
if (allDone) return true;
interval += 100;
time += interval;
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return false;
}
public static void setProcessStarted() {
hasProcessStarted = true;
}
public void waitTillAlive() {
while (true) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!isProcessAlive()) {
break;
}
}
}
public boolean isProcessAlive() {
if (status == ProcessHelper.Status.STOPPED) return false;
if (status == ProcessHelper.Status.INITIALIZED) return true;
ArrayList<String> pidArray = getPIDs();
for (String pid : pids) {
if (pidArray.contains(pid)) {
return true;
}
}
status = ProcessHelper.Status.STOPPED;
return false;
}
}