com.panet.imeta.core.vfs.KettleVFS.java Source code

Java tutorial

Introduction

Here is the source code for com.panet.imeta.core.vfs.KettleVFS.java

Source

/*
 * Copyright (c) 2007 Pentaho Corporation.  All rights reserved. 
 * This software was developed by Pentaho Corporation and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Pentaho 
 * Data Integration.  The Initial Developer is Pentaho Corporation.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
*/
package com.panet.imeta.core.vfs;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Comparator;

import org.apache.commons.vfs.FileContent;
import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.VFS;
import org.apache.commons.vfs.impl.DefaultFileSystemManager;
import org.apache.commons.vfs.provider.local.LocalFile;

import com.panet.imeta.core.Const;
import com.panet.imeta.core.util.UUIDUtil;

public class KettleVFS {
    private static KettleVFS kettleVFS;

    private KettleVFS() {
        // Install a shutdown hook to make sure that the file system manager is closed
        // This will clean up temporary files in vfs_cache
        //
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    FileSystemManager mgr = VFS.getManager();
                    if (mgr instanceof DefaultFileSystemManager) {
                        ((DefaultFileSystemManager) mgr).close();
                    }
                } catch (FileSystemException e) {
                    e.printStackTrace();
                }
            }
        });
        Runtime.getRuntime().addShutdownHook(thread);
    }

    private synchronized static void checkHook() {
        if (kettleVFS == null)
            kettleVFS = new KettleVFS();
    }

    public static FileObject getFileObject(String vfsFilename) throws IOException {
        checkHook();

        try {
            FileSystemManager fsManager = VFS.getManager();

            // We have one problem with VFS: if the file is in a subdirectory of the current one: somedir/somefile
            // In that case, VFS doesn't parse the file correctly.
            // We need to put file: in front of it to make it work.
            // However, how are we going to verify this?
            // 
            // We are going to see if the filename starts with one of the known protocols like file: zip: ram: smb: jar: etc.
            // If not, we are going to assume it's a file.
            //
            boolean relativeFilename = true;
            String[] schemes = VFS.getManager().getSchemes();
            for (int i = 0; i < schemes.length && relativeFilename; i++) {
                if (vfsFilename.startsWith(schemes[i] + ":"))
                    relativeFilename = false;
            }

            String filename;
            if (vfsFilename.startsWith("\\\\")) {
                File file = new File(vfsFilename);
                filename = file.toURI().toString();
            } else {
                if (relativeFilename) {
                    File file = new File(vfsFilename);
                    filename = file.getAbsolutePath();
                } else {
                    filename = vfsFilename;
                }
            }

            FileObject fileObject = fsManager.resolveFile(filename);

            return fileObject;
        } catch (IOException e) {
            throw new IOException(
                    "Unable to get VFS File object for filename '" + vfsFilename + "' : " + e.toString());
        }
    }

    /**
     * Read a text file (like an XML document).  WARNING DO NOT USE FOR DATA FILES.
     * 
     * @param vfsFilename the filename or URL to read from
     * @param charSetName the character set of the string (UTF-8, ISO8859-1, etc)
     * @return The content of the file as a String
     * @throws IOException
     */
    public static String getTextFileContent(String vfsFilename, String charSetName) throws IOException {
        InputStream inputStream = getInputStream(vfsFilename);
        InputStreamReader reader = new InputStreamReader(inputStream, charSetName);
        int c;
        StringBuffer stringBuffer = new StringBuffer();
        while ((c = reader.read()) != -1)
            stringBuffer.append((char) c);
        reader.close();
        inputStream.close();

        return stringBuffer.toString();
    }

    public static boolean fileExists(String vfsFilename) throws IOException {
        FileObject fileObject = getFileObject(vfsFilename);
        return fileObject.exists();
    }

    public static InputStream getInputStream(FileObject fileObject) throws FileSystemException {
        FileContent content = fileObject.getContent();
        return content.getInputStream();
    }

    public static InputStream getInputStream(String vfsFilename) throws IOException {
        FileObject fileObject = getFileObject(vfsFilename);
        return getInputStream(fileObject);
    }

    public static OutputStream getOutputStream(FileObject fileObject, boolean append) throws IOException {
        FileObject parent = fileObject.getParent();
        if (parent != null) {
            if (!parent.exists()) {
                throw new IOException(
                        Messages.getString("KettleVFS.Exception.ParentDirectoryDoesNotExist", getFilename(parent)));
            }
        }
        try {
            fileObject.createFile();
            FileContent content = fileObject.getContent();
            return content.getOutputStream(append);
        } catch (FileSystemException e) {
            // Perhaps if it's a local file, we can retry using the standard
            // File object.  This is because on Windows there is a bug in VFS.
            //
            if (fileObject instanceof LocalFile) {
                try {
                    String filename = getFilename(fileObject);
                    return new FileOutputStream(new File(filename), append);
                } catch (Exception e2) {
                    throw e; // throw the original exception: hide the retry.
                }
            } else {
                throw e;
            }
        }
    }

    public static OutputStream getOutputStream(String vfsFilename, boolean append) throws IOException {
        FileObject fileObject = getFileObject(vfsFilename);
        return getOutputStream(fileObject, append);
    }

    public static String getFilename(FileObject fileObject) {
        FileName fileName = fileObject.getName();
        String root = fileName.getRootURI();
        if (!root.startsWith("file:"))
            return fileName.getURI(); // nothing we can do about non-normal files.
        if (root.endsWith(":/")) // Windows
        {
            root = root.substring(8, 10);
        } else // *nix & OSX
        {
            root = "";
        }
        String fileString = root + fileName.getPath();
        if (!"/".equals(Const.FILE_SEPARATOR)) {
            fileString = Const.replace(fileString, "/", Const.FILE_SEPARATOR);
        }
        return fileString;
    }

    public static FileObject createTempFile(String prefix, String suffix, String directory) throws IOException {
        FileObject fileObject;
        do {
            // Build temporary file name using UUID to ensure uniqueness. Old mechanism would fail using Sort Rows (for example)
            // when there multiple nodes with multiple JVMs on each node. In this case, the temp file names would end up being
            // duplicated which would cause the sort to fail.
            String filename = new StringBuffer(50).append(directory).append('/').append(prefix).append('_')
                    .append(UUIDUtil.getUUIDAsString()).append(suffix).toString();
            fileObject = getFileObject(filename);
        } while (fileObject.exists());
        return fileObject;
    }

    public static Comparator<FileObject> getComparator() {
        return new Comparator<FileObject>() {
            public int compare(FileObject o1, FileObject o2) {
                String filename1 = getFilename(o1);
                String filename2 = getFilename(o2);
                return filename1.compareTo(filename2);
            }
        };
    }

    /**
     * Get a FileInputStream for a local file.  Local files can be read with NIO.
     * 
     * @param fileObject
     * @return a FileInputStream
     * @throws IOException
     */
    public static FileInputStream getFileInputStream(FileObject fileObject) throws IOException {

        if (!(fileObject instanceof LocalFile)) {
            // We can only use NIO on local files at the moment, so that's what we limit ourselves to.
            //
            throw new IOException(Messages.getString("FixedInput.Log.OnlyLocalFilesAreSupported"));
        }

        return (FileInputStream) ((LocalFile) fileObject).getInputStream();
    }

}