cziegeler 2003/02/07 03:21:00 Added: sourceresolve/src/java/org/apache/excalibur/source/impl FileSource.java Log: Adding FileSource from cocoon Revision Changes Path 1.1 avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/FileSource.java Index: FileSource.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software * itself, if and wherever such third-party acknowledgments * normally appear. * * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation" * must not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.excalibur.source.impl; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.util.ConcurrentModificationException; import java.util.Map; import org.apache.excalibur.source.ModifiableSource; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.impl.URLSource; /** * A {@link ModifiableSource} for 'file:/' system IDs. * * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a> * @version $Id: FileSource.java,v 1.1 2003/02/07 11:21:00 cziegeler Exp $ */ public class FileSource extends URLSource implements ModifiableSource { /** * Initialize a new object from a <code>URL</code>. * @param parameters This is optional */ public void init(URL url, Map parameters ) throws IOException { super.init( url, parameters ); if ( null == this.file ) { throw new IllegalArgumentException("Malformed url for a file source : " + url); } } /** * Get the associated file */ public File getFile() { return this.file; } /** * A file outputStream that will rename the temp file to the destination file upon close() * and discard the temp file upon cancel(). */ private class FileSourceOutputStream extends FileOutputStream { private File tmpFile; private boolean isClosed = false; private FileSource source; public FileSourceOutputStream(File tmpFile, FileSource source) throws IOException { super(tmpFile); this.tmpFile = tmpFile; this.source = source; } public void close() throws IOException { if (!this.isClosed) { super.close(); try { // Delete destination file if (this.source.getFile().exists()) { this.source.getFile().delete(); } // Rename temp file to destination file tmpFile.renameTo(this.source.getFile()); } finally { // Ensure temp file is deleted, ie lock is released. // If there was a failure above, written data is lost. if (tmpFile.exists()) { tmpFile.delete(); } this.isClosed = true; } } } public boolean canCancel() { return !this.isClosed; } public void cancel() throws Exception { if (this.isClosed) { throw new IllegalStateException("Cannot cancel : outputstrem is already closed"); } this.isClosed = true; super.close(); this.tmpFile.delete(); } public void finalize() { if (!this.isClosed && tmpFile.exists()) { // Something wrong happened while writing : delete temp file tmpFile.delete(); } } public FileSource getSource() { return this.source; } } /** * Does this source actually exist ? * * @return true if the resource exists. */ public boolean exists() { return this.file.exists(); } /** * Get an <code>InputStream</code> where raw bytes can be written to. * The signification of these bytes is implementation-dependent and * is not restricted to a serialized XML document. * * Get an output stream to write to this source. The output stream returned * actually writes to a temp file that replaces the real one on close. This * temp file is used as lock to forbid multiple simultaneous writes. The * real file is updated atomically when the output stream is closed. * * @return a stream to write to * @throws ConcurrentModificationException if another thread is currently * writing to this file. */ public OutputStream getOutputStream() throws IOException, SourceException { // Create a temp file. It will replace the right one when writing terminates, // and serve as a lock to prevent concurrent writes. File tmpFile = new File(this.file.getPath() + ".tmp"); // Ensure the directory exists tmpFile.getParentFile().mkdirs(); // Can we write the file ? if (this.file.exists() && !this.file.canWrite()) { throw new IOException("Cannot write to file " + this.file.getPath()); } // Check if it temp file already exists, meaning someone else currently writing if (!tmpFile.createNewFile()) { throw new ConcurrentModificationException("File " + this.file.getPath() + " is already being written by another thread"); } // Return a stream that will rename the temp file on close. return new FileSourceOutputStream(tmpFile, this); } /** * Can the data sent to an <code>OutputStream</code> returned by * {@link #getOutputStream()} be cancelled ? * * @return true if the stream can be cancelled */ public boolean canCancel(OutputStream stream) { if (stream instanceof FileSourceOutputStream) { FileSourceOutputStream fsos = (FileSourceOutputStream)stream; if (fsos.getSource() == this) { return fsos.canCancel(); } } // Not a valid stream for this source throw new IllegalArgumentException("The stream is not associated to this source"); } /** * Cancel the data sent to an <code>OutputStream</code> returned by * {@link #getOutputStream()}. * <p> * After cancel, the stream should no more be used. */ public void cancel(OutputStream stream) throws SourceException { if (stream instanceof FileSourceOutputStream) { FileSourceOutputStream fsos = (FileSourceOutputStream)stream; if (fsos.getSource() == this) { try { fsos.cancel(); } catch (Exception e) { throw new SourceException("Exception during cancel.", e); } return; } } // Not a valid stream for this source throw new IllegalArgumentException("The stream is not associated to this source"); } /** * Delete the source. */ public boolean delete() { return this.file.delete(); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]