Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 1&1 Internet AG, http://www.1and1.org
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation; either version 2 of the License,
   * or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package net.sf.beezle.sushi.fs;
 
 
 import java.io.Writer;
 import java.net.URI;
 import java.util.List;

Abstraction from a file: something stored under a path that you can get an input stream from or output stream to. FileNode is the most prominent example of a node. The api is similar to java.world.File. It provides the same functionality, adds some methods useful for scripting, and removes some redundant methods to simplify api (in particular the constructors).

A node is identified by a URI, whose most important part is the path.

The path is a sequence of names separated by /, even for files on windows. It never starts or ends with a separator. It does not include the root, but it always includes the path of the base. A node with an empty path is called root node. That last part of the path is the name. Paths are always specified decoded, but URIs always contain encoded paths.

The base is a node this node is relative to. It's optional, a node without base is called absolute. It's use to simplify (shorten!) toString output.

Your application usually creates some "working-directory" nodes with world.node(URI). They will be used to create actual working nodes with node.join(path). The constructor of the respective node class is rarely used directly, it's used indirectly by the filesystem.

A node is immutable, except for its base.

Method names try to be short, but no abbreviations. Exceptions from this rule are mkfile, mkdir and mklink, because mkdir is a well-established name.

If an Implementation cannot (or does not want to) implement a method (e.g. move), it throws an UnsupportedOperationException.

As long as you stick to read operations, nodes are thread-save

 
 public abstract class Node {
     protected UnsupportedOperationException unsupported(String op) {
         return new UnsupportedOperationException(getURI() + ":" + op);
     }
 
     public abstract Root<?> getRoot();
 
     public Node getRootNode() {
         return getRoot().node(""null);
     }
 
     public World getWorld() {
         return getRoot().getFilesystem().getWorld();
     }

    
Creates a stream to read this node. Closing the stream more than once is ok, but reading from a closed stream is rejected by an exception
    public abstract InputStream createInputStream() throws IOException;
    public OutputStream createOutputStream() throws IOException {
        return createOutputStream(false);
    }
    public OutputStream createAppendStream() throws IOException {
        return createOutputStream(true);
    }

    
Create a stream to write this node. Closing the stream more than once is ok, but writing to a closed stream is rejected by an exception.
    public abstract OutputStream createOutputStream(boolean appendthrows IOException;

    
Lists child nodes of this node.

Returns:
List of child nodes or null if this node is a file. Note that returning null allows for optimizations because list() may be called on any existing node; otherwise, you'd have to inspect the resulting exception whether you called list on a file.
Throws:
ListException if this does not exist (in this case, cause is set to a FileNotFoundException), permission is denied, or another IO problem occurs.
    public abstract List<? extends Nodelist() throws ListException;

    
Fails if the directory already exists. Features define whether is operation is atomic.

Returns:
this
    public abstract Node mkdir() throws MkdirException;

    
Fails if the directory already exists. Features define whether this operation is atomic. This default implementation is not atomic.

Returns:
this
    public Node mkfile() throws MkfileException {
    	try {
			if (exists()) {
				throw new MkfileException(this);
			}
catch (IOException e) {
			throw new MkfileException(thise);
		}
		return this;
    }


    
Deletes this node, no matter if it's a file or a directory. If this is a link, the link is deleted, not the link target.

Returns:
this
    public abstract Node delete() throws DeleteException;

    
Moves this file or directory to dest. Throws an exception if this does not exist or if dest already exists. This method is a default implementation with copy and delete, derived classes should override it with a native implementation when available.

Returns:
dest
    public Node move(Node destthrows MoveException {
        try {
            dest.checkNotExists();
            copy(dest);
            delete();
        } catch (IOException e) {
            throw new MoveException(thisdest"move failed"e);
        }
        return dest;
    }
    //-- status methods

    
Throws an Exception if this node is not a file.
    public abstract long length() throws LengthException;

    

Returns:
true if the file exists, even if it's a dangling link
    public abstract boolean exists() throws ExistsException;
    public abstract boolean isFile() throws ExistsException;
    public abstract boolean isDirectory() throws ExistsException;
    public abstract boolean isLink() throws ExistsException;

    
Throws an exception is the file does not exist
    public abstract long getLastModified() throws GetLastModifiedException;
    public abstract void setLastModified(long millisthrows SetLastModifiedException;
    public abstract int getMode() throws IOException;
    public abstract void setMode(int modethrows IOException;
    public abstract int getUid() throws IOException;
    public abstract void setUid(int idthrows IOException;
    public abstract int getGid() throws IOException;
    public abstract void setGid(int idthrows IOException;
    //-- path functionality

    
Never starts or end with a slash or a drive; an empty string is the root path. The path is decoded, you have to encoded if you want to build an URI.
    public abstract String getPath();

    

Returns:
a normalized URI, not necessarily the URI this node was created from
    public URI getURI() {
        return URI.create(getRoot().getFilesystem().getScheme() + ":" + getRoot().getId() + encodePath(getPath()));
    }


    

Returns:
the last path segment (or an empty string for the root node
    public String getName() {
        String path;
        path = getPath();
        // ok for -1:
        return path.substring(path.lastIndexOf(.) + 1);
    }
    public String getExtension() {
        String name;
        int idx;
        name = getName();
        idx = name.lastIndexOf('.');
        if (idx <= 0 || idx == name.length() - 1) {
            return "";
        }
        return name.substring(idx + 1);
    }
    public abstract Node getParent();
    protected Node doGetParent() {
        String path;
        int idx;
        path = getPath();
        if ("".equals(path)) {
            return null;
        }
        idx = path.lastIndexOf(.);
        if (idx == -1) {
            return getRoot().node(""null);
        } else {
            return getRoot().node(path.substring(0, idx), null);
        }
    }
    public boolean hasDifferentAnchestor(Node anchestor) {
        Node parent;
        parent = getParent();
        if (parent == null) {
            return false;
        } else {
            return parent.hasAnchestor(anchestor);
        }
    }
    public boolean hasAnchestor(Node anchestor) {
        Node current;
        current = this;
        while (true) {
            if (current.equals(anchestor)) {
                return true;
            }
            current = current.getParent();
            if (current == null) {
                return false;
            }
        }
    }

    

Returns:
kind of a path, with . and .. where appropriate.
    public String getRelative(Node base) {
        String startfilepath;
        String destpath;
        String common;
        StringBuilder result;
        int len;
        int ups;
        int i;
        if (base.equals(this)) {
            return ".";
        }
        startfilepath = base.join("foo").getPath();
        destpath = getPath();
        common = Strings.getCommon(startfilepathdestpath);
        common = common.substring(0, common.lastIndexOf(.) + 1);  // ok for idx == -1
        len = common.length();
        startfilepath = startfilepath.substring(len);
        destpath = destpath.substring(len);
        result = new StringBuilder();
        ups = Strings.count(startfilepath.);
        for (i = 0; i < upsi++) {
            result.append("..").append(.);
        }
        result.append(destpath);
        return result.toString();
    }
    public abstract Node join(List<Stringpaths);
    protected Node doJoin(List<Stringpaths) {
        Root<?> root;
        Node result;
        root = getRoot();
        result = root.node(root.getFilesystem().join(getPath(), paths), null);
        return result;
    }
    public abstract Node join(String... names);
    public Node doJoin(String... names) {
        return join(Arrays.asList(names));
    }
    //-- input stream functionality
    public NodeReader createReader() throws IOException {
        return NodeReader.create(this);
    }
        return new ObjectInputStream(createInputStream());
    }

    
Reads all bytes of the node. Default implementation that works for all nodes: reads the file in chunks and builds the result in memory. Derived classes should override it if they can provide a more efficient implementation, e.g. by determining the length first if getting the length is cheap.

Returns:
Throws:
java.io.IOException
    public byte[] readBytes() throws IOException {
        InputStream src;
        byte[] result;
        Buffer buffer;
        src = createInputStream();
        buffer = getWorld().getBuffer();
        synchronized (buffer) {
            result = buffer.readBytes(src);
        }
        src.close();
        return result;
    }

    
Reads all chars of the node. Do not use this method on large files because it's memory consuming: the string is created from the byte array returned by readBytes.
    public String readString() throws IOException {
        return getWorld().getSettings().string(readBytes());
    }

    

Returns:
lines without tailing line separator
    public List<StringreadLines() throws IOException {
        return readLines(getWorld().getSettings().);
    }

    

Returns:
lines without tailing line separator
    public List<StringreadLines(LineFormat formatthrows IOException {
        return new LineReader(createReader(), format).collect();
    }
    public Object readObject() throws IOException {
        ObjectInputStream src;
        Object result;
        src = createObjectInputStream();
        try {
            result = src.readObject();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        src.close();
        return result;
    }
    public Document readXml() throws IOExceptionSAXException {
        Builder builder;
        builder = getWorld().getXml().getBuilder();
        synchronized (builder) {
            return builder.parse(this);
        }
    }
        InputStream in;
        Templates templates;
        in = createInputStream();
        templates = Serializer.templates(new SAXSource(new InputSource(in)));
        in.close();
        return templates.newTransformer();
    }
    public void xslt(Transformer transformerNode destthrows IOExceptionTransformerException {
        InputStream in;
        OutputStream out;
        in = createInputStream();
        out = dest.createOutputStream();
        transformer.transform(new StreamSource(in), new StreamResult(out));
        out.close();
        in.close();
    }
    //--
    public Node checkExists() throws IOException {
        if (!exists()) {
            throw new IOException("no such file or directory: " + this);
        }
        return this;
    }
    public Node checkNotExists() throws IOException {
        if (exists()) {
            throw new IOException("file or directory already exists: " + this);
        }
        return this;
    }
        if (isDirectory()) {
            return this;
        }
        if (exists()) {
            throw new FileNotFoundException("directory expected: " + this);
        } else {
            throw new FileNotFoundException("no such directory: " + this);
        }
    }
    public Node checkFile() throws ExistsExceptionFileNotFoundException {
        if (isFile()) {
            return this;
        }
        if (exists()) {
            throw new FileNotFoundException("file expected: " + this);
        } else {
            throw new FileNotFoundException("no such file: " + this);
        }
    }
    //--

    
Creates an absolute link. The signature of this method resembles the copy method.

Returns:
dest;
    public Node link(Node destthrows LinkException {
        if (!getClass().equals(dest.getClass())) {
            throw new IllegalArgumentException(this.getClass() + " vs " + dest.getClass());
        }
        try {
            checkExists();
        } catch (IOException e) {
            throw new LinkException(thise);
        }
        // TODO: getRoot() for ssh root ...
        dest.mklink(. + this.getPath());
        return dest;
    }

    
Creates this link, pointing to the specified path. Throws an exception if this already exists or if the parent does not exist; the target is not checked, it may be absolute or relative
    public abstract void mklink(String paththrows LinkException;

    
Returns the link target of this file or throws an exception.
    public abstract String readLink() throws ReadLinkException;

    
Throws an exception if this is not a link.
    public Node resolveLink() throws ReadLinkException {
        String path;
        path = readLink();
        if (path.startsWith(.)) {
            return getRoot().node(path.substring(1), null);
        } else {
            return getParent().join(path);
        }
    }
    public void copy(Node destthrows CopyException {
        try {
            if (isDirectory()) {
                dest.mkdirOpt();
                copyDirectory(dest);
            } else {
                copyFile(dest);
            }
        } catch (CopyException e) {
            throw e;
        } catch (IOException e) {
            throw new CopyException(thisdeste);
        }
    }

    
Overwrites dest if it already exists.

Returns:
dest
    public Node copyFile(Node destthrows CopyException {
        InputStream in;
        try {
            in = createInputStream();
            getWorld().getBuffer().copy(indest);
            in.close();
            return dest;
        } catch (IOException e) {
            throw new CopyException(thisdeste);
        }
    }

    
Convenience method for copy with filters below.

Returns:
list of files and directories created
    public List<NodecopyDirectory(Node destthrows CopyException {
        return copyDirectory(destgetWorld().filter().includeAll());
    }

    
Throws an exception is this or dest is not a directory. Overwrites existing files in dest.

Returns:
list of files and directories created
    public List<NodecopyDirectory(Node destdirFilter filterthrows CopyException {
        return new Copy(thisfilter).directory(destdir);
    }
    //-- diff
    public String diffDirectory(Node rightdirthrows IOException {
        return diffDirectory(rightdirfalse);
    }
    public String diffDirectory(Node rightdirboolean briefthrows IOException {
        return new Diff(brief).directory(thisrightdirgetWorld().filter().includeAll());
    }

    
cheap diff if you only need a yes/no answer
    public boolean diff(Node rightthrows IOException {
        return diff(rightnew Buffer(getWorld().getBuffer()));
    }

    
cheap diff if you only need a yes/no answer
    public boolean diff(Node rightBuffer rightBufferthrows IOException {
        InputStream leftSrc;
        InputStream rightSrc;
        Buffer leftBuffer;
        int leftChunk;
        int rightChunk;
        boolean[] leftEof;
        boolean[] rightEof;
        boolean result;
        leftBuffer = getWorld().getBuffer();
        leftSrc = createInputStream();
        leftEof = new boolean[] { false };
        rightSrc = right.createInputStream();
        rightEof = new boolean[] { false };
        result = false;
        do {
            leftChunk = leftEof[0] ? 0 : leftBuffer.fill(leftSrcleftEof);
            rightChunk = rightEof[0] ? 0 : rightBuffer.fill(rightSrcrightEof);
            if (leftChunk != rightChunk || leftBuffer.diff(rightBufferleftChunk)) {
                result = true;
                break;
            }
        } while (leftChunk > 0);
    	leftSrc.close();
    	rightSrc.close();
        return result;
    }
    //-- search for child nodes

    
uses default excludes
    public List<Nodefind(String... includesthrows IOException {
        return find(getWorld().filter().include(includes));
    }
    public Node findOne(String includethrows IOException {
        Node found;
        found = findOpt(include);
        if (found == null) {
            throw new FileNotFoundException(toString() + ": not found: " + include);
        }
        return found;
    }
    public Node findOpt(String includethrows IOException {
        List<Nodefound;
        found = find(include);
        switch (found.size()) {
        case 0:
            return null;
        case 1:
            return found.get(0);
        default:
            throw new IOException(toString() + ": ambiguous: " + include);
        }
    }
    public List<Nodefind(Filter filterthrows IOException {
        return filter.collect(this);
    }
    //--
    public Node deleteOpt() throws IOException {
        if (exists()) {
            delete();
        }
        return this;
    }
    public Node mkdirOpt() throws MkdirException {
        try {
			if (!isDirectory()) {
			    mkdir(); // fail here if it's a file!
			}
catch (ExistsException e) {
			throw new MkdirException(thise);
		}
        return this;
    }
    public Node mkdirsOpt() throws MkdirException {
        Node parent;
        try {
			if (!isDirectory()) {
			    parent = getParent();
			    if (parent != null) {
			        parent.mkdirsOpt();
			    }
			    mkdir(); // fail here if it's a file!
			}
catch (ExistsException e) {
			throw new MkdirException(thise);
		}
        return this;
    }
    public Node mkdirs() throws MkdirException {
    	try {
    		if (exists()) {
    			throw new MkdirException(this);
    		}
    	    return mkdirsOpt();
    	} catch (IOException e) {
    		throw new MkdirException(thise);
    	}
    }
    //-- output create functionality
    public NodeWriter createWriter() throws IOException {
        return createWriter(false);
    }
    public NodeWriter createAppender() throws IOException {
        return createWriter(true);
    }
    public NodeWriter createWriter(boolean appendthrows IOException {
        return NodeWriter.create(thisappend);
    }
        return new ObjectOutputStream(createOutputStream());
    }
    public Node writeBytes(byte ... bytesthrows IOException {
        return writeBytes(bytes, 0, bytes.lengthfalse);
    }
    public Node appendBytes(byte ... bytesthrows IOException {
        return writeBytes(bytes, 0, bytes.lengthtrue);
    }
    public Node writeBytes(byte[] bytesint ofsint lenboolean appendthrows IOException {
        OutputStream out;
        out = createOutputStream(append);
        out.write(bytesofslen);
        out.close();
        return this;
    }
    public Node writeChars(char ... charsthrows IOException {
        return writeChars(chars, 0, chars.lengthfalse);
    }
    public Node appendChars(char ... charsthrows IOException {
        return writeChars(chars, 0, chars.lengthtrue);
    }
    public Node writeChars(char[] charsint ofsint lenboolean appendthrows IOException {
        Writer out;
        out = createWriter(append);
        out.write(charsofslen);
        out.close();
        return this;
    }
    public Node writeString(String txtthrows IOException {
        Writer w;
        w = createWriter();
        w.write(txt);
        w.close();
        return this;
    }
    public Node appendString(String txtthrows IOException {
        Writer w;
        w = createAppender();
        w.write(txt);
        w.close();
        return this;
    }
    public Node writeStrings(String ... strthrows IOException {
        return writeStrings(Arrays.asList(str));
    }
    public Node writeStrings(List<Stringstringsthrows IOException {
        return strings(createWriter(), strings);
    }
    public Node appendStrings(String ... strthrows IOException {
        return appendStrings(Arrays.asList(str));
    }
    public Node appendStrings(List<Stringstringsthrows IOException {
        return strings(createAppender(), strings);
    }
    private Node strings(Writer destList<Stringstringsthrows IOException {
        for (String str : strings) {
            dest.write(str);
        }
        dest.close();
        return this;
    }

    

Parameters:
line without tailing line separator
    public Node writeLines(String ... linethrows IOException {
        return writeLines(Arrays.asList(line));
    }

    

Parameters:
lines without tailing line separator
    public Node writeLines(List<Stringlinesthrows IOException {
        return lines(createWriter(), lines);
    }

    

Parameters:
line without tailing line separator
    public Node appendLines(String ... linethrows IOException {
        return appendLines(Arrays.asList(line));
    }

    

Parameters:
lines without tailing line separator
    public Node appendLines(List<Stringlinesthrows IOException {
        return lines(createAppender(), lines);
    }

    

Parameters:
lines without tailing line separator
    private Node lines(Writer destList<Stringlinesthrows IOException {
        String separator;
        separator = getWorld().getSettings()..getSeparator();
        for (String line : lines) {
            dest.write(line);
            dest.write(separator);
        }
        dest.close();
        return this;
    }
    public Node writeObject(Serializable objthrows IOException {
        ObjectOutputStream out;
        out = createObjectOutputStream();
        out.writeObject(obj);
        out.close();
        return this;
    }
    public Node writeXml(org.w3c.dom.Node nodethrows IOException {
        getWorld().getXml().getSerializer().serialize(nodethis);
        return this;
    }
    //-- other
    public void gzip(Node destthrows IOException {
        InputStream in;
        OutputStream out;
        in = createInputStream();
        out = new GZIPOutputStream(dest.createOutputStream());
        getWorld().getBuffer().copy(inout);
        in.close();
        out.close();
    }
    public void gunzip(Node destthrows IOException {
        InputStream in;
        OutputStream out;
        in = new GZIPInputStream(createInputStream());
        out = dest.createOutputStream();
        getWorld().getBuffer().copy(inout);
        in.close();
        out.close();
    }
    public String sha() throws IOException {
        try {
            return digest("SHA");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    public String md5() throws IOException {
        try {
            return digest("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    public byte[] digestBytes(String namethrows IOExceptionNoSuchAlgorithmException {
        InputStream src;
        MessageDigest digest;
        Buffer buffer;
        src =  createInputStream();
        digest = MessageDigest.getInstance(name);
        synchronized (digest) {
            buffer = getWorld().getBuffer();
            synchronized (buffer) {
                buffer.digest(srcdigest);
            }
            src.close();
            return digest.digest();
        }
    }
    public String digest(String namethrows IOExceptionNoSuchAlgorithmException {
        return Strings.toHex(digestBytes(name));
    }
    //-- Object functionality
    @Override
    public boolean equals(Object obj) {
        Node node;
        if (obj == null || !getClass().equals(obj.getClass())) {
            return false;
        }
        node = (Nodeobj;
        if (!getPath().equals(node.getPath())) {
            return false;
        }
        return getRoot().equals(node.getRoot());
    }
    @Override
    public int hashCode() {
        return getPath().hashCode();
    }

    
Returns a String representation suitable for messages. CAUTION: don't use to convert to a string, use instead.
    @Override
    public String toString() {
        Node working;
        working = getWorld().getWorking();
        if (working == null || !getRoot().equals(working.getRoot())) {
            return getURI().toString();
        } else {
            if (hasAnchestor(working)) {
                return getRelative(working);
            } else {
                return . + getPath();
            }
        }
    }
    //--

    
TODO: is there a better way ... ?
    public static String encodePath(String path) {
        URI tmp;
        try {
            tmp = new URI("foo""host""/" + pathnull);
        } catch (URISyntaxException e) {
            throw new IllegalStateException(e);
        }
        return tmp.getRawPath().substring(1);
    }

    
TODO: is there a better way ... ?
    public static String decodePath(String path) {
        URI tmp;
        try {
            tmp = new URI("scheme://host/" + path);
        } catch (URISyntaxException e) {
            throw new IllegalStateException(e);
        }
        return tmp.getPath().substring(1);
    }
New to GrepCode? Check out our FAQ X