| /* |
| * Copyright 2008 Google Inc. |
| * |
| * 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 com.google.gwt.junit; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.UnableToCompleteException; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Runs in Production Mode via browsers managed as an external process. This |
| * feature is experimental and is not officially supported. |
| */ |
| class RunStyleExternalBrowser extends RunStyle { |
| |
| private static class ExternalBrowser { |
| String browserPath; |
| Process process; |
| |
| public ExternalBrowser(String browserPath) { |
| this.browserPath = browserPath; |
| } |
| |
| public String getPath() { |
| return browserPath; |
| } |
| |
| public Process getProcess() { |
| return process; |
| } |
| |
| public void setProcess(Process process) { |
| this.process = process; |
| } |
| } |
| |
| /** |
| * Registered as a shutdown hook to make sure that any browsers that were not |
| * finished are killed. |
| */ |
| private class ShutdownCb extends Thread { |
| |
| @Override |
| public void run() { |
| for (ExternalBrowser browser : externalBrowsers) { |
| if (browser.getProcess() != null) { |
| try { |
| browser.getProcess().exitValue(); |
| } catch (IllegalThreadStateException e) { |
| // The process is still active. Kill it. |
| browser.getProcess().destroy(); |
| } |
| } |
| } |
| } |
| } |
| |
| private ExternalBrowser[] externalBrowsers; |
| |
| /** |
| * @param shell the containing shell |
| */ |
| public RunStyleExternalBrowser(JUnitShell shell) { |
| super(shell); |
| } |
| |
| @Override |
| public String[] getInterruptedHosts() { |
| // Make sure all browsers are still running |
| Set<String> toRet = null; |
| for (ExternalBrowser browser : externalBrowsers) { |
| try { |
| browser.getProcess().exitValue(); |
| |
| // The host exited, so return its path. |
| if (toRet == null) { |
| toRet = new HashSet<String>(); |
| } |
| toRet.add(browser.getPath()); |
| } catch (IllegalThreadStateException e) { |
| // The process is still active, keep looking. |
| } |
| } |
| return toRet == null ? null : toRet.toArray(new String[toRet.size()]); |
| } |
| |
| @Override |
| public int initialize(String args) { |
| if (args == null || args.length() == 0) { |
| getLogger().log( |
| TreeLogger.ERROR, |
| "ExternalBrowser runstyle requires an " |
| + "argument listing one or more executables of external browsers to " |
| + "launch"); |
| return -1; |
| } |
| String browsers[] = args.split(","); |
| synchronized (this) { |
| this.externalBrowsers = new ExternalBrowser[browsers.length]; |
| for (int i = 0; i < browsers.length; ++i) { |
| externalBrowsers[i] = new ExternalBrowser(browsers[i]); |
| } |
| } |
| Runtime.getRuntime().addShutdownHook(new ShutdownCb()); |
| return browsers.length; |
| } |
| |
| @Override |
| public synchronized void launchModule(String moduleName) |
| throws UnableToCompleteException { |
| String commandArray[] = new String[2]; |
| // construct the URL for the browser to hit |
| commandArray[1] = shell.getModuleUrl(moduleName); |
| |
| Process child = null; |
| for (ExternalBrowser browser : externalBrowsers) { |
| try { |
| commandArray[0] = browser.getPath(); |
| |
| child = Runtime.getRuntime().exec(commandArray); |
| if (child == null) { |
| getLogger().log(TreeLogger.ERROR, |
| "Problem exec()'ing " + commandArray[0]); |
| throw new UnableToCompleteException(); |
| } |
| } catch (Exception e) { |
| getLogger().log(TreeLogger.ERROR, |
| "Error launching external browser at " + browser.getPath(), e); |
| throw new UnableToCompleteException(); |
| } |
| browser.setProcess(child); |
| } |
| } |
| } |