Java tutorial
/* ========================================================================== * * 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(); } }