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 + -
显示快捷键?