blob: 4bff0593df0788cea64c526f749cae1868a73a59 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.functions;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
/**
* This class wraps the FileRowColContainer for use across multiple threads.
*
* It does this by maintaining a list of open files, keyed by file name (or
* alias, if used). A list of open files is also maintained for each thread,
* together with the current line number.
*
*/
public final class FileWrapper {
private static final Logger log = LoggingManager.getLoggerForClass();
private static final int NO_LINE = -1;
private static volatile String defaultFile = ""; // for omitted file names //$NON-NLS-1$
/*
* This Map serves two purposes:
* - maps file names to containers
* - ensures only one container per file across all threads
*/
private static final Map<String, FileRowColContainer> fileContainers = new HashMap<>();
/* The cache of file packs - used to improve thread access */
private static final ThreadLocal<Map<String, FileWrapper>> filePacks =
new ThreadLocal<Map<String, FileWrapper>>() {
@Override
protected Map<String, FileWrapper> initialValue() {
return new HashMap<>();
}
};
private final FileRowColContainer container;
private int currentRow;
/*
* Only needed locally
*/
private FileWrapper(FileRowColContainer fdc) {
super();
container = fdc;
currentRow = -1;
}
private static String checkDefault(String file) {
if (file.length() == 0) {
if (fileContainers.size() == 1 && defaultFile.length() > 0) {
log.warn("Using default: " + defaultFile);
file = defaultFile;
} else {
log.error("Cannot determine default file name");
}
}
return file;
}
/*
* called by CSVRead(file,alias)
*/
public static synchronized void open(String file, String alias) {
log.info("Opening " + file + " as " + alias);
file = checkDefault(file);
if (alias.length() == 0) {
log.error("Alias cannot be empty");
return;
}
Map<String, FileWrapper> m = filePacks.get();
if (m.get(alias) == null) {
FileRowColContainer frcc;
try {
frcc = getFile(file, alias);
log.info("Stored " + file + " as " + alias);
m.put(alias, new FileWrapper(frcc));
} catch (IOException e) {
// Already logged
}
}
}
private static FileRowColContainer getFile(String file, String alias) throws FileNotFoundException, IOException {
FileRowColContainer frcc;
if ((frcc = fileContainers.get(alias)) == null) {
frcc = new FileRowColContainer(file);
fileContainers.put(alias, frcc);
log.info("Saved " + file + " as " + alias + " delimiter=<" + frcc.getDelimiter() + ">");
if (defaultFile.length() == 0) {
defaultFile = file;// Save in case needed later
}
}
return frcc;
}
/*
* Called by CSVRead(x,next) - sets the row to nil so the next row will be
* picked up the next time round
*
*/
public static void endRow(String file) {
file = checkDefault(file);
Map<String, FileWrapper> my = filePacks.get();
FileWrapper fw = my.get(file);
if (fw == null) {
log.warn("endRow(): no entry for " + file);
} else {
fw.endRow();
}
}
private void endRow() {
if (currentRow == NO_LINE) {
log.warn("endRow() called twice in succession");
}
currentRow = NO_LINE;
}
public static String getColumn(String file, int col) {
Map<String, FileWrapper> my = filePacks.get();
FileWrapper fw = my.get(file);
if (fw == null) // First call
{
if (file.startsWith("*")) { //$NON-NLS-1$
log.warn("Cannot perform initial open using alias " + file);
} else {
file = checkDefault(file);
log.info("Attaching " + file);
open(file, file);
fw = my.get(file);
}
// TODO improve the error handling
if (fw == null) {
return ""; //$NON-NLS-1$
}
}
return fw.getColumn(col);
}
private String getColumn(int col) {
if (currentRow == NO_LINE) {
currentRow = container.nextRow();
}
return container.getColumn(currentRow, col);
}
/**
* Gets the current row number (mainly for error reporting)
*
* @param file
* name of the file for which the row number is asked
* @return the current row number for this thread, or <code>-1</code> if
* <code>file</code> was not opened yet
*/
public static int getCurrentRow(String file) {
Map<String, FileWrapper> my = filePacks.get();
FileWrapper fw = my.get(file);
if (fw == null) // Not yet open
{
return -1;
}
return fw.currentRow;
}
/**
*
*/
public static void clearAll() {
log.debug("clearAll()");
Map<String, FileWrapper> my = filePacks.get();
for (Iterator<Map.Entry<String, FileWrapper>> i = my.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, FileWrapper> fw = i.next();
log.info("Removing " + fw.toString());
i.remove();
}
fileContainers.clear();
defaultFile = ""; //$NON-NLS-1$
}
}