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.modifiers;
020:
021: import java.io.ObjectStreamException;
022: import java.io.Serializable;
023: import java.text.DecimalFormat;
024:
025: import org.apache.jmeter.engine.event.LoopIterationEvent;
026: import org.apache.jmeter.engine.event.LoopIterationListener;
027: import org.apache.jmeter.engine.util.NoThreadClone;
028: import org.apache.jmeter.testelement.AbstractTestElement;
029: import org.apache.jmeter.testelement.property.BooleanProperty;
030: import org.apache.jmeter.testelement.property.LongProperty;
031: import org.apache.jmeter.threads.JMeterContextService;
032: import org.apache.jmeter.threads.JMeterVariables;
033:
034: /**
035: * Provides a counter per-thread/user or globally
036: * The long value can be
037: */
038: public class CounterConfig extends AbstractTestElement implements
039: Serializable, LoopIterationListener, NoThreadClone {
040:
041: private final static String START = "CounterConfig.start"; // $NON-NLS-1$
042:
043: private final static String END = "CounterConfig.end"; // $NON-NLS-1$
044:
045: private final static String INCREMENT = "CounterConfig.incr"; // $NON-NLS-1$
046:
047: private final static String FORMAT = "CounterConfig.format"; // $NON-NLS-1$
048:
049: public final static String PER_USER = "CounterConfig.per_user"; // $NON-NLS-1$
050:
051: public final static String VAR_NAME = "CounterConfig.name"; // $NON-NLS-1$
052:
053: // This class is not cloned per thread, so this is shared
054: private long globalCounter = Long.MIN_VALUE;
055:
056: // Used for per-thread/user numbers
057: transient private ThreadLocal perTheadNumber;
058:
059: private void init() {
060: perTheadNumber = new ThreadLocal() {
061: protected synchronized Object initialValue() {
062: return new Long(getStart());
063: }
064: };
065: }
066:
067: public CounterConfig() {
068: super ();
069: init();
070: }
071:
072: private Object readResolve() throws ObjectStreamException {
073: init();
074: return this ;
075: }
076:
077: /**
078: * @see LoopIterationListener#iterationStart(LoopIterationEvent)
079: */
080: public synchronized void iterationStart(LoopIterationEvent event) {
081: // Cannot use getThreadContext() as not cloned per thread
082: JMeterVariables variables = JMeterContextService.getContext()
083: .getVariables();
084: long start = getStart(), end = getEnd(), increment = getIncrement();
085: if (!isPerUser()) {
086: if (globalCounter == Long.MIN_VALUE || globalCounter > end) {
087: globalCounter = start;
088: }
089: variables.put(getVarName(), formatNumber(globalCounter));
090: globalCounter += increment;
091: } else {
092: long current = ((Long) perTheadNumber.get()).longValue();
093: variables.put(getVarName(), formatNumber(current));
094: current += increment;
095: if (current > end) {
096: current = start;
097: }
098: perTheadNumber.set(new Long(current));
099: }
100: }
101:
102: // Use format to create number; if it fails, use the default
103: private String formatNumber(long value) {
104: String format = getFormat();
105: if (format != null && format.length() > 0) {
106: try {
107: DecimalFormat myFormatter = new DecimalFormat(format);
108: return myFormatter.format(value);
109: } catch (NumberFormatException ignored) {
110: } catch (IllegalArgumentException ignored) {
111: }
112: }
113: return Long.toString(value);
114: }
115:
116: public void setStart(long start) {
117: setProperty(new LongProperty(START, start));
118: }
119:
120: public void setStart(String start) {
121: setProperty(START, start);
122: }
123:
124: public long getStart() {
125: return getPropertyAsLong(START);
126: }
127:
128: public String getStartAsString() {
129: return getPropertyAsString(START);
130: }
131:
132: public void setEnd(long end) {
133: setProperty(new LongProperty(END, end));
134: }
135:
136: public void setEnd(String end) {
137: setProperty(END, end);
138: }
139:
140: /**
141: *
142: * @return counter upper limit (default Long.MAX_VALUE)
143: */
144: public long getEnd() {
145: long propertyAsLong = getPropertyAsLong(END);
146: if (propertyAsLong == 0
147: && "".equals(getProperty(END).getStringValue())) {
148: propertyAsLong = Long.MAX_VALUE;
149: }
150: return propertyAsLong;
151: }
152:
153: public String getEndAsString() {
154: return getPropertyAsString(END);
155: }
156:
157: public void setIncrement(long inc) {
158: setProperty(new LongProperty(INCREMENT, inc));
159: }
160:
161: public void setIncrement(String incr) {
162: setProperty(INCREMENT, incr);
163: }
164:
165: public long getIncrement() {
166: return getPropertyAsLong(INCREMENT);
167: }
168:
169: public String getIncrementAsString() {
170: return getPropertyAsString(INCREMENT);
171: }
172:
173: public void setIsPerUser(boolean isPer) {
174: setProperty(new BooleanProperty(PER_USER, isPer));
175: }
176:
177: public boolean isPerUser() {
178: return getPropertyAsBoolean(PER_USER);
179: }
180:
181: public void setVarName(String name) {
182: setProperty(VAR_NAME, name);
183: }
184:
185: public String getVarName() {
186: return getPropertyAsString(VAR_NAME);
187: }
188:
189: public void setFormat(String format) {
190: setProperty(FORMAT, format);
191: }
192:
193: public String getFormat() {
194: return getPropertyAsString(FORMAT);
195: }
196: }
|