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.control;
020:
021: import java.io.Serializable;
022:
023: import org.apache.jmeter.samplers.SampleEvent;
024: import org.apache.jmeter.samplers.SampleListener;
025: import org.apache.jmeter.samplers.SampleResult;
026: import org.apache.jmeter.samplers.Sampler;
027: import org.apache.jmeter.testelement.property.BooleanProperty;
028: import org.apache.jmeter.threads.JMeterContext;
029: import org.apache.jmeter.threads.JMeterThread;
030: import org.apache.jmeter.threads.JMeterVariables;
031: import org.apache.jmeter.threads.ListenerNotifier;
032: import org.apache.jmeter.threads.SamplePackage;
033: import org.apache.jorphan.logging.LoggingManager;
034: import org.apache.log.Logger;
035:
036: /**
037: * Transaction Controller to measure transaction times
038: *
039: * There are two different modes for the controller:
040: * - generate additional total sample after nested samples (as in JMeter 2.2)
041: * - generate parent sampler containing the nested samples
042: *
043: */
044: public class TransactionController extends GenericController implements
045: SampleListener, Controller, Serializable {
046: private static final Logger log = LoggingManager
047: .getLoggerForClass();
048:
049: transient private TransactionSampler transactionSampler;
050:
051: transient private ListenerNotifier lnf;
052:
053: transient private SampleResult res;
054:
055: transient private int calls;
056:
057: transient private int noFailingSamples;
058:
059: private static final String PARENT = "TransactionController.parent";// $NON-NLS-1$
060:
061: /**
062: * Creates a Transaction Controller
063: */
064: public TransactionController() {
065: lnf = new ListenerNotifier();
066: }
067:
068: private Object readResolve() {
069: lnf = new ListenerNotifier();
070: return this ;
071: }
072:
073: public void setParent(boolean _parent) {
074: setProperty(new BooleanProperty(PARENT, _parent));
075: }
076:
077: public boolean isParent() {
078: return getPropertyAsBoolean(PARENT);
079: }
080:
081: public Sampler next() {
082: if (isParent()) {
083: return next1();
084: } else {
085: return next2();
086: }
087: }
088:
089: ///////////////// Transaction Controller - parent ////////////////
090:
091: /**
092: * @see org.apache.jmeter.control.Controller#next()
093: */
094: public Sampler next1() {
095: // Check if transaction is done
096: if (transactionSampler != null
097: && transactionSampler.isTransactionDone()) {
098: if (log.isDebugEnabled()) {
099: log.debug("End of transaction " + getName());
100: }
101: // This transaction is done
102: transactionSampler = null;
103: return null;
104: }
105:
106: // Check if it is the start of a new transaction
107: if (isFirst()) // must be the start of the subtree
108: {
109: if (log.isDebugEnabled()) {
110: log.debug("Start of transaction " + getName());
111: }
112: transactionSampler = new TransactionSampler(this , getName());
113: }
114:
115: // Sample the children of the transaction
116: Sampler subSampler = super .next();
117: transactionSampler.setSubSampler(subSampler);
118: // If we do not get any sub samplers, the transaction is done
119: if (subSampler == null) {
120: transactionSampler.setTransactionDone();
121: }
122: return transactionSampler;
123: }
124:
125: protected Sampler nextIsAController(Controller controller)
126: throws NextIsNullException {
127: if (!isParent()) {
128: return super .nextIsAController(controller);
129: }
130: Sampler returnValue;
131: Sampler sampler = controller.next();
132: if (sampler == null) {
133: currentReturnedNull(controller);
134: // We need to call the super.next, instead of this.next, which is done in GenericController,
135: // because if we call this.next(), it will return the TransactionSampler, and we do not want that.
136: // We need to get the next real sampler or controller
137: returnValue = super .next();
138: } else {
139: returnValue = sampler;
140: }
141: return returnValue;
142: }
143:
144: ////////////////////// Transaction Controller - additional sample //////////////////////////////
145:
146: public Sampler next2() {
147: if (isFirst()) // must be the start of the subtree
148: {
149: calls = 0;
150: noFailingSamples = 0;
151: res = new SampleResult();
152: res.setSampleLabel(getName());
153: // Assume success
154: res.setSuccessful(true);
155: res.sampleStart();
156: }
157:
158: Sampler returnValue = super .next();
159:
160: if (returnValue == null) // Must be the end of the controller
161: {
162: if (res != null) {
163: res.sampleEnd();
164: res
165: .setResponseMessage("Number of samples in transaction : "
166: + calls
167: + ", number of failing samples : "
168: + noFailingSamples);
169: if (res.isSuccessful()) {
170: res.setResponseCodeOK();
171: }
172:
173: // TODO could these be done earlier (or just once?)
174: JMeterContext threadContext = getThreadContext();
175: JMeterVariables threadVars = threadContext
176: .getVariables();
177:
178: SamplePackage pack = (SamplePackage) threadVars
179: .getObject(JMeterThread.PACKAGE_OBJECT);
180: if (pack == null) {
181: log.warn("Could not fetch SamplePackage");
182: } else {
183: SampleEvent event = new SampleEvent(res,
184: threadContext.getThreadGroup().getName());
185: // We must set res to null now, before sending the event for the transaction,
186: // so that we can ignore that event in our sampleOccured method
187: res = null;
188: lnf.notifyListeners(event, pack
189: .getSampleListeners());
190: }
191: }
192: } else {
193: // We have sampled one of our children
194: calls++;
195: }
196:
197: return returnValue;
198: }
199:
200: public void sampleOccurred(SampleEvent se) {
201: if (!isParent()) {
202: // Check if we are still sampling our children
203: if (res != null) {
204: SampleResult sampleResult = se.getResult();
205: res.setThreadName(sampleResult.getThreadName());
206: res.setBytes(res.getBytes() + sampleResult.getBytes());
207: if (!sampleResult.isSuccessful()) {
208: res.setSuccessful(false);
209: noFailingSamples++;
210: }
211: }
212: }
213: }
214:
215: public void sampleStarted(SampleEvent e) {
216: }
217:
218: public void sampleStopped(SampleEvent e) {
219: }
220: }
|