remotemanager.java.svn-base

来自「cqME :java framework for TCK test.」· SVN-BASE 代码 · 共 408 行

SVN-BASE
408
字号
/* * $Id$ * * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program 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 * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */package com.sun.tck.j2me.javatest;import java.io.IOException;import java.io.PrintWriter;import java.util.Vector;import com.sun.javatest.Status;import com.sun.javatest.TestEnvironment;import com.sun.javatest.TestResult;import com.sun.javatest.agent.AgentManager;/** * Manage the remote components of a distributed test. * The components are created from string based descriptions. * The parameters for each component are: *    	-host XXX	Execute on the machine named XXX. *			This parameter is required. *     	-port XXX	Contact the JavaTest Agent on port XXX. *			This parameter is optional; if omitted, *			the default port for an agent running in *			passive mode will be used. *	-classpath PPP	Load the classes to be executed from PPP. *			If omitted, the classes will be loaded *			from the agent's system class path. * After these parameters should be given the name of a class * to execute and any parameters it may require. * * The class is intended to support the "remote" field of a * JCK test description, using the following paradigm: * * <table border=1> * <tr><td>remote   	<td>${remote.host1}  class1 arg11 arg12 arg13 ... * <tr><td>remote	<td>${remote.host2}  class2 arg21 arg22 arg23 ... * <tr><td><em>etc.</em> * </table> * * The values for ${remote.host1}, $remote.host2} etc are deferred, * and filled in automatically from the environment being used to * run the tests. This avoids having to hard code actual class names * into the test descriptions.  These values would be provided by * entries such as these, within the .jte file: * <table> * <tr><td> env.ENVNAME.remote.host1 = -host gzilla * <tr><td> env.ENVNAME.remote.host2 = -host calloway * </table> */public class RemoteManager {    /**     * Used to indicate errors that occur during initialization.     * These errors will typically be configurations errors of some     * sort or another; if one occurs, the test should be aborted.     */    public static class Fault extends Exception {	/**	 * Create one.	 * @param msg  A detail message.	 */	public Fault(String msg) {	    super(msg);	    msgs = new String[1];	    msgs[0] = msg;	}	/**	 * Create one.	 * @param msgs  Detail messages.	 */	public Fault(String[] msgs) {	    super(msgs[0]);	    this.msgs = msgs;	}	public String[] getMessages() {	    return msgs;	}	private String[] msgs;    }    /**     * Create and initialize a distributed test. If successful, classes     * will be launched on the various remote systems, each reporting back     * into its own section in the test result object.     * If any errors occur, no threads will be launched on the remote systems.     * @param args A string containing the info required to start the     * 		remote classes. The string is broken into lines:     *		each line defines the info and options to start a remote     *		class.     * @param tr The test result in which to store any data written by the     *		remote classes, and the status returned from each class.     * @throws Fault if any problems occur during initialization that     * 		effectively prevent the test from executing successfully.     */    public RemoteManager(String args, TestEnvironment env, TestResult tr) throws Fault {	String[] remoteEntries = splitIntoLines(args);	tasks = new Task[remoteEntries.length];	try {	    // for each remote entry, create a task to do the corresponding work	    for (int i = 0; i < remoteEntries.length; i++) {		String remoteEntry = remoteEntries[i];		String hostInfo = null;		String remoteClassName = null;		String[] remoteArgs = null;		// parse each task's args into hostInfo : remoteClassName remoteArgs		int tokenNo = 0;		for (int remoteIndex = 0; remoteIndex < remoteEntry.length(); ) {		    char ch = remoteEntry.charAt(remoteIndex);		    if (ch == ' ') {			remoteIndex++;		    }		    else if ((tokenNo == 0 || tokenNo == 2) && Character.isJavaIdentifierStart(ch)) {			int start = remoteIndex++;			while (remoteIndex < remoteEntry.length()) {			    ch = remoteEntry.charAt(remoteIndex);			    if (Character.isJavaIdentifierPart(ch) || ch == '.')				remoteIndex++;			    else				break;			}			String word = remoteEntry.substring(start, remoteIndex);			if (tokenNo == 0)			    hostInfo = word;			else			    remoteClassName = word;			tokenNo++;		    }		    else if (tokenNo == 1 && ch == ':') {			tokenNo++;			remoteIndex++;		    }		    else if (tokenNo == 3) {			try {			    remoteArgs = env.resolve(remoteEntry.substring(remoteIndex));			    break;			}			catch (TestEnvironment.Fault e) {			    throw new Fault("error evaluating args for remote entry " + hostInfo);			}		    }		    else			throw new Fault("syntax error in remote entry");		}		if (hostInfo == null || remoteClassName == null)		    throw new Fault("format error in remote entry");		TestResult.Section trs = tr.createSection("remote." + hostInfo);		try {		    String[] hostArgs = env.lookup("remote." + hostInfo);		    if (hostArgs == null || hostArgs.length == 0)			throw new Fault("no value found for remote." + hostInfo + " in environment");		    tasks[i] = new Task(hostArgs, remoteClassName, remoteArgs, trs);		}		catch (TestEnvironment.Fault e) {		    throw new Fault("error evaluating host info for remote entry " + hostInfo);		}	    }	    // now that we have successfully created all the tasks, create threads for them	    for (int i = 0; i < tasks.length; i++) {		Thread thrd = new Thread(tasks[i]);		thrd.start();	    }	}	catch (Fault f) {	    // if any exceptions occur, clean up any tasks that have been created	    dispose();	    throw f;	}	catch (RuntimeException any) {	    // if any exceptions occur, clean up any tasks that have been created	    dispose();	    throw any;	}    }    /**     * Wait until all the tasks that were started have completed.     */    synchronized public boolean waitUntilDone(int timeout) throws InterruptedException {	long now = System.currentTimeMillis();	long end = now + timeout*1000;	boolean allDone = isAllTasksDone();	while (now < end && !allDone) {	    wait(end - now);	    now = System.currentTimeMillis();	    allDone = isAllTasksDone();	}	return allDone;    }    /**     * Check if all the tasks that were started have completed.     */    private boolean isAllTasksDone() {	for (int i = 0; i < tasks.length; i++) {	    if (tasks[i] != null && !tasks[i].isDone())		return false;	}	return true;    }    /**     * Clean up after the main class has been executed.     */    synchronized public void dispose() {	if (tasks == null)	    return;	for (int i = 0; i < tasks.length; i++) {	    Task t = tasks[i];	    if (t != null) {		t.dispose();		tasks[i] = null;	    }	}	tasks = null;    }    /**     * @return a status which is the "worst" status returned from     * 		any of the remote classes. If all the remote classes     *		returned "passed", this will also be "passed".     */    synchronized public Status getStatus() {	if (tasks == null)	    return Status.error("Initialization error");	Status s = OK;	for (int i = 0; i < tasks.length; i++) {	    Task t = tasks[i];	    if (t != null) {                Status status = t.getStatus();                if (status == null) { 		    status = Status.error("No real status available");                }		s = mergeStatus(s, status);            }	}	return s;    }    /**     * Return the worst of two status objects.     */    public static Status mergeStatus(Status s1, Status s2) {	return (s1 == null ? s2 :		s2 == null ? s1 :		s1.getType() >= s2.getType() ? s1 : s2);    }    private Task[] tasks;    /**     * Break a string into lines     */    private static String[] splitIntoLines(String s) throws Fault {	Vector v = new Vector();	int start = 0;	int end   = 0;	while ((end = s.indexOf("\n", start)) != -1) {	    v.addElement(s.substring(start, end));	    start = end+1;	}	v.addElement(s.substring(start));	String[] result = new String[v.size()];	v.copyInto(result);	return result;    }    /**     * A class to cause the remote execution of a class via a JavaTest Agent.     */    private class Task implements Runnable {	Task(String[] hostArgs, String className, String[] args, TestResult.Section trs) throws Fault {	    this.className = className;	    this.args = args;	    this.trs = trs;	    // decode hostArgs into component entries	    String host = null;	    int port = -1;	    String classPath = null;	    for (int i = 0; i < hostArgs.length && hostArgs[i].startsWith("-"); i++) {		if (hostArgs[i].equals("-classpath") && i+1 < hostArgs.length) {		    classPath = hostArgs[++i];		}		else if (hostArgs[i].equals("-host") && i+1 < hostArgs.length) {		    host = hostArgs[++i];		}		else if (hostArgs[i].equals("-port") && i+1 < hostArgs.length) {		    try {			port = Integer.parseInt(hostArgs[++i]);		    }		    catch (NumberFormatException e) {			throw new Fault("bad port number: " + hostArgs[i]);		    }		}		else		    throw new Fault("Unrecognized option: " + hostArgs[i]);	    }	    if (host == null)		throw new Fault("No host specified");	    try {		AgentManager mgr = AgentManager.access();		if (port == -1) {		    amTask = mgr.connectToPassiveAgent(host);		} else {		    amTask = mgr.connectToPassiveAgent(host, port);                }		if (classPath != null)		    amTask.setClassPath(classPath);	    }	    catch (IOException e) {		throw new Fault("Error accessing agent: " + e);	    }	}	/**	 * Initiate the remote task. Any data that the task writes to its two	 * standard PrintWriters are copied into the TestResult section for	 * this task.	 */	public void run() {	    PrintWriter mw = trs.getMessageWriter();	    PrintWriter log = trs.createOutput("log");	    PrintWriter ref = trs.createOutput("ref");	    try {		mw.println("Executing remote component via " + amTask.getConnection().getName());		status = amTask.executeTest(trs.getTitle(), className, args, true, log, ref);                if (trs.isMutable()) {                    trs.setStatus(status);                }		synchronized (RemoteManager.this) {		    RemoteManager.this.notifyAll();		}	    }	    finally {		mw.close();		log.close();		ref.close();	    }	}	Status getStatus() {	    return status;	}	boolean isDone() {	    return (status != null);	}	/**	 * Clean up the task when it is no longer required	 */	void dispose() {	    // amTask.dispose(); // XXX: not currently implemented	    if (status == null) {		status = Status.error("incomplete");		trs.setStatus(status);	    }	}	private final AgentManager.Task amTask;	private final TestResult.Section trs;	private final String className;	private final String[] args;	private Status status;    }    private static Status OK = Status.passed("OK");}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?