001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.simulator.distrunner;
005:
006: import com.tcsimulator.ClientSpec;
007: import com.tcsimulator.distrunner.NullServerSpec;
008: import com.tcsimulator.distrunner.ServerSpec;
009:
010: import java.net.URI;
011: import java.net.URISyntaxException;
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.Iterator;
015: import java.util.LinkedList;
016: import java.util.List;
017:
018: public class ArgParser {
019:
020: private final Collection clientSpecs = new LinkedList();
021: private final SpecFactory specFactory;
022: private final Collection testServerSpecs = new LinkedList();
023: private final ServerSpec controlServerSpec;
024: private final String testClassname;
025: private final int intensity;
026: private final int testServerStartMode;
027: private final String javaHome;
028: private static final String CLASS_NAME_ARG = "classname";
029: private static final String INTENSITY_ARG = "intensity";
030: private static final String CLIENT_ARG = "client";
031: private static final String TEST_SERVER_ARG = "server";
032: private static final String CONTROL_SERVER_ARG = "control";
033: private static final String BACKUP_SERVER_ARG = "backup";
034: private static final String VM_COUNT_ARG = "vm.count";
035: private static final String EXECUTION_COUNT_ARG = "execution.count";
036: private static final String JVM_OPTS_ARG = "jvm.args";
037: private static final String CACHE_COUNT_ARG = "config.dso.server.cache";
038: private static final String HTTP_PORT_ARG = "config.dso.http.port";
039: private static final String JMX_PORT_ARG = "config.dso.jmx.port";
040: private static final String DSO_PORT_ARG = "config.dso.dso.port";
041:
042: private static final String DSO_START_ARG = "dsostart";
043: private static final String DSO_START_TRUE_ARG = "true";
044: private static final String JAVA_HOME_ARG = "javahome";
045: private static final String UNDEFINED = "undefined";
046: private static final String UNDEFINED_NUMBER = "-1";
047:
048: public static final int DSO_START = 0;
049: public static final int NON_DSO_START = 1;
050: // default port values of control server... for test server, add 1... for back up, add 2
051: public static final int DEFAULT_HTTP_PORT = 9515;
052: public static final int DEFAULT_JMX_PORT = 9520;
053: public static final int DEFAULT_DSO_PORT = 9510;
054: // default cache count for all servers
055: public static final int DEFAULT_SERVER_CACHE = 200000;
056:
057: public ArgParser(String[] args, SpecFactory specFactory,
058: boolean serverSpecRequired,
059: boolean controlServerSpecRequired) throws ArgException {
060: this .specFactory = specFactory;
061: if (args == null || args.length == 0) {
062: throw new ArgException("No arguments specified");
063: }
064: ServerSpec theControlServerSpec = new NullServerSpec();
065: String theTestClassname = "";
066: int theIntensity = -1;
067: int theTestServerStartMode = -1;
068: String theJavaHome = "";
069: try {
070: for (int i = 0; i < args.length; i++) {
071: if (args[i].startsWith(CLIENT_ARG)) {
072: parseClientSpecs(args[i]);
073: } else if (args[i].startsWith(TEST_SERVER_ARG)
074: || args[i].startsWith(CONTROL_SERVER_ARG)
075: || args[i].startsWith(BACKUP_SERVER_ARG)) {
076: theControlServerSpec = parseServerSpecs(args[i]);
077: } else if (args[i].startsWith(CLASS_NAME_ARG)) {
078: if (!theTestClassname.equals("")) {
079: throw new ArgException(
080: "More than one test classname specified.");
081: }
082: String[] nvPair = args[i].split("=");
083: if (nvPair.length != 2) {
084: throw new ArgException(
085: "Malformed test classname argument.");
086: }
087: theTestClassname = nvPair[1];
088: } else if (args[i].startsWith(INTENSITY_ARG)) {
089: if (theIntensity >= 0) {
090: throw new ArgException(
091: "More than one intensity specified.");
092: }
093: String[] nvPair = args[i].split("=");
094: if (nvPair.length != 2) {
095: throw new ArgException(
096: "Malformed intensity argument.");
097: }
098: if (!nvPair[1].equals(UNDEFINED)) {
099: theIntensity = Integer.parseInt(nvPair[1]);
100: }
101: } else if (args[i].startsWith(DSO_START_ARG)) {
102: String[] nvPair = args[i].split("=");
103: if (nvPair.length != 2) {
104: throw new ArgException(
105: "Malformed dso start argument.");
106: }
107: if (nvPair[1].equalsIgnoreCase(DSO_START_TRUE_ARG)) {
108: theTestServerStartMode = DSO_START;
109: } else {
110: theTestServerStartMode = NON_DSO_START;
111: }
112: } else if (args[i].startsWith(JAVA_HOME_ARG)) {
113: String[] nvPair = args[i].split("=");
114: if (nvPair.length != 2) {
115: throw new ArgException(
116: "Malformed java home argument.");
117: }
118: theJavaHome = nvPair[1];
119: }
120: }
121: } catch (URISyntaxException e) {
122: throw new ArgException(e);
123: }
124: this .testClassname = theTestClassname; // if not specified, then value is "undefined"
125: this .intensity = theIntensity; // if not specified, then value is -1
126: this .testServerStartMode = theTestServerStartMode;
127: if (theControlServerSpec.isNull() && controlServerSpecRequired) {
128: throw new ArgException("No control server spec specified.");
129: }
130: this .controlServerSpec = theControlServerSpec;
131: if (testServerSpecs.isEmpty() && serverSpecRequired) {
132: throw new ArgException("No server spec specified.");
133: }
134: this .javaHome = theJavaHome;
135: }
136:
137: private ServerSpec parseServerSpecs(String arg)
138: throws ArgException, URISyntaxException {
139: ServerSpec theControlServerSpec = new NullServerSpec();
140: String[] specDescriptions = arg.split(";");
141: for (int i = 0; i < specDescriptions.length; i++) {
142: ServerSpec csSpec = parseServerSpec(new URI(
143: specDescriptions[i]));
144: if (!csSpec.isNull() && theControlServerSpec.isNull()) {
145: theControlServerSpec = csSpec;
146: } else if (!csSpec.isNull()) {
147: throw new ArgException(
148: "More than one control server spec specified.");
149: }
150: }
151: return theControlServerSpec;
152: }
153:
154: private ServerSpec parseServerSpec(URI uri) throws ArgException {
155: String hostname = uri.getHost();
156: String testHome = uri.getPath();
157: int cache = 0;
158: int jmxPort = 0;
159: int dsoPort = 0;
160: List parsedJvmOpts = new ArrayList();
161: int undefNumber = ArgParser.getUndefinedNumber();
162: String typeName = uri.getScheme();
163: int type = -1;
164:
165: if (typeName.startsWith(CONTROL_SERVER_ARG)) {
166: type = 0;
167: } else if (typeName.startsWith(TEST_SERVER_ARG)) {
168: type = 1;
169: } else if (typeName.startsWith(BACKUP_SERVER_ARG)) {
170: type = 2;
171: }
172:
173: try {
174: cache = Integer.parseInt(getValueFromQuery(CACHE_COUNT_ARG,
175: UNDEFINED_NUMBER, uri.getQuery()));
176: if (cache == undefNumber) {
177: cache = ArgParser.DEFAULT_SERVER_CACHE;
178: }
179: } catch (NumberFormatException e) {
180: throw new ArgException("Unable to parse " + CACHE_COUNT_ARG
181: + ": " + uri);
182: }
183: try {
184: jmxPort = Integer.parseInt(getValueFromQuery(JMX_PORT_ARG,
185: UNDEFINED_NUMBER, uri.getQuery()));
186: if (jmxPort == undefNumber) {
187: jmxPort = ArgParser.DEFAULT_JMX_PORT + type;
188: }
189: } catch (NumberFormatException e) {
190: throw new ArgException("Unable to parse " + JMX_PORT_ARG
191: + ": " + uri);
192: }
193: try {
194: dsoPort = Integer.parseInt(getValueFromQuery(DSO_PORT_ARG,
195: UNDEFINED_NUMBER, uri.getQuery()));
196: if (dsoPort == undefNumber) {
197: dsoPort = ArgParser.DEFAULT_DSO_PORT + type;
198: }
199: } catch (NumberFormatException e) {
200: throw new ArgException("Unable to parse " + DSO_PORT_ARG
201: + ": " + uri);
202: }
203: String[] jvmOpts = getValueFromQuery(JVM_OPTS_ARG, UNDEFINED,
204: uri.getQuery()).split(",");
205: for (int i = 0; i < jvmOpts.length; i++) {
206: parsedJvmOpts.add(jvmOpts[i]);
207: }
208:
209: switch (type) {
210: case 0:
211: return specFactory.newServerSpec(hostname, testHome, cache,
212: jmxPort, dsoPort, parsedJvmOpts,
213: ServerSpec.CONTROL_SERVER);
214: case 1:
215: testServerSpecs.add(specFactory.newServerSpec(hostname,
216: testHome, cache, jmxPort, dsoPort, parsedJvmOpts,
217: ServerSpec.TEST_SERVER));
218: return new NullServerSpec();
219: case 2:
220: testServerSpecs.add(specFactory.newServerSpec(hostname,
221: testHome, cache, jmxPort, dsoPort, parsedJvmOpts,
222: ServerSpec.BACKUP_SERVER));
223: return new NullServerSpec();
224: default:
225: throw new AssertionError(
226: "Attempting to parse unrecognizable server type!");
227: }
228: }
229:
230: private void parseClientSpecs(String arg)
231: throws URISyntaxException, NumberFormatException,
232: ArgException {
233: String[] specDescriptions = arg.split(";");
234: for (int i = 0; i < specDescriptions.length; i++) {
235: parseClientSpec(new URI(specDescriptions[i]));
236: }
237: }
238:
239: private void parseClientSpec(URI uri) throws ArgException {
240: String hostname = uri.getHost();
241: String testHome = uri.getPath();
242: int vmCount = 0;
243: int executionCount = 0;
244: List parsedJvmOpts = new ArrayList();
245:
246: try {
247: vmCount = Integer.parseInt(getValueFromQuery(VM_COUNT_ARG,
248: "1", uri.getQuery()));
249: } catch (NumberFormatException e) {
250: throw new ArgException("Unable to parse " + VM_COUNT_ARG
251: + ": " + uri);
252: }
253: try {
254: executionCount = Integer.parseInt(getValueFromQuery(
255: EXECUTION_COUNT_ARG, "1", uri.getQuery()));
256: } catch (NumberFormatException e) {
257: throw new ArgException("Unable to parse "
258: + EXECUTION_COUNT_ARG + ": " + uri);
259: }
260: String[] jvmOpts = getValueFromQuery(JVM_OPTS_ARG, UNDEFINED,
261: uri.getQuery()).split(",");
262: for (int i = 0; i < jvmOpts.length; i++) {
263: parsedJvmOpts.add(jvmOpts[i]);
264: }
265: clientSpecs.add(specFactory.newClientSpec(hostname, testHome,
266: vmCount, executionCount, parsedJvmOpts));
267: }
268:
269: public int getIntensity() {
270: return intensity;
271: }
272:
273: public Collection getClientSpecs() {
274: return clientSpecs;
275: }
276:
277: public Collection getServerSpecs() {
278: return this .testServerSpecs;
279: }
280:
281: // TODO: this is temp way to get active test server
282: public ServerSpec getServerSpec() {
283: return (ServerSpec) this .testServerSpecs.iterator().next();
284: }
285:
286: public ServerSpec getControlServerSpec() {
287: return this .controlServerSpec;
288: }
289:
290: public String getTestClassname() {
291: return this .testClassname;
292: }
293:
294: public boolean getTestServerStartMode() {
295: if (this .testServerStartMode == DSO_START) {
296: return true;
297: }
298: return false;
299: }
300:
301: public String getJavaHome() {
302: String fileSeparator = System.getProperty("file.separator");
303:
304: return this .javaHome + fileSeparator + "bin" + fileSeparator
305: + "java";
306: }
307:
308: private static String getValueFromQuery(String name,
309: String defaultValue, String query) throws ArgException {
310: List results = getValuesFromQuery(name, query);
311: if (results.isEmpty()) {
312: return defaultValue;
313: }
314: if (results.size() > 1) {
315: throw new ArgException("More than one value for name ("
316: + name + "): " + query);
317: } else {
318: return (String) results.get(0);
319: }
320: }
321:
322: private static List getValuesFromQuery(String name, String query) {
323: List rv = new LinkedList();
324: if (query != null) {
325: String[] pairs = query.split("&");
326: for (int i = 0; i < pairs.length; i++) {
327: String pair = pairs[i];
328: int split = pair.indexOf("=");
329: String[] nv = new String[] { pair.substring(0, split),
330: pair.substring(split + 1, pair.length()) };
331: if (name.equals(nv[0])) {
332: rv.add(nv[1]);
333: }
334: }
335: }
336: return rv;
337: }
338:
339: public static String getArgumentForTestClassName(
340: String testClassName) {
341: return CLASS_NAME_ARG + "=" + testClassName;
342: }
343:
344: public static String getArgumentForClientSpec(ClientSpec cSpec) {
345: StringBuffer jopts = new StringBuffer();
346: for (Iterator i = cSpec.getJvmOpts().iterator(); i.hasNext();) {
347: jopts.append(i.next());
348: if (i.hasNext()) {
349: jopts.append(",");
350: }
351: }
352: StringBuffer result = new StringBuffer();
353: result.append(CLIENT_ARG + "://" + cSpec.getHostName()
354: + cSpec.getTestHome() + "?" + VM_COUNT_ARG + "="
355: + cSpec.getVMCount() + "&" + EXECUTION_COUNT_ARG + "="
356: + cSpec.getExecutionCount());
357: if (!jopts.toString().equals(UNDEFINED)) {
358: result.append("&" + JVM_OPTS_ARG + "=" + jopts.toString());
359: }
360: return result.toString();
361: }
362:
363: public static Collection getArgumentsForClientSpecs(
364: Collection clientSpecs) {
365: List result = new ArrayList();
366: for (Iterator i = clientSpecs.iterator(); i.hasNext();) {
367: result.add(ArgParser
368: .getArgumentForClientSpec((ClientSpec) i.next()));
369: }
370: return result;
371: }
372:
373: public static String getArgumentForIntensity(int intensity) {
374: return INTENSITY_ARG + "=" + intensity;
375: }
376:
377: public static String getArgumentForServerSpec(ServerSpec sSpec) {
378: int type = sSpec.getType();
379: String token = null;
380: switch (type) {
381: case ServerSpec.CONTROL_SERVER:
382: token = CONTROL_SERVER_ARG;
383: break;
384: case ServerSpec.TEST_SERVER:
385: token = TEST_SERVER_ARG;
386: break;
387: case ServerSpec.BACKUP_SERVER:
388: token = BACKUP_SERVER_ARG;
389: }
390:
391: StringBuffer jopts = new StringBuffer();
392: for (Iterator i = sSpec.getJvmOpts().iterator(); i.hasNext();) {
393: jopts.append(i.next());
394: if (i.hasNext()) {
395: jopts.append(",");
396: }
397: }
398: StringBuffer result = new StringBuffer();
399: result.append(token + "://" + sSpec.getHostName()
400: + sSpec.getTestHome() + "?config.dso.server.cache="
401: + sSpec.getCache() + "&config.dso.jmx.port="
402: + sSpec.getJmxPort() + "&config.dso.dso.port="
403: + sSpec.getDsoPort());
404: if (!jopts.toString().equals(UNDEFINED)) {
405: result.append("&" + JVM_OPTS_ARG + "=" + jopts.toString());
406: }
407: return result.toString();
408: }
409:
410: public static Collection getArgumentsForServerSpecs(
411: Collection serverSpecs) {
412: List result = new ArrayList();
413: for (Iterator i = serverSpecs.iterator(); i.hasNext();) {
414: result.add(ArgParser
415: .getArgumentForServerSpec((ServerSpec) i.next()));
416: }
417: return result;
418: }
419:
420: public static String getUndefinedString() {
421: return UNDEFINED;
422: }
423:
424: public static int getUndefinedNumber() {
425: return Integer.parseInt(UNDEFINED_NUMBER);
426: }
427:
428: public static final String usage() {
429: StringBuffer buf = new StringBuffer(
430: "Setup for distributed test runner.\nUsage:");
431:
432: buf.append("\n\njava ");
433: buf.append("<client spec>[;<client spec>;<client spec>...]");
434: buf.append(" <server spec>[;<server spec>...]");
435: buf.append(" " + CLASS_NAME_ARG
436: + "=<test application classname>");
437: buf.append(" " + INTENSITY_ARG
438: + "=<integer describing intensity>");
439: buf.append("\n\nclient spec: " + CLIENT_ARG
440: + "://<hostname>/path/to/test/home[?[" + VM_COUNT_ARG
441: + "=<vm count>]");
442: buf.append("[&" + EXECUTION_COUNT_ARG + "=<execution count>][&"
443: + JVM_OPTS_ARG + "=<jvm args>]]\n");
444: buf.append("server spec: {" + TEST_SERVER_ARG + " "
445: + CONTROL_SERVER_ARG
446: + "}://<hostname>/path/to/test/home");
447: buf.append("[?[" + JVM_OPTS_ARG + "=<jvm args>][&"
448: + CACHE_COUNT_ARG + "=<cache count>]");
449: buf.append("[&" + HTTP_PORT_ARG + "=<http port>][&"
450: + JMX_PORT_ARG + "=<jmx port>]");
451: buf.append("[&" + DSO_PORT_ARG + "=<dso port>]]\n");
452: buf.append("\t" + VM_COUNT_ARG
453: + ": how many JVMs to start on this client\n");
454: buf
455: .append("\t"
456: + EXECUTION_COUNT_ARG
457: + ": the number of application instances to start per vm\n");
458: buf
459: .append("\t"
460: + JVM_OPTS_ARG
461: + ": jvm options to be used when running this process\n");
462: buf.append("\t" + TEST_SERVER_ARG
463: + ": DSO server used to run the test apps\n");
464: buf
465: .append("\t"
466: + CONTROL_SERVER_ARG
467: + ": DSO server used to manage the distribute test framework\n");
468: return buf.toString();
469: }
470: }
|