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.testelement;
020:
021: import java.io.Serializable;
022: import java.util.Collections;
023: import java.util.LinkedHashMap;
024: import java.util.LinkedHashSet;
025: import java.util.Iterator;
026: import java.util.Map;
027: import java.util.Set;
028:
029: import org.apache.jmeter.control.NextIsNullException;
030: import org.apache.jmeter.samplers.Sampler;
031: import org.apache.jmeter.testelement.property.CollectionProperty;
032: import org.apache.jmeter.testelement.property.JMeterProperty;
033: import org.apache.jmeter.testelement.property.MapProperty;
034: import org.apache.jmeter.testelement.property.MultiProperty;
035: import org.apache.jmeter.testelement.property.NullProperty;
036: import org.apache.jmeter.testelement.property.PropertyIterator;
037: import org.apache.jmeter.testelement.property.PropertyIteratorImpl;
038: import org.apache.jmeter.testelement.property.StringProperty;
039: import org.apache.jmeter.testelement.property.TestElementProperty;
040: import org.apache.jmeter.threads.JMeterContext;
041: import org.apache.jmeter.threads.JMeterContextService;
042: import org.apache.jorphan.logging.LoggingManager;
043: import org.apache.log.Logger;
044:
045: /**
046: */
047: public abstract class AbstractTestElement implements TestElement,
048: Serializable {
049: private static final Logger log = LoggingManager
050: .getLoggerForClass();
051:
052: private Map propMap = Collections
053: .synchronizedMap(new LinkedHashMap());
054:
055: private transient Set temporaryProperties;
056:
057: private transient boolean runningVersion = false;
058:
059: // Thread-specific variables saved here to save recalculation
060: private transient JMeterContext threadContext = null;
061:
062: private transient String threadName = null;
063:
064: public Object clone() {
065: try {
066: TestElement clonedElement = (TestElement) this .getClass()
067: .newInstance();
068:
069: PropertyIterator iter = propertyIterator();
070: while (iter.hasNext()) {
071: clonedElement.setProperty((JMeterProperty) iter.next()
072: .clone());
073: }
074: clonedElement.setRunningVersion(runningVersion);
075: return clonedElement;
076: } catch (InstantiationException e) {
077: throw new AssertionError(e); // clone should never return null
078: } catch (IllegalAccessException e) {
079: throw new AssertionError(e); // clone should never return null
080: }
081: }
082:
083: public void clear() {
084: propMap.clear();
085: }
086:
087: public void removeProperty(String key) {
088: propMap.remove(key);
089: }
090:
091: public boolean equals(Object o) {
092: if (o instanceof AbstractTestElement) {
093: return ((AbstractTestElement) o).propMap.equals(propMap);
094: } else {
095: return false;
096: }
097: }
098:
099: // TODO temporary hack to avoid unnecessary bug reports for subclasses
100:
101: public int hashCode() {
102: return System.identityHashCode(this );
103: }
104:
105: /*
106: * URGENT: TODO - sort out equals and hashCode() - at present equal
107: * instances can/will have different hashcodes - problem is, when a proper
108: * hashcode is used, tests stop working, e.g. listener data disappears when
109: * switching views... This presumably means that instances currently
110: * regarded as equal, aren't really equal...
111: *
112: * (non-Javadoc)
113: *
114: * @see java.lang.Object#hashCode()
115: */
116: // This would be sensible, but does not work:
117: // public int hashCode()
118: // {
119: // return propMap.hashCode();
120: // }
121: public void addTestElement(TestElement el) {
122: mergeIn(el);
123: }
124:
125: public void setName(String name) {
126: setProperty(new StringProperty(TestElement.NAME, name));
127: }
128:
129: public String getName() {
130: return getProperty(TestElement.NAME).getStringValue();
131: }
132:
133: public void setComment(String comment) {
134: setProperty(new StringProperty(TestElement.COMMENTS, comment));
135: }
136:
137: public String getComment() {
138: return getProperty(TestElement.COMMENTS).getStringValue();
139: }
140:
141: /**
142: * Get the named property. If it doesn't exist, a new NullProperty object is
143: * created with the same name and returned.
144: */
145: public JMeterProperty getProperty(String key) {
146: JMeterProperty prop = (JMeterProperty) propMap.get(key);
147: if (prop == null) {
148: prop = new NullProperty(key);
149: }
150: return prop;
151: }
152:
153: public void traverse(TestElementTraverser traverser) {
154: PropertyIterator iter = propertyIterator();
155: traverser.startTestElement(this );
156: while (iter.hasNext()) {
157: traverseProperty(traverser, iter.next());
158: }
159: traverser.endTestElement(this );
160: }
161:
162: protected void traverseProperty(TestElementTraverser traverser,
163: JMeterProperty value) {
164: traverser.startProperty(value);
165: if (value instanceof TestElementProperty) {
166: ((TestElement) value.getObjectValue()).traverse(traverser);
167: } else if (value instanceof CollectionProperty) {
168: traverseCollection((CollectionProperty) value, traverser);
169: } else if (value instanceof MapProperty) {
170: traverseMap((MapProperty) value, traverser);
171: }
172: traverser.endProperty(value);
173: }
174:
175: protected void traverseMap(MapProperty map,
176: TestElementTraverser traverser) {
177: PropertyIterator iter = map.valueIterator();
178: while (iter.hasNext()) {
179: traverseProperty(traverser, iter.next());
180: }
181: }
182:
183: protected void traverseCollection(CollectionProperty col,
184: TestElementTraverser traverser) {
185: PropertyIterator iter = col.iterator();
186: while (iter.hasNext()) {
187: traverseProperty(traverser, iter.next());
188: }
189: }
190:
191: public int getPropertyAsInt(String key) {
192: return getProperty(key).getIntValue();
193: }
194:
195: public boolean getPropertyAsBoolean(String key) {
196: return getProperty(key).getBooleanValue();
197: }
198:
199: public boolean getPropertyAsBoolean(String key, boolean defaultVal) {
200: JMeterProperty jmp = getProperty(key);
201: return jmp instanceof NullProperty ? defaultVal : jmp
202: .getBooleanValue();
203: }
204:
205: public float getPropertyAsFloat(String key) {
206: return getProperty(key).getFloatValue();
207: }
208:
209: public long getPropertyAsLong(String key) {
210: return getProperty(key).getLongValue();
211: }
212:
213: public double getPropertyAsDouble(String key) {
214: return getProperty(key).getDoubleValue();
215: }
216:
217: public String getPropertyAsString(String key) {
218: return getProperty(key).getStringValue();
219: }
220:
221: public String getPropertyAsString(String key, String defaultValue) {
222: JMeterProperty jmp = getProperty(key);
223: return jmp instanceof NullProperty ? defaultValue : jmp
224: .getStringValue();
225: }
226:
227: protected void addProperty(JMeterProperty property) {
228: if (isRunningVersion()) {
229: setTemporary(property);
230: } else {
231: clearTemporary(property);
232: }
233: JMeterProperty prop = getProperty(property.getName());
234:
235: if (prop instanceof NullProperty
236: || (prop instanceof StringProperty && prop
237: .getStringValue().equals(""))) {
238: propMap.put(property.getName(), property);
239: } else {
240: prop.mergeIn(property);
241: }
242: }
243:
244: protected void clearTemporary(JMeterProperty property) {
245: if (temporaryProperties != null) {
246: temporaryProperties.remove(property);
247: }
248: }
249:
250: /**
251: * Log the properties of the test element
252: *
253: * @see TestElement#setProperty(JMeterProperty)
254: */
255: protected void logProperties() {
256: if (log.isDebugEnabled()) {
257: PropertyIterator iter = propertyIterator();
258: while (iter.hasNext()) {
259: JMeterProperty prop = iter.next();
260: log.debug("Property " + prop.getName() + " is temp? "
261: + isTemporary(prop) + " and is a "
262: + prop.getObjectValue());
263: }
264: }
265: }
266:
267: public void setProperty(JMeterProperty property) {
268: if (isRunningVersion()) {
269: if (getProperty(property.getName()) instanceof NullProperty) {
270: addProperty(property);
271: } else {
272: getProperty(property.getName()).setObjectValue(
273: property.getObjectValue());
274: }
275: } else {
276: propMap.put(property.getName(), property);
277: }
278: }
279:
280: public void setProperty(String name, String value) {
281: setProperty(new StringProperty(name, value));
282: }
283:
284: public void setProperty(String name, boolean value) {
285: setProperty(new StringProperty(name, Boolean.toString(value)));
286: }
287:
288: public PropertyIterator propertyIterator() {
289: return new PropertyIteratorImpl(propMap.values());
290: }
291:
292: protected void mergeIn(TestElement element) {
293: PropertyIterator iter = element.propertyIterator();
294: while (iter.hasNext()) {
295: JMeterProperty prop = iter.next();
296: addProperty(prop);
297: }
298: }
299:
300: /**
301: * Returns the runningVersion.
302: */
303: public boolean isRunningVersion() {
304: return runningVersion;
305: }
306:
307: /**
308: * Sets the runningVersion.
309: *
310: * @param runningVersion
311: * the runningVersion to set
312: */
313: public void setRunningVersion(boolean runningVersion) {
314: this .runningVersion = runningVersion;
315: PropertyIterator iter = propertyIterator();
316: while (iter.hasNext()) {
317: iter.next().setRunningVersion(runningVersion);
318: }
319: }
320:
321: public void recoverRunningVersion() {
322: Iterator iter = propMap.entrySet().iterator();
323: while (iter.hasNext()) {
324: Map.Entry entry = (Map.Entry) iter.next();
325: JMeterProperty prop = (JMeterProperty) entry.getValue();
326: if (isTemporary(prop)) {
327: iter.remove();
328: clearTemporary(prop);
329: } else {
330: prop.recoverRunningVersion(this );
331: }
332: }
333: emptyTemporary();
334: }
335:
336: protected void emptyTemporary() {
337: if (temporaryProperties != null) {
338: temporaryProperties.clear();
339: }
340: }
341:
342: protected Sampler nextIsNull() throws NextIsNullException {
343: return null;
344: }
345:
346: /*
347: * (non-Javadoc)
348: *
349: * @see org.apache.jmeter.testelement.TestElement#isTemporary(org.apache.jmeter.testelement.property.JMeterProperty)
350: */
351: public boolean isTemporary(JMeterProperty property) {
352: if (temporaryProperties == null) {
353: return false;
354: } else {
355: return temporaryProperties.contains(property);
356: }
357: }
358:
359: /*
360: * (non-Javadoc)
361: *
362: * @see org.apache.jmeter.testelement.TestElement#setTemporary(org.apache.jmeter.testelement.property.JMeterProperty)
363: */
364: public void setTemporary(JMeterProperty property) {
365: if (temporaryProperties == null) {
366: temporaryProperties = new LinkedHashSet();
367: }
368: temporaryProperties.add(property);
369: if (property instanceof MultiProperty) {
370: PropertyIterator iter = ((MultiProperty) property)
371: .iterator();
372: while (iter.hasNext()) {
373: setTemporary(iter.next());
374: }
375: }
376: }
377:
378: /**
379: * @return Returns the threadContext.
380: */
381: public JMeterContext getThreadContext() {
382: if (threadContext == null) {
383: /*
384: * Only samplers have the thread context set up by JMeterThread at
385: * present, so suppress the warning for now
386: */
387: // log.warn("ThreadContext was not set up - should only happen in
388: // JUnit testing..."
389: // ,new Throwable("Debug"));
390: threadContext = JMeterContextService.getContext();
391: }
392: return threadContext;
393: }
394:
395: /**
396: * @param inthreadContext
397: * The threadContext to set.
398: */
399: public void setThreadContext(JMeterContext inthreadContext) {
400: if (threadContext != null) {
401: if (inthreadContext != threadContext)
402: throw new RuntimeException(
403: "Attempting to reset the thread context");
404: }
405: this .threadContext = inthreadContext;
406: }
407:
408: /**
409: * @return Returns the threadName.
410: */
411: public String getThreadName() {
412: return threadName;
413: }
414:
415: /**
416: * @param inthreadName
417: * The threadName to set.
418: */
419: public void setThreadName(String inthreadName) {
420: if (threadName != null) {
421: if (!threadName.equals(inthreadName))
422: throw new RuntimeException(
423: "Attempting to reset the thread name");
424: }
425: this .threadName = inthreadName;
426: }
427:
428: public AbstractTestElement() {
429: super ();
430: }
431:
432: // Default implementation
433: public boolean canRemove() {
434: return true;
435: }
436:
437: // Moved from JMeter class
438: public boolean isEnabled() {
439: return getProperty(TestElement.ENABLED) instanceof NullProperty
440: || getPropertyAsBoolean(TestElement.ENABLED);
441: }
442: }
|