001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.threadtest.tester;
018:
019: import java.util.Arrays;
020: import java.util.List;
021:
022: import org.apache.commons.httpclient.HttpClient;
023: import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
024: import org.apache.commons.httpclient.methods.GetMethod;
025: import org.apache.commons.httpclient.params.HttpClientParams;
026: import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.wicket.threadtest.tester.CommandRunner.CommandRunnerObserver;
030: import org.apache.wicket.util.time.Duration;
031: import org.mortbay.jetty.Server;
032: import org.mortbay.jetty.webapp.WebAppContext;
033:
034: /**
035: * @author eelcohillenius
036: */
037: public final class Tester implements CommandRunnerObserver {
038:
039: private static final Log log = LogFactory.getLog(Tester.class);
040:
041: private static HttpClientParams params;
042:
043: static {
044: params = new HttpClientParams();
045: params.setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS,
046: true);
047: }
048:
049: /**
050: * Main method for just starting the server
051: *
052: * @param args
053: */
054: public static void main(String[] args) {
055: // start server on its own
056: int port = 8090;
057: if (args.length > 0) {
058: port = Integer.valueOf(args[0]);
059: }
060: Server server = startServer(port);
061: try {
062: server.start();
063: } catch (Exception e) {
064: e.printStackTrace();
065: try {
066: server.stop();
067: } catch (Exception e1) {
068: e1.printStackTrace();
069: }
070: System.exit(1);
071: }
072: }
073:
074: /**
075: * Start Jetty server instance and return the handle.
076: *
077: * @param port
078: * @return server handle
079: */
080: private static Server startServer(int port) {
081: Server server;
082: // start up server
083: server = new Server(port);
084: WebAppContext ctx = new WebAppContext("./src/main/webapp", "/");
085: server.addHandler(ctx);
086: try {
087: server.start();
088: } catch (Exception e) {
089: throw new RuntimeException(e);
090: }
091: return server;
092: }
093:
094: private int activeThreads = 0;
095:
096: private final List<Command> commands;
097:
098: private String host = "localhost";
099:
100: /**
101: * if true, each thread will represent a seperate session. If false, the
102: * test behaves like one client issuing multiple concurrent requests.
103: */
104: private final boolean multipleSessions;
105:
106: private final int numberOfThreads;
107:
108: private int port = 8090;
109:
110: /**
111: * Construct.
112: *
113: * @param command
114: * Command to execute
115: * @param numberOfThreads
116: * Number of threads to run the commands. Each thread runs all
117: * commands
118: * @param multipleSessions
119: * if true, each thread will represent a seperate session. If
120: * false, the test behaves like one client issuing multiple
121: * concurrent requests
122: */
123: public Tester(Command command, int numberOfThreads,
124: boolean multipleSessions) {
125: this (Arrays.asList(new Command[] { command }), numberOfThreads,
126: multipleSessions);
127: }
128:
129: /**
130: * Construct.
131: *
132: * @param commands
133: * Commands to execute
134: * @param numberOfThreads
135: * Number of threads to run the commands. Each thread runs all
136: * commands
137: * @param multipleSessions
138: * if true, each thread will represent a seperate session. If
139: * false, the test behaves like one client issuing multiple
140: * concurrent requests
141: */
142: public Tester(List<Command> commands, int numberOfThreads,
143: boolean multipleSessions) {
144: this .commands = commands;
145: this .numberOfThreads = numberOfThreads;
146: this .multipleSessions = multipleSessions;
147: }
148:
149: /**
150: * Gets host.
151: *
152: * @return host
153: */
154: public String getHost() {
155: return host;
156: }
157:
158: /**
159: * Gets port.
160: *
161: * @return port
162: */
163: public int getPort() {
164: return port;
165: }
166:
167: public synchronized void onDone(CommandRunner runner) {
168: activeThreads--;
169: notifyAll();
170: }
171:
172: public synchronized void onError(CommandRunner runner, Exception e) {
173: activeThreads--;
174: notifyAll();
175: }
176:
177: /**
178: * Runs the test.
179: *
180: * @throws Exception
181: */
182: public void run() throws Exception {
183:
184: activeThreads = 0;
185:
186: HttpConnectionManagerParams connManagerParams = new HttpConnectionManagerParams();
187: connManagerParams
188: .setDefaultMaxConnectionsPerHost(numberOfThreads * 2);
189: MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
190: manager.setParams(connManagerParams);
191:
192: Server server = null;
193: GetMethod getMethod = new GetMethod("http://localhost:" + port
194: + "/");
195: try {
196: getMethod.setFollowRedirects(true);
197: HttpClient httpClient = new HttpClient(params, manager);
198: int code = httpClient.executeMethod(getMethod);
199: if (code != 200) {
200: server = startServer(port);
201: }
202: } catch (Exception e) {
203: server = startServer(port);
204: } finally {
205: getMethod.releaseConnection();
206: }
207:
208: try {
209:
210: ThreadGroup g = new ThreadGroup("runners");
211: Thread[] threads = new Thread[numberOfThreads];
212: HttpClient client = null;
213: for (int i = 0; i < numberOfThreads; i++) {
214:
215: if (multipleSessions) {
216: client = new HttpClient(params, manager);
217: client.getHostConfiguration().setHost(host, port);
218: } else {
219: if (client == null) {
220: client = new HttpClient(params, manager);
221: client.getHostConfiguration().setHost(host,
222: port);
223: }
224: }
225: threads[i] = new Thread(g, new CommandRunner(commands,
226: client, this ));
227: }
228:
229: long start = System.currentTimeMillis();
230:
231: for (int i = 0; i < numberOfThreads; i++) {
232: activeThreads++;
233: threads[i].start();
234: }
235:
236: while (activeThreads > 0) {
237: synchronized (this ) {
238: wait();
239: }
240: }
241:
242: long end = System.currentTimeMillis();
243: long time = end - start;
244: log.info("\n******** finished in "
245: + Duration.milliseconds(time) + " (" + time
246: + " milis)");
247:
248: } finally {
249: MultiThreadedHttpConnectionManager.shutdownAll();
250: if (server != null) {
251: server.stop();
252: }
253: }
254: }
255:
256: /**
257: * Sets host.
258: *
259: * @param host
260: * host
261: */
262: public void setHost(String host) {
263: this .host = host;
264: }
265:
266: /**
267: * Sets port.
268: *
269: * @param port
270: * port
271: */
272: public void setPort(int port) {
273: this.port = port;
274: }
275: }
|