Project: i18n
/**
 * Copyright (C) 2011 Ovea <[email protected]
 * 
 * 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 com.ovea.i18n.util; 
 
import java.io.*; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLConnection; 
import java.nio.channels.Channels; 
import java.nio.channels.FileChannel; 
import java.nio.channels.WritableByteChannel; 
import java.util.Arrays; 
 
public abstract class Resource { 
 
    private Resource() { 
    } 
 
    public abstract URL toURL(); 
 
    public abstract File toFile(); 
 
    public abstract InputStream read(); 
 
    public abstract OutputStream write(); 
 
    public abstract String readAsString(); 
 
    public abstract byte[] readAsBytes(); 
 
    public abstract boolean isFile(); 
 
    public abstract boolean exist(); 
 
    @Override 
    public abstract String toString(); 
 
    @Override 
    public abstract boolean equals(Object obj); 
 
    @Override 
    public abstract int hashCode(); 
 
    public void transferTo(File dest) { 
        dest.getParentFile().mkdirs(); 
        if (isFile()) { 
            try { 
                transfer(toFile(), new RandomAccessFile(dest, "rw").getChannel()); 
            } catch (FileNotFoundException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } else { 
            try { 
                transfer(read(), new FileOutputStream(dest)); 
            } catch (FileNotFoundException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
    } 
 
    /**
     * classpath:<path> 
     * <br> 
     * file:<path> 
     * <br> 
     * http://... 
     */
 
    public static Resource from(String pattern) { 
        if (pattern == null
            throw new IllegalArgumentException("Missing parameter"); 
        if (pattern.startsWith("classpath:")) 
            return from(Thread.currentThread().getContextClassLoader(), pattern.substring(10)); 
        if (pattern.startsWith("file:")) 
            return new FileResource(new File(pattern.substring(5))); 
        try { 
            return new UrlResource(new URL(pattern)); 
        } catch (MalformedURLException e) { 
            throw new IllegalArgumentException("Invalid resource " + pattern + " : " + e.getMessage(), e); 
        } 
    } 
 
    public static Resource from(ClassLoader classloader, String pattern) { 
        if (pattern == null
            throw new IllegalArgumentException("Missing parameter"); 
        if (pattern.startsWith("/")) 
            pattern = pattern.substring(1); 
        return new ClassPathResource(classloader, pattern); 
    } 
 
    public static Resource from(File file) { 
        return new FileResource(file); 
    } 
 
    public static Resource from(URL url) { 
        return new UrlResource(url); 
    } 
 
    public static Resource fromData(String data) { 
        return new ByteResource(data.getBytes()); 
    } 
 
    public static Resource fromData(byte[] data) { 
        return new ByteResource(data); 
    } 
 
    private static class ByteResource extends ReadOnlyBufferBasedResource { 
        private final byte[] data; 
 
        private ByteResource(byte[] data) { 
            this.data = data; 
        } 
 
        @Override 
        public InputStream read() { 
            try { 
                return new ByteArrayInputStream(data); 
            } catch (Exception e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
        @Override 
        public boolean equals(Object o) { 
            if (this == o) return true
            if (o == null || getClass() != o.getClass()) return false
            ByteResource that = (ByteResource) o; 
            return Arrays.equals(data, that.data); 
        } 
 
        @Override 
        public int hashCode() { 
            return Arrays.hashCode(data); 
        } 
 
    } 
 
    private static final class ClassPathResource extends UrlBasedResource { 
        private final String path; 
        private final ClassLoader classloader; 
 
        private ClassPathResource(ClassLoader classloader, String path) { 
            this.path = path; 
            this.classloader = classloader; 
        } 
 
        @Override 
        public URL toURL() { 
            URL url = classloader.getResource(path); 
            if (url == null) { 
                throw new ResourceException(this, path + " cannot be found on classpath"); 
            } 
            return url; 
        } 
 
        @Override 
        public String toString() { 
            return "classpath:" + path; 
        } 
 
        @Override 
        public boolean equals(Object o) { 
            if (this == o) return true
            if (o == null || getClass() != o.getClass()) return false
            ClassPathResource that = (ClassPathResource) o; 
            return path.equals(that.path); 
        } 
 
        @Override 
        public int hashCode() { 
            return path.hashCode(); 
        } 
 
        @Override 
        public boolean exist() { 
            return classloader.getResource(path) != null
        } 
    } 
 
    private static final class UrlResource extends UrlBasedResource { 
        private final URL url; 
 
        private UrlResource(URL url) { 
            this.url = url; 
        } 
 
        @Override 
        public URL toURL() { 
            return url; 
        } 
 
        @Override 
        public String toString() { 
            return url.toString(); 
        } 
 
        @Override 
        public boolean equals(Object o) { 
            if (this == o) return true
            if (o == null || getClass() != o.getClass()) return false
            UrlResource that = (UrlResource) o; 
            return url.equals(that.url); 
        } 
 
        @Override 
        public int hashCode() { 
            return url.hashCode(); 
        } 
 
        @Override 
        public boolean exist() { 
            InputStream is = null
            try { 
                is = toIS(url); 
                return true
            } catch (Exception e) { 
                return false
            } finally { 
                if (is != null) { 
                    try { 
                        is.close(); 
                    } catch (IOException ignored) { 
                    } 
                } 
            } 
        } 
    } 
 
    private static final class FileResource extends UrlBasedResource { 
        private final File file; 
 
        private FileResource(File file) { 
            this.file = file; 
        } 
 
        @Override 
        public URL toURL() { 
            try { 
                return file.toURI().toURL(); 
            } catch (Exception e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
        @Override 
        public String toString() { 
            return file.toString(); 
        } 
 
        @Override 
        public boolean equals(Object o) { 
            if (this == o) return true
            if (o == null || getClass() != o.getClass()) return false
            FileResource that = (FileResource) o; 
            return file.equals(that.file); 
        } 
 
        @Override 
        public int hashCode() { 
            return file.hashCode(); 
        } 
 
        @Override 
        public boolean exist() { 
            return file.exists(); 
        } 
    } 
 
    static abstract class UrlBasedResource extends Resource { 
        @Override 
        public final InputStream read() { 
            URL url = toURL(); 
            File file = Resource.urlToFile(url); 
            try { 
                if (file != null
                    return Channels.newInputStream(new RandomAccessFile(file, "r").getChannel()); 
                return toIS(url); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
        @Override 
        public final OutputStream write() { 
            URL url = toURL(); 
            File file = Resource.urlToFile(url); 
            try { 
                if (file != null) { 
                    return Channels.newOutputStream(new RandomAccessFile(file, "rw").getChannel()); 
                } 
                URLConnection connection = url.openConnection(); 
                connection.setUseCaches(false); 
                connection.connect(); 
                return connection.getOutputStream(); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
        @Override 
        public final File toFile() { 
            URL url = toURL(); 
            File file = Resource.urlToFile(url); 
            if (file == null
                throw new ResourceException(this"Unable to convert " + url + " to a file"); 
            return file; 
        } 
 
        @Override 
        public final String readAsString() { 
            return new String(readAsBytes()); 
        } 
 
        @Override 
        public final byte[] readAsBytes() { 
            URL url = toURL(); 
            File file = Resource.urlToFile(url); 
            try { 
                return file != null ? readBytes(file) : readBytes(url); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
 
        @Override 
        public final boolean isFile() { 
            try { 
                return Resource.urlToFile(toURL()) != null
            } catch (Exception e) { 
                return false
            } 
        } 
    } 
 
    static abstract class ReadOnlyBufferBasedResource extends Resource { 
        @Override 
        public final File toFile() { 
            throw new UnsupportedOperationException(); 
        } 
 
        @Override 
        public final String readAsString() { 
            return new String(readAsBytes()); 
        } 
 
        @Override 
        public byte[] readAsBytes() { 
            try { 
                return readBytes(read()); 
            } catch (IOException e) { 
                throw new ResourceException(this, e.getMessage(), e); 
            } 
        } 
 
        @Override 
        public final boolean isFile() { 
            return false
        } 
 
        @Override 
        public String toString() { 
            return "<data>"
        } 
 
        @Override 
        public final URL toURL() { 
            throw new UnsupportedOperationException(); 
        } 
 
        @Override 
        public final OutputStream write() { 
            throw new UnsupportedOperationException(); 
        } 
 
        @Override 
        public boolean exist() { 
            return true
        } 
    } 
 
    static byte[] readBytes(URL url) throws IOException { 
        return readBytes(toIS(url)); 
    } 
 
    static byte[] readBytes(File file) throws IOException { 
        FileChannel channel = null
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        transfer(file, Channels.newChannel(baos)); 
        return baos.toByteArray(); 
    } 
 
    static void transfer(File src, WritableByteChannel out) throws IOException { 
        FileChannel channel = null
        try { 
            channel = new RandomAccessFile(src, "r").getChannel(); 
            channel.transferTo(0, src.length(), out); 
        } finally { 
            if (channel != null) { 
                try { 
                    channel.close(); 
                } catch (IOException ignored) { 
                } 
            } 
            try { 
                out.close(); 
            } catch (IOException ignored) { 
            } 
        } 
    } 
 
    static InputStream toIS(URL url) throws IOException { 
        URLConnection connection = url.openConnection(); 
        connection.setUseCaches(false); 
        connection.connect(); 
        return connection.getInputStream(); 
    } 
 
    static byte[] readBytes(InputStream in) throws IOException { 
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        transfer(in, baos); 
        return baos.toByteArray(); 
    } 
 
    static void transfer(InputStream in, OutputStream out) throws IOException { 
        try { 
            byte[] buffer = new byte[8196]; 
            int c; 
            while ((c = in.read(buffer)) != -1
                out.write(buffer, 0, c); 
        } finally { 
            try { 
                in.close(); 
            } catch (IOException ignored) { 
            } 
            try { 
                out.close(); 
            } catch (IOException ignored) { 
            } 
        } 
    } 
 
    static File urlToFile(URL url) { 
        try { 
            return new File(url.toURI()); 
        } catch (Exception e) { 
            return null
        } 
    } 
}