com.adito.vfs.VFSOutputStream.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.vfs.VFSOutputStream.java

Source

/* ========================================================================== *
 * Copyright (C) 2004-2005 Pier Fumagalli <http://www.betaversion.org/~pier/> *
 *                            All rights reserved.                            *
 * ========================================================================== *
 *                                                                            *
 * 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.adito.vfs;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;

import com.adito.vfs.webdav.DAVException;
import com.adito.vfs.webdav.DAVListener;

/**
 * <p>A specialized {@link OutputStream} to write to {@link VFSResource}s.</p>
 * 
 * <p>When writing to this {@link OutputStream} the data will be written to
 * a temporary file. This temporary file will be moved to its final destination
 * (the original file identifying the resource) when the {@link #close()}
 * method is called.</p>
 *
 * <p>This specialized {@link OutputStream} never throws {@link IOException}s,
 * but rather relies on the unchecked {@link DAVException} to notify the
 * framework of the correct DAV errors.</p>
 *
 * @author <a href="http://www.betaversion.org/~pier/">Pier Fumagalli</a>
 */
public class VFSOutputStream extends OutputStream {

    final static Log log = LogFactory.getLog(VFSOutputStream.class);

    /** <p>The index of the temporary file.</p> */
    private static int tmpno = (int) (Math.random() * 100000);
    /** <p>The original resource {@link File}.</p> */
    private FileObject temporary = null;
    /** <p>The {@link OutputStream} of the temporary {@link File}. </p> */
    private OutputStream output = null;
    /** <p>The {@link VFSResource} associated with this instance. </p> */
    private VFSResource resource = null;

    /**
     * <p>Create a new {@link VFSOutputStream} instance.</p>
     */
    protected VFSOutputStream(VFSResource resource) {
        if (resource == null)
            throw new NullPointerException();
        this.resource = resource;

        try {
            if (resource instanceof FileObjectVFSResource) {
                // LDP - changed to get the parent using the FileObject rather than
                // the DAVResource beause we may have a null parent if the resource
                // is located at the root of a mount.
                this.temporary = resource.getFile().getParent();
                this.temporary = this.temporary.resolveFile(VFSResource.PREFIX + (tmpno++) + VFSResource.SUFFIX);
                this.output = this.temporary.getContent().getOutputStream();
            } else {
                throw new IOException("DAV resource is not a true file.");
            }
        } catch (IOException e) {
            String message = VfsUtils.maskSensitiveArguments("Unable to create temporary file. " + e.getMessage());
            throw new DAVException(507, message, resource);
        }
    }

    /**
     * <p>Rename the temporary {@link File} to the original one.</p>
     */
    protected void rename(FileObject temporary, FileObject original) throws IOException {
        if ((original.exists()) && (!original.delete())) {
            throw new IOException("Unable to delete original file");
        }
        temporary.moveTo(original);
    }

    /**
     * <p>Abort any data written to the temporary file and delete it.</p>
     */
    public void abort() {
        try {
            if (this.temporary.exists())
                this.temporary.delete();
        } catch (FileSystemException e) {
            log.error(e);
        }
        if (this.output != null)
            try {
                this.output.close();
            } catch (IOException exception) {
                // Swallow the IOException on close
            } finally {
                this.output = null;
            }
    }

    /**
     * <p>Close this {@link OutputStream} {@link #rename(File,File) renaming}
     * the temporary file to the {@link VFSResource#getFile() original} one.</p>
     */
    public void close() {
        if (this.output == null)
            return;
        try {
            /* What kind of event should this invocation trigger? */
            int event = ((FileObjectVFSResource) this.resource).getFile().exists() ? DAVListener.RESOURCE_MODIFIED
                    : DAVListener.RESOURCE_CREATED;

            /* Make sure that everything is closed and named properly */
            this.output.close();
            this.output = null;
            this.rename(this.temporary, ((FileObjectVFSResource) this.resource).getFile());

            /* Send notifications to all listeners of the repository */
            this.resource.getMount().getStore().getRepository().notify(this.resource, event);

        } catch (IOException e) {
            String message = "Error processing temporary file";
            throw new DAVException(507, message, e, this.resource);
        } finally {
            this.abort();
        }
    }

    /**
     * <p>Flush any unwritten data to the disk.</p>
     */
    public void flush() {
        if (this.output == null)
            throw new IllegalStateException("Closed");
        try {
            this.output.flush();
        } catch (IOException e) {
            this.abort();
            String message = "Unable to flush buffers";
            throw new DAVException(507, message, e, this.resource);
        }
    }

    /**
     * <p>Write data to this {@link OutputStream}.</p>
     */
    public void write(int b) {
        if (this.output == null)
            throw new IllegalStateException("Closed");
        try {
            this.output.write(b);
        } catch (IOException e) {
            this.abort();
            String message = "Unable to write data";
            throw new DAVException(507, message, e, this.resource);
        }
    }

    /**
     * <p>Write data to this {@link OutputStream}.</p>
     */
    public void write(byte b[]) {
        if (this.output == null)
            throw new IllegalStateException("Closed");
        try {
            this.output.write(b);
        } catch (IOException e) {
            this.abort();
            String message = "Unable to write data";
            throw new DAVException(507, message, e, this.resource);
        }
    }

    /**
     * <p>Write data to this {@link OutputStream}.</p>
     */
    public void write(byte b[], int o, int l) {
        if (this.output == null)
            throw new IllegalStateException("Closed");
        try {
            this.output.write(b, o, l);
        } catch (IOException e) {
            this.abort();
            String message = "Unable to write data";
            throw new DAVException(507, message, e, this.resource);
        }
    }

    /**
     * <p>Finalize this {@link VFSOutputStream} instance.</p>
     */
    public void finalize() {
        this.abort();
    }
}