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: */
018:
019: package org.apache.jmeter.threads;
020:
021: import java.io.Serializable;
022: import java.util.Collections;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025: import java.util.List;
026:
027: import org.apache.jmeter.control.Controller;
028: import org.apache.jmeter.control.LoopController;
029: import org.apache.jmeter.engine.event.LoopIterationListener;
030: import org.apache.jmeter.samplers.RemoteSampleListener;
031: import org.apache.jmeter.samplers.SampleEvent;
032: import org.apache.jmeter.samplers.SampleListener;
033: import org.apache.jmeter.samplers.Sampler;
034: import org.apache.jmeter.testelement.AbstractTestElement;
035: import org.apache.jmeter.testelement.TestElement;
036: import org.apache.jmeter.testelement.property.IntegerProperty;
037: import org.apache.jmeter.testelement.property.LongProperty;
038: import org.apache.jmeter.testelement.property.BooleanProperty;
039: import org.apache.jmeter.testelement.property.TestElementProperty;
040: import org.apache.jorphan.logging.LoggingManager;
041: import org.apache.log.Logger;
042:
043: /**
044: * ThreadGroup
045: *
046: * @author Michael Stover
047: * @version $Id: ThreadGroup.java 493779 2007-01-07 17:46:38Z sebb $
048: */
049: public class ThreadGroup extends AbstractTestElement implements
050: SampleListener, Serializable, Controller {
051: private final static Logger log = LoggingManager
052: .getLoggerForClass();
053:
054: public final static String NUM_THREADS = "ThreadGroup.num_threads";
055:
056: public final static String RAMP_TIME = "ThreadGroup.ramp_time";
057:
058: public final static String MAIN_CONTROLLER = "ThreadGroup.main_controller";
059:
060: public final static String SCHEDULER = "ThreadGroup.scheduler";
061:
062: public final static String START_TIME = "ThreadGroup.start_time";
063:
064: public final static String END_TIME = "ThreadGroup.end_time";
065:
066: public final static String DURATION = "ThreadGroup.duration";
067:
068: public final static String DELAY = "ThreadGroup.delay";
069:
070: /* Action to be taken when a Sampler error occurs */
071: public final static String ON_SAMPLE_ERROR = "ThreadGroup.on_sample_error"; // int
072:
073: public final static String ON_SAMPLE_ERROR_CONTINUE = "continue";
074:
075: public final static String ON_SAMPLE_ERROR_STOPTHREAD = "stopthread";
076:
077: public final static String ON_SAMPLE_ERROR_STOPTEST = "stoptest";
078:
079: private final static int DEFAULT_NUM_THREADS = 1;
080:
081: private final static int DEFAULT_RAMP_UP = 0;
082:
083: private SampleQueue queue = null;
084:
085: private LinkedList listeners = new LinkedList();
086:
087: private LinkedList remoteListeners = new LinkedList();
088:
089: private int numberOfThreads = 0; // Number of threads currently running
090:
091: // in this group
092:
093: /**
094: * No-arg constructor.
095: */
096: public ThreadGroup() {
097: }
098:
099: /**
100: * Set the number of threads to start
101: *
102: * @param numThreads
103: * the number of threads.
104: */
105: public void setNumThreads(int numThreads) {
106: setProperty(new IntegerProperty(NUM_THREADS, numThreads));
107: }
108:
109: synchronized void incrNumberOfThreads() {
110: numberOfThreads++;
111: }
112:
113: synchronized void decrNumberOfThreads() {
114: numberOfThreads--;
115: }
116:
117: public synchronized int getNumberOfThreads() {
118: return numberOfThreads;
119: }
120:
121: public boolean isDone() {
122: return getSamplerController().isDone();
123: }
124:
125: public Sampler next() {
126: return getSamplerController().next();
127: }
128:
129: /**
130: * Set the Scheduler value.
131: *
132: * @param Scheduler
133: * the Scheduler value.
134: */
135: public void setScheduler(boolean Scheduler) {
136: setProperty(new BooleanProperty(SCHEDULER, Scheduler));
137: }
138:
139: /**
140: * Get the Scheduler value.
141: *
142: * @return the Scheduler value.
143: */
144: public boolean getScheduler() {
145: return getPropertyAsBoolean(SCHEDULER);
146: }
147:
148: /**
149: * Set the StartTime value.
150: *
151: * @param stime -
152: * the StartTime value.
153: */
154: public void setStartTime(long stime) {
155: setProperty(new LongProperty(START_TIME, stime));
156: }
157:
158: /**
159: * Get the start time value.
160: *
161: * @return the start time value.
162: */
163: public long getStartTime() {
164: return getPropertyAsLong(START_TIME);
165: }
166:
167: /**
168: * Get the duration
169: *
170: * @return the duration (in secs)
171: */
172: public long getDuration() {
173: return getPropertyAsLong(DURATION);
174: }
175:
176: /**
177: * Set the duration
178: *
179: * @param duration
180: * in seconds
181: */
182: public void setDuration(long duration) {
183: setProperty(new LongProperty(DURATION, duration));
184: }
185:
186: /**
187: * Get the delay
188: *
189: * @return the delay (in secs)
190: */
191: public long getDelay() {
192: return getPropertyAsLong(DELAY);
193: }
194:
195: /**
196: * Set the delay
197: *
198: * @param delay
199: * in seconds
200: */
201: public void setDelay(long delay) {
202: setProperty(new LongProperty(DELAY, delay));
203: }
204:
205: /**
206: * Set the EndTime value.
207: *
208: * @param etime -
209: * the EndTime value.
210: */
211: public void setEndTime(long etime) {
212: setProperty(new LongProperty(END_TIME, etime));
213: }
214:
215: /**
216: * Get the end time value.
217: *
218: * @return the end time value.
219: */
220: public long getEndTime() {
221: return getPropertyAsLong(END_TIME);
222: }
223:
224: /**
225: * Set the ramp-up value.
226: *
227: * @param rampUp
228: * the ramp-up value.
229: */
230: public void setRampUp(int rampUp) {
231: setProperty(new IntegerProperty(RAMP_TIME, rampUp));
232: }
233:
234: /**
235: * Get the ramp-up value.
236: *
237: * @return the ramp-up value.
238: */
239: public int getRampUp() {
240: return getPropertyAsInt(ThreadGroup.RAMP_TIME);
241: }
242:
243: /**
244: * Get the sampler controller.
245: *
246: * @return the sampler controller.
247: */
248: public Controller getSamplerController() {
249: return (Controller) getProperty(MAIN_CONTROLLER)
250: .getObjectValue();
251: }
252:
253: /**
254: * Set the sampler controller.
255: *
256: * @param c
257: * the sampler controller.
258: */
259: public void setSamplerController(LoopController c) {
260: c.setContinueForever(false);
261: setProperty(new TestElementProperty(MAIN_CONTROLLER, c));
262: }
263:
264: /**
265: * Get the number of threads.
266: *
267: * @return the number of threads.
268: */
269: public int getNumThreads() {
270: return this .getPropertyAsInt(ThreadGroup.NUM_THREADS);
271: }
272:
273: /**
274: * Get the default number of threads.
275: *
276: * @return the default number of threads.
277: */
278: public int getDefaultNumThreads() {
279: return DEFAULT_NUM_THREADS;
280: }
281:
282: /**
283: * Get the default ramp-up value.
284: *
285: * @return the default ramp-up value (in seconds).
286: */
287: public int getDefaultRampUp() {
288: return DEFAULT_RAMP_UP;
289: }
290:
291: /**
292: * Add a test element.
293: *
294: * @param child
295: * the test element to add.
296: */
297: public void addTestElement(TestElement child) {
298: getSamplerController().addTestElement(child);
299: }
300:
301: /**
302: * A sample has occurred.
303: *
304: * @param e
305: * the sample event.
306: */
307: public void sampleOccurred(SampleEvent e) {
308: if (queue == null) {
309: queue = new SampleQueue();
310: Thread thread = new Thread(queue);
311: // thread.setPriority(Thread.MAX_PRIORITY);
312: thread.start();
313: }
314: queue.sampleOccurred(e);
315: }
316:
317: /**
318: * A sample has started.
319: *
320: * @param e
321: * the sample event.
322: */
323: public void sampleStarted(SampleEvent e) {
324: }
325:
326: /**
327: * A sample has stopped.
328: *
329: * @param e
330: * the sample event
331: */
332: public void sampleStopped(SampleEvent e) {
333: }
334:
335: /**
336: * Separate thread to deliver all SampleEvents. This ensures that sample
337: * listeners will get sample events one at a time and can thus ignore thread
338: * issues.
339: *
340: * @author Mike Stover
341: * @version $Id: ThreadGroup.java 493779 2007-01-07 17:46:38Z sebb $
342: */
343: private class SampleQueue implements Runnable, Serializable {
344: List occurredQ = Collections.synchronizedList(new LinkedList());
345:
346: /**
347: * No-arg constructor.
348: */
349: public SampleQueue() {
350: }
351:
352: /**
353: * A sample occurred.
354: *
355: * @param e
356: * the sample event.
357: */
358: public synchronized void sampleOccurred(SampleEvent e) {
359: occurredQ.add(e);
360: this .notifyAll();
361: }
362:
363: /**
364: * Run the thread.
365: *
366: * @see java.lang.Runnable#run()
367: */
368: public void run() {
369: SampleEvent event = null;
370: while (true) {
371: try {
372: event = (SampleEvent) occurredQ.remove(0);
373: } catch (Exception ex) {
374: waitForSamples();
375: continue;
376: }
377: try {
378: if (event != null) {
379: Iterator iter = listeners.iterator();
380: while (iter.hasNext()) {
381: ((SampleListener) iter.next())
382: .sampleOccurred(event);
383: }
384: iter = remoteListeners.iterator();
385: while (iter.hasNext()) {
386: try {
387: ((RemoteSampleListener) iter.next())
388: .sampleOccurred(event);
389: } catch (Exception ex) {
390: log.error("", ex);
391: }
392: }
393: } else {
394: waitForSamples();
395: }
396: } catch (Throwable ex) {
397: log.error("", ex);
398: }
399:
400: }
401: }
402:
403: private synchronized void waitForSamples() {
404: try {
405: this .wait();
406: } catch (Exception ex) {
407: log.error("", ex);
408: }
409: }
410: }
411:
412: /*
413: * (non-Javadoc)
414: *
415: * @see Controller#addIterationListener(LoopIterationListener)
416: */
417: public void addIterationListener(LoopIterationListener lis) {
418: getSamplerController().addIterationListener(lis);
419: }
420:
421: /*
422: * (non-Javadoc)
423: *
424: * @see Controller#initialize()
425: */
426: public void initialize() {
427: getSamplerController().initialize();
428: }
429:
430: /**
431: * Check if a sampler error should cause thread to stop.
432: *
433: * @return true if should stop
434: */
435: public boolean getOnErrorStopThread() {
436: return getPropertyAsString(ThreadGroup.ON_SAMPLE_ERROR)
437: .equalsIgnoreCase(ON_SAMPLE_ERROR_STOPTHREAD);
438: }
439:
440: /**
441: * Check if a sampler error should cause test to stop.
442: *
443: * @return true if should stop
444: */
445: public boolean getOnErrorStopTest() {
446: return getPropertyAsString(ThreadGroup.ON_SAMPLE_ERROR)
447: .equalsIgnoreCase(ON_SAMPLE_ERROR_STOPTEST);
448: }
449:
450: }
|