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.functions;
020:
021: import java.io.Serializable;
022: import java.util.Collection;
023: import java.util.LinkedList;
024: import java.util.List;
025:
026: import org.apache.jmeter.engine.util.CompoundVariable;
027: import org.apache.jmeter.samplers.SampleResult;
028: import org.apache.jmeter.samplers.Sampler;
029: import org.apache.jmeter.util.JMeterUtils;
030: import org.apache.jorphan.logging.LoggingManager;
031: import org.apache.log.Logger;
032:
033: /**
034: * The function represented by this class allows data to be read from CSV files.
035: * Syntax is similar to StringFromFile function. The function allows the test to
036: * line-thru the data in the CSV file - one line per each test. E.g. inserting
037: * the following in the test scripts :
038: *
039: * ${_CSVRead(c:/BOF/abcd.csv,0)} // read (first) line of 'c:/BOF/abcd.csv' ,
040: * return the 1st column ( represented by the '0'),
041: * ${_CSVRead(c:/BOF/abcd.csv,1)} // read (first) line of 'c:/BOF/abcd.csv' ,
042: * return the 2nd column ( represented by the '1'),
043: * ${_CSVRead(c:/BOF/abcd.csv,next())} // Go to next line of 'c:/BOF/abcd.csv'
044: *
045: * NOTE: A single instance of each different file is opened and used for all
046: * threads.
047: *
048: * To open the same file twice, use the alias function: __CSVRead(abc.csv,*ONE);
049: * __CSVRead(abc.csv,*TWO);
050: *
051: * __CSVRead(*ONE,1); etc
052: *
053: *
054: * @version $Revision: 539777 $ Last Updated: $Date: 2007-05-19 18:04:39 +0100 (Sat, 19 May 2007) $
055: */
056: public class CSVRead extends AbstractFunction implements Serializable {
057: private static final Logger log = LoggingManager
058: .getLoggerForClass();
059:
060: private static final String KEY = "__CSVRead"; // Function name //$NON-NLS-1$
061:
062: private static final List desc = new LinkedList();
063:
064: private Object[] values; // Parameter list
065:
066: static {
067: desc.add(JMeterUtils.getResString("csvread_file_file_name")); //$NON-NLS-1$
068: desc.add(JMeterUtils.getResString("column_number")); //$NON-NLS-1$
069: }
070:
071: public CSVRead() {
072: }
073:
074: public Object clone() throws CloneNotSupportedException {
075: return super .clone();
076: }
077:
078: /**
079: * @see org.apache.jmeter.functions.Function#execute(SampleResult, Sampler)
080: */
081: public synchronized String execute(SampleResult previousResult,
082: Sampler currentSampler) throws InvalidVariableException {
083: String myValue = ""; //$NON-NLS-1$
084:
085: String fileName = ((org.apache.jmeter.engine.util.CompoundVariable) values[0])
086: .execute();
087: String columnOrNext = ((org.apache.jmeter.engine.util.CompoundVariable) values[1])
088: .execute();
089:
090: log.debug("execute (" + fileName + " , " + columnOrNext
091: + ") ");
092:
093: // Process __CSVRead(filename,*ALIAS)
094: if (columnOrNext.startsWith("*")) { //$NON-NLS-1$
095: FileWrapper.open(fileName, columnOrNext);
096: /*
097: * All done, so return
098: */
099: return ""; //$NON-NLS-1$
100: }
101:
102: // if argument is 'next' - go to the next line
103: if (columnOrNext.equals("next()") || columnOrNext.equals("next")) { //$NON-NLS-1$ //$NON-NLS-2$
104: FileWrapper.endRow(fileName);
105:
106: /*
107: * All done now ,so return the empty string - this allows the caller
108: * to append __CSVRead(file,next) to the last instance of
109: * __CSVRead(file,col)
110: *
111: * N.B. It is important not to read any further lines at this point,
112: * otherwise the wrong line can be retrieved when using multiple
113: * threads.
114: */
115: return ""; //$NON-NLS-1$
116: }
117:
118: try {
119: int columnIndex = Integer.parseInt(columnOrNext); // what column
120: // is wanted?
121: myValue = FileWrapper.getColumn(fileName, columnIndex);
122: } catch (NumberFormatException e) {
123: log.warn(Thread.currentThread().getName()
124: + " - can't parse column number: " + columnOrNext
125: + " " + e.toString());
126: } catch (IndexOutOfBoundsException e) {
127: log.warn(Thread.currentThread().getName()
128: + " - invalid column number: " + columnOrNext
129: + " at row " + FileWrapper.getCurrentRow(fileName)
130: + " " + e.toString());
131: }
132:
133: log.debug("execute value: " + myValue);
134:
135: return myValue;
136: }
137:
138: /**
139: * @see org.apache.jmeter.functions.Function#getArgumentDesc()
140: */
141: public List getArgumentDesc() {
142: return desc;
143: }
144:
145: /**
146: * @see org.apache.jmeter.functions.Function#getReferenceKey()
147: */
148: public String getReferenceKey() {
149: return KEY;
150: }
151:
152: /**
153: * @see org.apache.jmeter.functions.Function#setParameters(Collection)
154: */
155: public synchronized void setParameters(Collection parameters)
156: throws InvalidVariableException {
157: log
158: .debug("setParameter - Collection.size="
159: + parameters.size());
160:
161: values = parameters.toArray();
162:
163: if (log.isDebugEnabled()) {
164: for (int i = 0; i < parameters.size(); i++) {
165: log.debug("i:"
166: + ((CompoundVariable) values[i]).execute());
167: }
168: }
169:
170: if (values.length != 2) {
171: throw new InvalidVariableException(
172: "Wrong number of parameters; 2 != " + values.length);
173: }
174:
175: /*
176: * Need to reset the containers for repeated runs; about the only way
177: * for functions to detect that a run is starting seems to be the
178: * setParameters() call.
179: */
180: FileWrapper.clearAll();// TODO only clear the relevant entry - if possible...
181:
182: }
183: }
|