All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.io.IO Maven / Gradle / Ivy

/*
 * $Id: IO.java 12345 2004-08-22 04:56:09Z fielding $
 *
 * Copyright 1997-2004 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.io;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UTFDataFormatException;
import java.io.Writer;
import java.util.Collection;

/**
 * Contains I/O utility functions.
 *
 * @version $Revision: 1.15 $, $Date: 2004-08-22 06:56:09 +0200 (Sun, 22 Aug 2004) $
 * @author tripod
 * @since antbear
 * @audience wad
 */
public class IO {

    /** default log category */
    private static final Logger log = LoggerFactory.getLogger(IO.class);

    /** temporary directory name */
    private static final String TEMPDIR = "tmp";

    /** Temporary directory folder */
    private static File tempDir;

    /** the current work directory file */
    private static File cwd;

    /**
     * Spools data from an InputStream into an
     * OutputStream. Please note, that both, input and output
     * stream, remain open after the spooling.
     *
     * @param in
     *            input stream
     * @param out
     *            output stream
     *
     * @return number of bytes transmitted
     *
     * @throws IOException
     *             if an I/O error occurs
     */
    public static int spool(InputStream in, OutputStream out)
            throws IOException {

        byte[] buffer = new byte[8192];
        int rd, total = 0;
        while ((rd = in.read(buffer)) > 0) {
            out.write(buffer, 0, rd);
            total += rd;
        }
        return total;
    }

    /**
     * Spools data from an InputStream into an
     * byte buffer. either until the buffer is full or the EOF is reached.
     *
     * @param in
     *            input stream
     * @param buffer
     *            output buffer
     *
     * @return number of bytes transmitted
     *
     * @throws IOException
     *             if an I/O error occurs
     */
    public static int spool(InputStream in, byte[] buffer)
            throws IOException {
        int rd, total = 0;
        while (total= 0) {
            total += rd;
        }
        return total;
    }

    /**
     * Spools characters from an Reader into an
     * Writer. Please note, that both, reader and writer remain
     * open after the spooling.
     *
     * @param in
     *            input Reader
     * @param out
     *            output Writer
     *
     * @return number of characters transmitted
     *
     * @throws IOException
     *             if an I/O error occurs
     */
    public static int spool(Reader in, Writer out) throws IOException {

        char[] buffer = new char[8192];
        int rd, total = 0;
        while (in.ready() && (rd = in.read(buffer)) > 0) {
            out.write(buffer, 0, rd);
            total += rd;
        }
        return total;
    }

    /**
     * Spools data from an InputStream into an
     * OutputStream. Please note, that both, input and output
     * stream, remain open after the spooling. This method only transfers
     * num bytes or less.
     *
     * @param in
     *            input stream
     * @param out
     *            output stream
     *
     * @return number of bytes transmitted
     *
     * @throws IOException
     *             if an I/O error occurs
     */
    public static int spool(InputStream in, OutputStream out, int num)
        throws IOException {

        byte[] buffer = new byte[8192];
        int rd = 0, total = num;
        while (num > 0 && rd >= 0) {
            if ((rd = in.read(buffer, 0, num > buffer.length
                    ? buffer.length
                    : num)) > 0) {
                out.write(buffer, 0, rd);
                num -= rd;
            }
        }
        return total - num;
    }

    /**
     * Closes the InputStream in if not
     * null and ignores a potential IOException thrown
     * from closing the stream.
     *
     * @param in The InputStream to close. This may be
     *          null.
     */
    public static void tryClose(InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (IOException ioe) {
                // ignored by intent
            }
        }
    }

    /**
     * Closes the OutputStream out if not
     * null and ignores a potential IOException thrown
     * from closing the stream.
     *
     * @param out The OutputStream to close. This may be
     *          null.
     */
    public static void tryClose(OutputStream out) {
        if (out != null) {
            try {
                out.close();
            } catch (IOException ioe) {
                // ignored by intent
            }
        }
    }

    /**
     * Closes the Reader out if not
     * null and ignores a potential IOException thrown
     * from closing the reader.
     *
     * @param reader The Reader to close. This may be
     *          null.
     */
    public static void tryClose(Reader reader) {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException ioe) {
                // ignored by intent
            }
        }
    }

    /**
     * Closes the Writer in if not
     * null and ignores a potential IOException thrown
     * from closing the writer.
     *
     * @param writer The Writer to close. This may be
     *          null.
     */
    public static void tryClose(Writer writer) {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException ioe) {
                // ignored by intent
            }
        }
    }

    /**
     * Renames a file to another. If the renaming does not work, it copies the
     * content and tries to delete the source file.
     *
     * @param src
     *            the source file
     * @param dst
     *            the destination file
     *
     * @return true if the renaming was successful and the file
     *         at leas exists at the new location; false if the
     *         renaming failed. in this case, the original file still exists.
     */
    public static boolean rename0(File src, File dst) {
        // try to delete dst file
        if (dst.exists()) {
            dst.delete();
        }

        // ensure that parent directory exists (bug #8942)
        dst.getParentFile().mkdirs();

        // try to rename
        if (!src.renameTo(dst)) {
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream(src);
                out = new FileOutputStream(dst);
                spool(in, out);
            } catch (IOException e) {
                return false;
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
            }

            // try to delete source
            if (!src.delete()) {
                // at least, truncate it
                try {
                    new FileOutputStream(src).close();
                } catch (IOException e) {
                    // ignore
                }
                // and mark for deletion
                src.deleteOnExit();
            }
        }
        return true;
    }

    /**
     * Read a UTF encoded string from an input stream.
     *
     * @param in
     *            input stream
     * @return string
     * @throws UTFDataFormatException
     *             if the input stream contains an invalid combination of bytes
     * @throws IOException
     *             if an I/O error occurs
     */
    public static String readUTF(InputStream in) throws UTFDataFormatException,
        IOException {

        CharArrayWriter out = new CharArrayWriter(256);
        int c, char2, char3;

        while (true) {
            if ((c = in.read()) == -1) {
                break;
            }
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    out.write(c);
                    break;
                case 12:
                case 13:
                    /* 110x xxxx 10xx xxxx */
                    if ((char2 = in.read()) == -1) {
                        throw new UTFDataFormatException(
                            "unexpected end of input");
                    }
                    if ((char2 & 0xC0) != 0x80)
                        throw new UTFDataFormatException(
                            "consecutive byte should have bit 6 cleared");
                    out.write((((c & 0x1F) << 6) | (char2 & 0x3F)));
                    break;
                case 14:
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    if ((char2 = in.read()) == -1) {
                        throw new UTFDataFormatException(
                            "unexpected end of input");
                    }
                    if ((char3 = in.read()) == -1) {
                        throw new UTFDataFormatException(
                            "unexpected end of input");
                    }
                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw new UTFDataFormatException(
                            "consecutive byte should have bit 6 cleared");

                    out
                        .write((((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F))));
                    break;
                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw new UTFDataFormatException("invalid UTF-8 byte");
            }
        }
        return out.toString();
    }

    /**
     * Initialization of CQ3 home. Either this method or
     * {@link #setTempDir(File)} must be called before methods inside {@link IO}
     * may be used.
     *
     * @param cwd directory to use as current work directory
     * @audience core
     */
    public static void setCWD(File cwd) {
        if (IO.cwd == null) {
            IO.cwd = cwd;
            setTempDir(IO.getAbsoluteFile(TEMPDIR));
        } else {
            Exception e = new Exception("Caller stack trace");
            log.warn("Attempt to initialize IO twice", e);
        }
    }

    /**
     * Initialization of CQ3 home. Either this method or
     * {@link #setTempDir(File)} must be called before methods inside {@link IO}
     * may be used.
     *
     * @param cq3Home directory to use as CQ3 home.
     * @deprecated use {@link IO#setCWD(File)} instead.
     */
    public static void setCQ3Home(File cq3Home) {
        setCWD(cq3Home);
    }

    /**
     * Initialization of temporary directory when used as a separate component.
     * This class has some functionality based on a temporary directory to use
     * and in order to use that functionality without having an engine at hand
     * makes this method necessary.
     *
     * @param tempDir
     *            temporary directory to use
     * @audience core
     */
    public static void setTempDir(File tempDir) {
        if (IO.tempDir == null) {
            IO.tempDir = tempDir;
            IO.tempDir.mkdirs();
        } else {
            Exception e = new Exception("Caller stack trace");
            log.warn("Attempt to initialize IO twice", e);
        }
    }

    /**
     * Return the temporary directory.
     *
     * @return the temporary directory.
     */
    public static File getTempDir() {
        if (tempDir == null) {
            throw new InternalError("IO has not been initialized");
        }
        return tempDir;
    }

    /**
     * Returns the path of the application home directory
     *
     * @return the path of the application home directory
     * @deprecated use {@link IO#getCWD()}.{@link File#getPath() getPath()} instead.
     */
    public static String getAppHome() {
        return getCWD().getPath();
    }

    /**
     * Returns the directory of the application home
     *
     * @return the directory of the application home
     * @deprecated  use {@link IO#getCWD()} instead.
     */
    public static File getAppHomeDirectory() {
        return getCWD();
    }

    /**
     * Returns the directory of the application home
     *
     * @return the directory of the application home
     */
    public static File getCWD() {
        if (cwd == null) {
            throw new InternalError("IO has not been initialized");
        }
        return cwd;
    }

    /**
     * Normalize a path, converting slashes to platform dependent separators and
     * removing dots.
     *
     * @return canonical file path or null if the path cannot be
     *         normalized
     */
    public static File getCanonicalFile(String path) {
        try {
            path = path.replace('/', File.separatorChar);
            return new File(path).getCanonicalFile();
        } catch (IOException e) {
            log.warn("Unable to canonicalize path: {}", path);
            return null;
        }
    }

    /**
     * Return a flag indicating whether a file is the parent of another file
     *
     * @param parent
     *            parent file
     * @param child
     *            child file
     * @return true if parent is parent of child, otherwise
     *         false
     */
    public static boolean isParent(File parent, File child) {
        if (!parent.isAbsolute() || !child.isAbsolute()) {
            throw new IllegalArgumentException(
                "parent and child must be absolute");
        }

        while (child != null) {
            if (parent.equals(child)) {
                return true;
            }
            child = child.getParentFile();
        }
        return false;
    }

    /**
     * Create a temporary file and add it to the given tracker
     *
     * @param tracker collection that is use to record the generated temp file.
     * @return a new temporary file.
     * @throws IOException if an I/O error occurs
     */
    public static File createTempFile(Collection tracker)
        throws IOException {

        return createTempFile(tracker, "cq3", "");
    }

    /**
     * Create a temporary file and add it to the given tracker
     *
     * @param tracker collection that is use to record the generated temp file.
     * @param prefix the prefix for the temporary file
     * @param suffix the suffix for the temporary file
     *
     * @return a new temp file
     * @throws IOException if an I/O error occurs
     */
    public static File createTempFile(Collection tracker, String prefix,
        String suffix) throws IOException {

        if (tracker == null) {
            throw new IllegalArgumentException("context == null");
        }

        File tempFile = File.createTempFile(prefix, suffix, getTempDir());
        tracker.add(tempFile);
        return tempFile;
    }

    /**
     * Create a temporary file in the generic tmp directory.
     *
     * @return a new temporary file
     * @throws IOException if an I/O error occurs
     */
    public static File createTempFile() throws IOException {
        return createTempFile("cq3", "");
    }

    /**
     * Create a temporary file in the generic tmp directory.
     *
     * @param prefix
     *            the prefix for the file
     * @param suffix
     *            the suffix for the file
     *
     * @return a new temporary file
     *
     * @throws IllegalArgumentException
     *             If the prefix argument contains fewer than three characters
     * @throws IOException
     *             If a file could not be created
     */
    public static File createTempFile(String prefix, String suffix)
        throws IOException {

        return File.createTempFile(prefix, suffix, getTempDir());
    }

    /**
     * returns an absolute path regarding the cq3 home as cwd. If the
     * path already is absolute, this string itself is returned.
     *
     * @param path
     *            the relative path
     *
     * @return an absolute path
     */
    public static String getAbsolutePath(String path) {
        return getAbsoluteFile(path).getPath();
    }

    /**
     * returns an absolute file regarding the cq3 home as cwd.
     *
     * @param path
     *            the relative path
     *
     * @return a new file pointing to the absolute path
     */
    public static File getAbsoluteFile(String path) {
        if (path == null) {
            path = "";
        }
        path = path.replace('/', File.separatorChar);

        File file = new File(path);
        if (!file.isAbsolute()) {
            file = new File(getCWD(), path);
        }
        return file;
    }

    /**
     * Renames a file to another. If the renaming does not work, it copies the
     * content and tries to delete the source file.
     *
     * @param src
     *            the source file
     * @param dst
     *            the destination file
     *
     * @return true if the renaming was successful and the file
     *         at leas exists at the new location; false if the
     *         renaming failed. in this case, the original file still exists.
     */
    public static boolean rename(File src, File dst) {
        // try to delete dst file
        if (dst.exists()) {
            if (!dst.delete()) {
                log
                    .warn(
                        "Error while deleting destination file {}. might be in use.",
                        dst.getPath());
            }
        }
        // ensure that parent directory exists (bug #8942)
        dst.getParentFile().mkdirs();

        // try to rename
        if (!src.renameTo(dst)) {
            log.warn("Error while renaming {} to {}. Copying content.", src
                .getPath(), dst.getPath());
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream(src);
                out = new FileOutputStream(dst);
                spool(in, out);
            } catch (IOException e) {
                log.error("Error while spooling {} to {}: {}",
                    new Object[]{ src.getPath(), dst.getPath(), e.getMessage() });
                return false;
                //throw new IOException("Error while spooling "+src.getPath()+" to "+dst.getPath()+": " + e.getMessage());
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        //ignore
                    }
                }
            }

            // try to delete source
            if (!src.delete()) {
                log.warn("Error while deleting src after spool {}", src
                    .getPath());

                // at least, truncate it
                try {
                    new FileOutputStream(src).close();
                } catch (IOException e) {
                    // ignore
                }
                // and mark for deletion
                src.deleteOnExit();
            }
        }
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy