Package org.apache.jmeter.services

Source Code of org.apache.jmeter.services.FileServer$FileEntry

/*
* 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.
*
*/

/*
* Created on Oct 19, 2004
*/
package org.apache.jmeter.services;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;

import org.apache.jmeter.gui.JMeterFileFilter;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
*
* The point of this class is to provide thread-safe access to files, and to
* provide some simplifying assumptions about where to find files and how to
* name them. For instance, putting supporting files in the same directory as
* the saved test plan file allows users to refer to the file with just it's
* name - this FileServer class will find the file without a problem.
* Eventually, I want all in-test file access to be done through here, with the
* goal of packaging up entire test plans as a directory structure that can be
* sent via rmi to remote servers (currently, one must make sure the remote
* server has all support files in a relative-same location) and to package up
* test plans to execute on unknown boxes that only have Java installed.
*/
public class FileServer {
    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final String DEFAULT_BASE = System.getProperty("user.dir");

    //@GuardedBy("this")
    private File base;

    //@GuardedBy("this")
    private final Map<String, FileEntry> files = new HashMap<String, FileEntry>();

    private static final FileServer server = new FileServer();

    private final Random random = new Random();

    private FileServer() {
        base = new File(DEFAULT_BASE);
        log.info("Default base="+DEFAULT_BASE);
    }

    public static FileServer getFileServer() {
        return server;
    }

    public void resetBase() throws IOException{
        setBasedir(DEFAULT_BASE);
    }

    public synchronized void setBasedir(String basedir) throws IOException {
        if (filesOpen()) {
            throw new IOException("Files are still open, cannot change base directory");
        }
        files.clear();
        if (basedir != null) {
            base = new File(basedir);
            if (!base.isDirectory()) {
                base = base.getParentFile();
            }
            log.info("Set new base="+base);
        }
    }

    public synchronized String getBaseDir() {
        return base.getAbsolutePath();
    }

    /**
     * Creates an association between a filename and a File inputOutputObject,
     * and stores it for later use - unless it is already stored.
     *
     * @param filename - relative (to base) or absolute file name (must not be null)
     */
    public synchronized void reserveFile(String filename) {
        reserveFile(filename,null);
    }

    /**
     * Creates an association between a filename and a File inputOutputObject,
     * and stores it for later use - unless it is already stored.
     *
     * @param filename - relative (to base) or absolute file name (must not be null)
     * @param charsetName - the character set encoding to use for the file (may be null)
     */
    public synchronized void reserveFile(String filename, String charsetName) {
        reserveFile(filename, charsetName, filename, false);
    }

    /**
     * Creates an association between a filename and a File inputOutputObject,
     * and stores it for later use - unless it is already stored.
     *
     * @param filename - relative (to base) or absolute file name (must not be null)
     * @param charsetName - the character set encoding to use for the file (may be null)
     * @param alias - the name to be used to access the object (must not be null)
     */
    public synchronized void reserveFile(String filename, String charsetName, String alias) {
        reserveFile(filename, charsetName, alias, false);
    }

    /**
     * Creates an association between a filename and a File inputOutputObject,
     * and stores it for later use - unless it is already stored.
     *
     * @param filename - relative (to base) or absolute file name (must not be null)
     * @param charsetName - the character set encoding to use for the file (may be null)
     * @param alias - the name to be used to access the object (must not be null)
     * @param hasHeader true if the file has a header line describing the contents
     */
    public synchronized String reserveFile(String filename, String charsetName, String alias, boolean hasHeader) {
        if (filename == null){
            throw new IllegalArgumentException("Filename must not be null");
        }
        if (alias == null){
            throw new IllegalArgumentException("Alias must not be null");
        }
        FileEntry fileEntry = files.get(alias);
        if (fileEntry == null) {
            File f = new File(filename);
            fileEntry =
                new FileEntry(f.isAbsolute() ? f : new File(base, filename),null,charsetName);
            if (filename.equals(alias)){
                log.info("Stored: "+filename);
            } else {
                log.info("Stored: "+filename+" Alias: "+alias);
            }
            files.put(alias, fileEntry);
            if (hasHeader){
                try {
                    fileEntry.headerLine=readLine(alias, false);
                } catch (IOException e) {
                    throw new IllegalArgumentException("Could not read file header line",e);
                }
            }
        }
        return fileEntry.headerLine;
    }

   /**
     * Get the next line of the named file, recycle by default.
     *
     * @param filename
     * @return String containing the next line in the file
     * @throws IOException
     */
    public String readLine(String filename) throws IOException {
      return readLine(filename, true);
    }

   /**
     * Get the next line of the named file.
     *
     * @param filename
     * @param recycle - should file be restarted at EOF?
     * @return String containing the next line in the file (null if EOF reached and not recycle)
     * @throws IOException
     */
    public synchronized String readLine(String filename, boolean recycle) throws IOException {
        FileEntry fileEntry = files.get(filename);
        if (fileEntry != null) {
            if (fileEntry.inputOutputObject == null) {
                fileEntry.inputOutputObject = createBufferedReader(fileEntry, filename);
            } else if (!(fileEntry.inputOutputObject instanceof Reader)) {
                throw new IOException("File " + filename + " already in use");
            }
            BufferedReader reader = (BufferedReader) fileEntry.inputOutputObject;
            String line = reader.readLine();
            if (line == null && recycle) {
                reader.close();
                reader = createBufferedReader(fileEntry, filename);
                fileEntry.inputOutputObject = reader;
                line = reader.readLine();
            }
            if (log.isDebugEnabled()) { log.debug("Read:"+line); }
            return line;
        }
        throw new IOException("File never reserved: "+filename);
    }

    private BufferedReader createBufferedReader(FileEntry fileEntry, String filename) throws IOException {
        FileInputStream fis = new FileInputStream(fileEntry.file);
        InputStreamReader isr = null;
        // If file encoding is specified, read using that encoding, otherwise use default platform encoding
        String charsetName = fileEntry.charSetEncoding;
        if(charsetName != null && charsetName.trim().length() > 0) {
            isr = new InputStreamReader(fis, charsetName);
        } else {
            isr = new InputStreamReader(fis);
        }
        return new BufferedReader(isr);
    }

    public synchronized void write(String filename, String value) throws IOException {
        FileEntry fileEntry = files.get(filename);
        if (fileEntry != null) {
            if (fileEntry.inputOutputObject == null) {
                fileEntry.inputOutputObject = createBufferedWriter(fileEntry, filename);
            } else if (!(fileEntry.inputOutputObject instanceof Writer)) {
                throw new IOException("File " + filename + " already in use");
            }
            BufferedWriter writer = (BufferedWriter) fileEntry.inputOutputObject;
            if (log.isDebugEnabled()) { log.debug("Write:"+value); }
            writer.write(value);
        } else {
            throw new IOException("File never reserved: "+filename);
        }
    }

    private BufferedWriter createBufferedWriter(FileEntry fileEntry, String filename) throws IOException {
        FileOutputStream fos = new FileOutputStream(fileEntry.file);
        OutputStreamWriter osw = null;
        // If file encoding is specified, write using that encoding, otherwise use default platform encoding
        String charsetName = fileEntry.charSetEncoding;
        if(charsetName != null && charsetName.trim().length() > 0) {
            osw = new OutputStreamWriter(fos, charsetName);
        } else {
            osw = new OutputStreamWriter(fos);
        }
        return new BufferedWriter(osw);
    }

    public synchronized void closeFiles() throws IOException {
        Iterator<Map.Entry<String, FileEntry>>  iter = files.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, FileEntry> me = iter.next();
            closeFile(me.getKey(),me.getValue() );
        }
        files.clear();
    }

    /**
     * @param name
     * @throws IOException
     */
    public synchronized void closeFile(String name) throws IOException {
        FileEntry fileEntry = files.get(name);
        closeFile(name, fileEntry);
    }

    private void closeFile(String name, FileEntry fileEntry) throws IOException {
        if (fileEntry != null && fileEntry.inputOutputObject != null) {
            log.info("Close: "+name);
            if (fileEntry.inputOutputObject instanceof Reader) {
                ((Reader) fileEntry.inputOutputObject).close();
            } else if (fileEntry.inputOutputObject instanceof Writer) {
                ((Writer) fileEntry.inputOutputObject).close();
            } else {
                log.error("Unknown inputOutputObject type : " + fileEntry.inputOutputObject.getClass());
            }
            fileEntry.inputOutputObject = null;
        }
    }

    boolean filesOpen() { // package access for test code only
        Iterator<FileEntry> iter = files.values().iterator();
        while (iter.hasNext()) {
            FileEntry fileEntry = iter.next();
            if (fileEntry.inputOutputObject != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Method will get a random file in a base directory
     * TODO hey, not sure this method belongs here.  FileServer is for threadsafe
     * File access relative to current test's base directory.
     *
     * @param basedir
     * @return a random File from the basedir that matches one of the extensions
     */
    public File getRandomFile(String basedir, String[] extensions) {
        File input = null;
        if (basedir != null) {
            File src = new File(basedir);
            if (src.isDirectory() && src.list() != null) {
                File[] lfiles = src.listFiles(new JMeterFileFilter(extensions));
                int count = lfiles.length;
                input = lfiles[random.nextInt(count)];
            }
        }
        return input;
    }

    private static class FileEntry{
        private String headerLine;
        private final File file;
        private Object inputOutputObject; // Reader/Writer
        private final String charSetEncoding;
        FileEntry(File f, Object o, String e){
            file=f;
            inputOutputObject=o;
            charSetEncoding=e;
        }
    }
}
TOP

Related Classes of org.apache.jmeter.services.FileServer$FileEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.