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.FileNotFoundException;
022: import java.io.IOException;
023: import java.util.HashMap;
024: import java.util.Map;
025:
026: import javax.xml.parsers.ParserConfigurationException;
027: import javax.xml.transform.TransformerException;
028:
029: import org.apache.jorphan.logging.LoggingManager;
030: import org.apache.log.Logger;
031: import org.xml.sax.SAXException;
032:
033: /**
034: * This class wraps the XPathFileContainer for use across multiple threads.
035: *
036: * It maintains a list of nodelist containers, one for each file/xpath combination
037: *
038: */
039: public class XPathWrapper {
040:
041: private static final Logger log = LoggingManager
042: .getLoggerForClass();
043:
044: /*
045: * This Map serves two purposes:
046: * - maps names to containers
047: * - ensures only one container per file across all threads
048: */
049: private static Map fileContainers = new HashMap();
050:
051: /* The cache of file packs - for faster local access */
052: private static ThreadLocal filePacks = new ThreadLocal() {
053: protected Object initialValue() {
054: return new HashMap();
055: }
056: };
057:
058: private XPathWrapper() {// Prevent separate instantiation
059: super ();
060: }
061:
062: private static XPathFileContainer open(String file,
063: String xpathString) {
064: String tname = Thread.currentThread().getName();
065: log.info(tname + ": Opening " + file);
066: XPathFileContainer frcc = null;
067: try {
068: frcc = new XPathFileContainer(file, xpathString);
069: } catch (FileNotFoundException e) {
070: log.warn(e.getLocalizedMessage());
071: } catch (IOException e) {
072: log.warn(e.getLocalizedMessage());
073: } catch (ParserConfigurationException e) {
074: log.warn(e.getLocalizedMessage());
075: } catch (SAXException e) {
076: log.warn(e.getLocalizedMessage());
077: } catch (TransformerException e) {
078: log.warn(e.getLocalizedMessage());
079: }
080: return frcc;
081: }
082:
083: /**
084: * Not thread-safe - must be called from a synchronized method.
085: *
086: * @param file
087: * @param xpathString
088: * @return the next row from the file container
089: */
090: public static String getXPathString(String file, String xpathString) {
091: Map my = (Map) filePacks.get();
092: String key = file + xpathString;
093: XPathFileContainer xpfc = (XPathFileContainer) my.get(key);
094: if (xpfc == null) // We don't have a local copy
095: {
096: synchronized (fileContainers) {
097: xpfc = (XPathFileContainer) fileContainers.get(key);
098: if (xpfc == null) { // There's no global copy either
099: xpfc = open(file, xpathString);
100: }
101: if (xpfc != null) {
102: fileContainers.put(key, xpfc);// save the global copy
103: }
104: }
105: // TODO improve the error handling
106: if (xpfc == null) {
107: log.error("XPathWrapper is null!");
108: return ""; //$NON-NLS-1$
109: }
110: my.put(key, xpfc); // save our local copy
111: }
112: int currentRow = xpfc.nextRow();
113: log.debug("getting match number " + currentRow);
114: return xpfc.getXPathString(currentRow);
115: }
116:
117: public static void clearAll() {
118: log.debug("clearAll()");
119: Map my = (Map) filePacks.get();
120: my.clear();
121: String tname = Thread.currentThread().getName();
122: log.info(tname + ": clearing container");
123: fileContainers.clear();
124: }
125: }
|