/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.cocoon.components.source; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.component.ComponentSelector; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.serialization.Serializer; import org.apache.cocoon.xml.AbstractXMLPipe; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import java.io.IOException; import java.io.OutputStream; /** * This abstract class provides convenience methods to implement * a stream based <code>org.apache.cocoon.environment.WriteableSource</code>. * Implement getOutputStream() to obtain a valid implementation. * <p> * This base implementation creates a <code>ContentHandler</code> by using * the sitemap 'xml' serializer to write SAX events to the stream returned by * <code>getOutputStream()</code>. * * @deprecated Use the new Avalon Excalibur Source Resolving * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a> * @version CVS $Id$ */ public abstract class AbstractStreamWriteableSource extends AbstractStreamSource implements org.apache.cocoon.environment.WriteableSource { 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 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 { selector = (ComponentSelector)this.manager.lookup(Serializer.ROLE + "Selector"); serializer = (Serializer)selector.select(serializerName); } catch(ComponentException ce) { throw new ProcessingException("Cannot get '" + serializerName + "' serializer"); } try { 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 org.apache.cocoon.environment.WriteableSource getSource() { return AbstractStreamWriteableSource.this; } /** * 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(); } 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; } } // Ensure all is closed properly protected void finalize() throws Throwable { close(); super.finalize(); } } }