org.dkpro.lab.Util.java Source code

Java tutorial

Introduction

Here is the source code for org.dkpro.lab.Util.java

Source

/*******************************************************************************
 * Copyright 2011
 * Ubiquitous Knowledge Processing (UKP) Lab
 * Technische Universitt Darmstadt
 *   
 * Licensed 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.dkpro.lab;

import java.io.Closeable;
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.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.FileExistsException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.apache.tools.ant.taskdefs.Execute;
import org.dkpro.lab.storage.StreamReader;
import org.dkpro.lab.task.Discriminable;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.util.MethodInvoker;

public class Util {
    private static Map<URL, File> urlFileCache;

    static {
        urlFileCache = new HashMap<URL, File>();
    }

    /**
     * Make the given URL available as a file. A temporary file is created and
     * deleted upon a regular shutdown of the JVM. If the parameter {@code
     * aCache} is {@code true}, the temporary file is remembered in a cache and
     * if a file is requested for the same URL at a later time, the same file is
     * returned again. If the previously created file has been deleted
     * meanwhile, it is recreated from the URL.
     *
     * @param aUrl
     *            the URL.
     * @param aCache
     *            use the cache or not.
     * @return a file created from the given URL.
     * @throws IOException
     *             if the URL cannot be accessed to (re)create the file.
     */
    public static synchronized File getUrlAsFile(URL aUrl, boolean aCache) throws IOException {
        // If the URL already points to a file, there is not really much to do.
        if ("file".equals(aUrl.getProtocol())) {
            try {
                return new File(aUrl.toURI());
            } catch (URISyntaxException e) {
                throw new IOException(e);
            }
        }

        // Lets see if we already have a file for this URL in our cache. Maybe
        // the file has been deleted meanwhile, so we also check if the file
        // actually still exists on disk.
        File file = urlFileCache.get(aUrl);
        if (!aCache || (file == null) || !file.exists()) {
            // Create a temporary file and try to preserve the file extension
            String suffix = ".temp";
            String name = new File(aUrl.getPath()).getName();
            int suffixSep = name.indexOf(".");
            if (suffixSep != -1) {
                suffix = name.substring(suffixSep + 1);
                name = name.substring(0, suffixSep);
            }

            // Get a temporary file which will be deleted when the JVM shuts
            // down.
            file = File.createTempFile(name, suffix);
            file.deleteOnExit();

            // Now copy the file from the URL to the file.
            shoveAndClose(aUrl.openStream(), new FileOutputStream(file));

            // Remember the file
            if (aCache) {
                urlFileCache.put(aUrl, file);
            }
        }

        return file;
    }

    /**
     * Makes the given stream available as a file. The created file is temporary
     * and deleted upon normal termination of the JVM. Still the file should be
     * deleted as soon as possible if it is no longer required. In case the JVM
     * crashes the file would not be deleted. The source stream is closed by
     * this operation in all cases.
     *
     * @param is
     *            the source.
     * @return the file.
     * @throws IOException
     *             in case of read or write problems.
     */
    public static File getStreamAsFile(final InputStream is) throws IOException {
        OutputStream os = null;
        try {
            final File f = File.createTempFile("lab_stream", "tmp");
            f.deleteOnExit();
            os = new FileOutputStream(f);
            shove(is, os);
            return f;
        } finally {
            close(os);
            close(is);
        }
    }

    /**
     * Shove data from an {@link InputStream} into an {@link OutputStream}.
     * Neither of the streams are closed after the operation.
     *
     * @param is the source.
     * @param os the target.
     * @throws IOException in case of read or write problems.
     */
    public static void shove(final InputStream is, final OutputStream os) throws IOException {
        byte[] buffer = new byte[65536];
        int read;
        while (true) {
            read = is.read(buffer);
            if (read == -1) {
                break;
            }
            os.write(buffer, 0, read);
        }
        os.flush();
    }

    /**
     * As {@link #shove(InputStream, OutputStream)} but the streams are closed
     * at the end of the process.
     *
     * @param is the input stream.
     * @param os the output stream.
     * @throws IOException in case of read or write problems.
     */
    public static void shoveAndClose(final InputStream is, final OutputStream os) throws IOException {
        try {
            shove(is, os);
        } finally {
            close(is);
            close(os);
        }
    }

    /**
     * Close a {@link Closeable} object. This method is best used in {@code finally}
     * sections.
     *
     * @param object the object to close.
     */
    public static void close(final Closeable object) {
        if (object == null) {
            return;
        }

        try {
            object.close();
        } catch (IOException e) {
            // Ignore exceptions happening while closing.
        }
    }

    /**
     * Recursively copy files and directories. The target must not exist before this operation.
     *
     * @param aIn the source.
     * @param aOut the target.
     * @throws IOException if something goes wrong.
     */
    public static void copy(File aIn, File aOut) throws IOException {
        copy(aIn, aOut, false);
    }

    /**
     * Recursively copy files and directories. The target must not exist before this operation.
     *
     * @param aIn the source.
     * @param aOut the target.
     * @throws IOException if something goes wrong.
     */
    public static void copy(File aIn, File aOut, boolean aLink) throws IOException {
        if (aOut.exists()) {
            throw new IOException("Target [" + aOut + "] already exists");
        }

        if (aIn.isDirectory()) {
            aOut.mkdirs();
            for (File child : aIn.listFiles()) {
                copy(child, new File(aOut, child.getName()), aLink);
            }
        } else {
            if (aLink) {
                createSymbolicLink(aIn, aOut);
            } else {
                copyFile(aIn, aOut);
            }
        }
    }

    public static void copyFile(final File aIn, final File aOut) throws IOException {
        FileUtils.copyFile(aIn, aOut);
    }

    public static String toString(final Object aObject) {
        if (aObject == null) {
            return "null";
        }

        if (aObject.getClass().isArray()) {
            return new ToStringBuilder(aObject, LAB_STYLE).append(aObject).toString();
        } else if (aObject instanceof Discriminable) {
            return toString(((Discriminable) aObject).getDiscriminatorValue());
        } else {
            return String.valueOf(aObject);
        }
    }

    public static <T extends StreamReader> T retrieveBinary(final File aFile, final T aConsumer) {
        InputStream is = null;
        try {
            is = new FileInputStream(aFile);
            if (aFile.getName().toLowerCase().endsWith(".gz")) {
                is = new GZIPInputStream(is);
            }
            aConsumer.read(is);
            return aConsumer;
        } catch (IOException e) {
            throw new DataAccessResourceFailureException(e.getMessage(), e);
        } finally {
            Util.close(is);
        }
    }

    public static boolean isWindows() {
        return (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0);
    }

    public static boolean isMac() {
        return (System.getProperty("os.name").toLowerCase().indexOf("mac") >= 0);
    }

    public static boolean isUnix() {
        String os = System.getProperty("os.name").toLowerCase();
        return (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0);
    }

    public static boolean isSymlinkSupported() {
        return isMac() || isUnix();
    }

    public static void createSymbolicLink(File aSource, File aTarget) throws IOException {
        if (aTarget.exists()) {
            throw new FileExistsException(aTarget);
        }

        File parentDir = aTarget.getAbsoluteFile().getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            FileUtils.forceMkdir(parentDir);
        }

        // Try Java 7 methods
        try {
            Object fromPath = MethodUtils.invokeExactMethod(aSource, "toPath", new Object[0]);
            Object toPath = MethodUtils.invokeExactMethod(aTarget, "toPath", new Object[0]);
            Object options = Array.newInstance(Class.forName("java.nio.file.attribute.FileAttribute"), 0);
            MethodInvoker inv = new MethodInvoker();
            inv.setStaticMethod("java.nio.file.Files.createSymbolicLink");
            inv.setArguments(new Object[] { toPath, fromPath, options });
            inv.prepare();
            inv.invoke();
            return;
        } catch (ClassNotFoundException e) {
            // Ignore
        } catch (NoSuchMethodException e) {
            // Ignore
        } catch (IllegalAccessException e) {
            // Ignore
        } catch (InvocationTargetException e) {
            if ("java.nio.file.FileAlreadyExistsException".equals(e.getTargetException().getClass().getName())) {
                throw new FileExistsException(aTarget);
            }
        }

        // If the Java 7 stuff is not available, fall back to Runtime.exec
        String[] cmdline = { "ln", "-s", aSource.getAbsolutePath(), aTarget.getAbsolutePath() };
        Execute exe = new Execute();
        exe.setVMLauncher(false);
        exe.setCommandline(cmdline);
        exe.execute();
        if (exe.isFailure()) {
            throw new IOException("Unable to create symlink from [" + aSource + "] to [" + aTarget + "]");
        }
    }

    public static final ToStringStyle LAB_STYLE = new LabToStringStyle();

    /**
      * <p>Have to use a custom style here since Apache Commons Lang uses curly braces for arrays
      * and we traditionally use square brackets as is used in Java Collections toString() methods.
      * </p>
      */
    private static final class LabToStringStyle extends ToStringStyle {

        private static final long serialVersionUID = 1L;

        private LabToStringStyle() {
            super();
            setUseClassName(false);
            setUseIdentityHashCode(false);
            setUseFieldNames(false);
            setContentStart("");
            setContentEnd("");
            setArrayStart("[");
            setArrayEnd("]");
            setArraySeparator(", ");
        }

        private Object readResolve() {
            return Util.LAB_STYLE;
        }
    }

    public static String getComprehensiveMessage(Throwable aThrowable) {
        StringBuilder sb = new StringBuilder();
        getComprehensiveMessage(sb, aThrowable, 0);
        return sb.toString();
    }

    private static void getComprehensiveMessage(StringBuilder aSb, Throwable aThrowable, int aLevel) {
        aSb.append(aThrowable.getMessage());
        Throwable cause = ExceptionUtils.getCause(aThrowable);
        if (cause != null && cause != aThrowable) {
            aSb.append('\n');
            for (int i = 0; i < aLevel; i++) {
                aSb.append("  ");
            }
            getComprehensiveMessage(aSb, cause, aLevel + 1);
        }
    }
}