You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2002/02/28 19:00:50 UTC

cvs commit: xml-cocoon2/src/java/org/apache/cocoon/environment WriteableSource.java

sylvain     02/02/28 10:00:50

  Modified:    src/java/org/apache/cocoon/components/source
                        AbstractStreamWriteableSource.java FileSource.java
               src/java/org/apache/cocoon/environment WriteableSource.java
  Log:
  Add cancel methods on WriteableSource and FileSource
  
  Revision  Changes    Path
  1.2       +135 -26   xml-cocoon2/src/java/org/apache/cocoon/components/source/AbstractStreamWriteableSource.java
  
  Index: AbstractStreamWriteableSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/source/AbstractStreamWriteableSource.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractStreamWriteableSource.java	22 Feb 2002 23:25:18 -0000	1.1
  +++ AbstractStreamWriteableSource.java	28 Feb 2002 18:00:50 -0000	1.2
  @@ -85,7 +85,7 @@
    * <code>getOutputStream()</code>.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version $Id: AbstractStreamWriteableSource.java,v 1.1 2002/02/22 23:25:18 sylvain Exp $
  + * @version $Id: AbstractStreamWriteableSource.java,v 1.2 2002/02/28 18:00:50 sylvain Exp $
    */
   
   public abstract class AbstractStreamWriteableSource extends AbstractStreamSource implements WriteableSource {
  @@ -93,52 +93,161 @@
       protected AbstractStreamWriteableSource(ComponentManager manager) {
           super(manager);
       }
  +    
  +    /**
  +     * Checks if the <code>OutputStream</code> under <code>handler</code> can be cancelled.
  +     *
  +     * @see #canCancel(OutputStream)
  +     */
  +    public boolean canCancel(ContentHandler handler) {
  +        if (handler instanceof WritingPipe) {
  +            WritingPipe pipe = (WritingPipe)handler;
  +            if (pipe.getSource() == this) {
  +                return pipe.canCancel();
  +            }
  +        }
  +
  +        // Not a valid handler for this source
  +        throw new IllegalArgumentException("The handler is not associated to this source");
  +    }
  +
  +    /**
  +     * Always return <code>false</code>. To be redefined by implementations that support
  +     * <code>cancel()</code>.
  +     */
  +    public boolean canCancel(OutputStream stream) {
  +        return false;
  +    }
  +
  +    /**
  +     * Cancels the <code>OutputStream</code> under <code>handler</code>.
  +     *
  +     * @see #cancel(OutputStream)
  +     */
  +    public void cancel(ContentHandler handler) throws Exception {
  +        if (handler instanceof WritingPipe) {
  +            WritingPipe pipe = (WritingPipe)handler;
  +            if (pipe.getSource() == this) {
  +                pipe.cancel();
  +                return;
  +            }
  +        }
  +
  +        // Not a valid handler for this source
  +        throw new IllegalArgumentException("The handler is not associated to this source");
  +    }
  +
  +    /**
  +     * Always throw <code>UnsupportedOperationException</code>. To be redefined by
  +     * implementations that support <code>cancel()</code>.
  +     */
  +    public void cancel(OutputStream stream) throws Exception {
  +        throw new UnsupportedOperationException("Cancel is not implemented on " +
  +            this.getClass().getName());
  +    }
   
       /**
        * Get a <code>ContentHandler</code> to write a SAX stream to this source. It
  -     * uses the 'xml' serializer to serialize events, and thus this serializer
  -     * must exist in this source's component manager.
  +     * uses either the 'xml' or 'html' serializer depending on the result of
  +     * {@link #isHTMLContent()} to serialize events, and thus these serializers must
  +     * exist in this source's component manager.
        */
       public ContentHandler getContentHandler() throws SAXException, ProcessingException {
           
           Serializer serializer;
  +        ComponentSelector selector;
  +        
  +        String serializerName = this.isHTMLContent() ? "html" : "xml";
           
           // Get the serializer
           try {
  -            ComponentSelector selector =
  +            selector =
                   (ComponentSelector)this.manager.lookup(Serializer.ROLE + "Selector");
  -            serializer = (Serializer)selector.select("xml");
  +            serializer = (Serializer)selector.select(serializerName);
           } catch(ComponentException ce) {
  -            throw new ProcessingException("Cannot get 'xml' serializer");
  +            throw new ProcessingException("Cannot get '" + serializerName + "' serializer");
           }
           
  -        // Connect the output stream to the serializer
  -        final OutputStream output;
           try {
  -            output = getOutputStream();
  -            serializer.setOutputStream(getOutputStream());
  +            return new WritingPipe(getOutputStream(), selector, serializer);
           } catch(IOException ioe) {
  +            selector.release(serializer);
               throw new ProcessingException("Cannot open stream for " + this.getSystemId(), ioe);
  -        }        
  +        }
  +    }
  +    
  +    /**
  +     * A pipe that closes the outputstream at the end of the document and handles cancel().
  +     */
  +    private class WritingPipe extends AbstractXMLPipe {
  +        
  +        // The output stream
  +        private OutputStream output;
  +        
  +        // Serialier and its selector for proper release
  +        private Serializer serializer;
  +        private ComponentSelector selector;
  +        
  +        public WritingPipe(OutputStream output, ComponentSelector selector, Serializer serializer)
  +          throws IOException {
  +            this.output = output;
  +            this.selector = selector;
  +            this.serializer = serializer;
  +            
  +            // Connect this pipe, the serializer and the output stream
  +            this.setConsumer(this.serializer);
  +            this.serializer.setOutputStream(this.output);
  +        }
  +        
  +        public WriteableSource getSource() {
  +            return AbstractStreamWriteableSource.this;
  +        }
           
  -        // Wrap the serializer in a pipe that will close the output stream
  -        // at the end of the document
  -        AbstractXMLPipe result = new AbstractXMLPipe() {
  -
  -            public void endDocument() throws SAXException {
  -                super.endDocument();
  -                try {
  -                    output.close();
  -                }
  -                catch(Exception e) {
  -                    throw new SAXException("Error while closing output stream", e);
  -                }
  +        /**
  +         * Close the underlying stream
  +         */
  +        public void endDocument() throws SAXException {
  +            super.endDocument();
  +            try {
  +                close();
               }
  -        };
  +            catch(Exception e) {
  +                throw new SAXException("Error while closing output stream", e);
  +            }
  +        }
  +        
  +        public boolean canCancel() {
  +            return this.output != null;
  +        }
  +        
  +        /**
  +         * Cancel the wrapped output stream
  +         */
  +        public void cancel() throws Exception {
  +            AbstractStreamWriteableSource.this.cancel(output);
  +            close();
  +        }
           
  -        result.setConsumer(serializer);
  +        private void close() throws IOException {
  +            if (this.serializer != null) {
  +                // Disconnect serializer;
  +                this.recycle();
  +                // and release it
  +                this.selector.release(this.serializer);
  +                this.serializer = null;
  +            }
  +            
  +            if (this.output != null) {
  +                this.output.close();
  +                this.output = null;
  +            }
  +        }
           
  -        return result;
  +        // Ensure all is closed properly
  +        protected void finalize() throws Throwable {
  +            close();
  +            super.finalize();
  +        }
       }
   }
       
  
  
  
  1.2       +94 -27    xml-cocoon2/src/java/org/apache/cocoon/components/source/FileSource.java
  
  Index: FileSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/source/FileSource.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FileSource.java	22 Feb 2002 23:25:18 -0000	1.1
  +++ FileSource.java	28 Feb 2002 18:00:50 -0000	1.2
  @@ -75,7 +75,7 @@
    * A <code>WriteableSource</code> for 'file:/' system IDs.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version $Id: FileSource.java,v 1.1 2002/02/22 23:25:18 sylvain Exp $
  + * @version $Id: FileSource.java,v 1.2 2002/02/28 18:00:50 sylvain Exp $
    */
   
   public class FileSource extends AbstractStreamWriteableSource implements WriteableSource {
  @@ -107,6 +107,10 @@
           this.file = new File(url.substring(5)); // 5 == "file:".length()
       }
       
  +    public boolean exists() {
  +        return this.file.exists();
  +    }
  +    
       /**
        * Returns <code>true</code> if the file name ends with ".htm" or ".html".
        */
  @@ -157,7 +161,7 @@
           
           // Create a temp file. It will replace the right one when writing terminates,
           // and serve as a lock to prevent concurrent writes.
  -        final File tmpFile = new File(this.file.getPath() + ".tmp");
  +        File tmpFile = new File(this.file.getPath() + ".tmp");
           
           // Ensure the directory exists
           tmpFile.getParentFile().mkdirs();
  @@ -174,37 +178,100 @@
           }
           
           // Return a stream that will rename the temp file on close.
  -        return new FilterOutputStream(new FileOutputStream(tmpFile)) {
  -            boolean closed = false;
  +        return new FileSourceOutputStream(tmpFile);
  +    }
  +
  +    /**
  +     * Always return <code>false</code>. To be redefined by implementations that support
  +     * <code>cancel()</code>.
  +     */
  +    public boolean canCancel(OutputStream stream) {
  +        if (stream instanceof FileSourceOutputStream) {
  +            FileSourceOutputStream fsos = (FileSourceOutputStream)stream;
  +            if (fsos.getSource() == this) {
  +                return fsos.canCancel();
  +            }
  +        }
   
  -            public void close() throws IOException {
  -                super.close();
  +        // Not a valid stream for this source
  +        throw new IllegalArgumentException("The stream is not associated to this source");
  +    }
   
  -                try {
  -                    // Delete destination file
  -                    if (FileSource.this.file.exists()) {
  -                        FileSource.this.file.delete();
  -                    }
  -                    // Rename temp file to destination file
  -                    tmpFile.renameTo(FileSource.this.file);
  -                    
  -                } 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.closed = true;
  -                }
  +    /**
  +     * Cancels the output stream.
  +     */
  +    public void cancel(OutputStream stream) throws Exception {
  +        if (stream instanceof FileSourceOutputStream) {
  +            FileSourceOutputStream fsos = (FileSourceOutputStream)stream;
  +            if (fsos.getSource() == this) {
  +                fsos.cancel();
  +                return;
               }
  -            
  -            public void finalize() {
  -                if (!this.closed && tmpFile.exists()) {
  -                    // Something wrong happened while writing : delete temp file
  +        }
  +
  +        // Not a valid stream for this source
  +        throw new IllegalArgumentException("The stream is not associated to this source");
  +    }
  +    
  +    /**
  +     * 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;
  +        
  +        public FileSourceOutputStream(File tmpFile) throws IOException {
  +            super(tmpFile);
  +            this.tmpFile = tmpFile;
  +        }
  +        
  +        public FileSource getSource() {
  +            return FileSource.this;
  +        }
  +
  +        public void close() throws IOException {
  +            super.close();
  +
  +            try {
  +                // Delete destination file
  +                if (FileSource.this.file.exists()) {
  +                    FileSource.this.file.delete();
  +                }
  +                // Rename temp file to destination file
  +                tmpFile.renameTo(FileSource.this.file);
  +                
  +            } 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();
  +            }
  +        }
       }
   }
       
  
  
  
  1.2       +41 -3     xml-cocoon2/src/java/org/apache/cocoon/environment/WriteableSource.java
  
  Index: WriteableSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/environment/WriteableSource.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- WriteableSource.java	22 Feb 2002 23:25:19 -0000	1.1
  +++ WriteableSource.java	28 Feb 2002 18:00:50 -0000	1.2
  @@ -75,7 +75,7 @@
    * SAX events to a byte stream.
    *
    * @author <a href="sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Id: WriteableSource.java,v 1.1 2002/02/22 23:25:19 sylvain Exp $
  + * @version CVS $Id: WriteableSource.java,v 1.2 2002/02/28 18:00:50 sylvain Exp $
    */
   public interface WriteableSource extends ModifiableSource {
   
  @@ -83,6 +83,13 @@
   // such as user/password, headers, etc ?
   
       /**
  +     * Does this source actually exist ?
  +     *
  +     * @return true if the resource exists.
  +     */
  +    boolean exists();
  +
  +    /**
        * Get a <code>ContentHandler</code> where an XML document can
        * be written using SAX events.
        * <p>
  @@ -93,7 +100,7 @@
        * @return a handler for SAX events
        */
       ContentHandler getContentHandler() throws SAXException, ProcessingException;
  -    
  +
       /**
        * Get an <code>InputStream</code> where raw bytes can be written to.
        * The signification of these bytes is implementation-dependent and
  @@ -102,5 +109,36 @@
        * @return a stream to write to
        */ 
       OutputStream getOutputStream() throws IOException, ProcessingException;
  -    
  +
  +    /**
  +     * Can the data sent to a <code>ContentHandler</code> returned by 
  +     * {@link #getContentHandler()} be cancelled ?
  +     *
  +     * @return true if the handler can be cancelled
  +     */
  +    boolean canCancel(ContentHandler handler);
  +
  +    /**
  +     * Can the data sent to an <code>OutputStream</code> returned by
  +     * {@link #getOutputStream()} be cancelled ?
  +     *
  +     * @return true if the stream can be cancelled
  +     */
  +    boolean canCancel(OutputStream stream);
  +
  +    /**
  +     * Cancel the data sent to a <code>ContentHandler</code> returned by
  +     * {@link #getContentHandler()}.
  +     * <p>
  +     * After cancel, the handler should no more be used.
  +     */
  +    void cancel(ContentHandler handler) throws Exception;
  +
  +    /**
  +     * Cancel the data sent to an <code>OutputStream</code> returned by
  +     * {@link #getOutputStream()}.
  +     * <p>
  +     * After cancel, the stream should no more be used.
  +     */
  +    void cancel(OutputStream stream) throws Exception;
   }
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     webmaster@xml.apache.org
To unsubscribe, e-mail:          cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org