001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.source;
018:
019: import org.apache.avalon.framework.component.ComponentException;
020: import org.apache.avalon.framework.component.ComponentManager;
021: import org.apache.avalon.framework.component.ComponentSelector;
022: import org.apache.cocoon.ProcessingException;
023: import org.apache.cocoon.serialization.Serializer;
024: import org.apache.cocoon.xml.AbstractXMLPipe;
025: import org.xml.sax.ContentHandler;
026: import org.xml.sax.SAXException;
027:
028: import java.io.IOException;
029: import java.io.OutputStream;
030:
031: /**
032: * This abstract class provides convenience methods to implement
033: * a stream based <code>org.apache.cocoon.environment.WriteableSource</code>.
034: * Implement getOutputStream() to obtain a valid implementation.
035: * <p>
036: * This base implementation creates a <code>ContentHandler</code> by using
037: * the sitemap 'xml' serializer to write SAX events to the stream returned by
038: * <code>getOutputStream()</code>.
039: *
040: * @deprecated Use the new Avalon Excalibur Source Resolving
041: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
042: * @version CVS $Id: AbstractStreamWriteableSource.java 433543 2006-08-22 06:22:54Z crossley $
043: */
044: public abstract class AbstractStreamWriteableSource extends
045: AbstractStreamSource implements
046: org.apache.cocoon.environment.WriteableSource {
047:
048: protected AbstractStreamWriteableSource(ComponentManager manager) {
049: super (manager);
050: }
051:
052: /**
053: * Checks if the <code>OutputStream</code> under <code>handler</code> can be cancelled.
054: *
055: * @see #canCancel(OutputStream)
056: */
057: public boolean canCancel(ContentHandler handler) {
058: if (handler instanceof WritingPipe) {
059: WritingPipe pipe = (WritingPipe) handler;
060: if (pipe.getSource() == this ) {
061: return pipe.canCancel();
062: }
063: }
064:
065: // Not a valid handler for this source
066: throw new IllegalArgumentException(
067: "The handler is not associated to this source");
068: }
069:
070: /**
071: * Always return <code>false</code>. To be redefined by implementations that support
072: * <code>cancel()</code>.
073: */
074: public boolean canCancel(OutputStream stream) {
075: return false;
076: }
077:
078: /**
079: * Cancels the <code>OutputStream</code> under <code>handler</code>.
080: *
081: * @see #cancel(OutputStream)
082: */
083: public void cancel(ContentHandler handler) throws Exception {
084: if (handler instanceof WritingPipe) {
085: WritingPipe pipe = (WritingPipe) handler;
086: if (pipe.getSource() == this ) {
087: pipe.cancel();
088: return;
089: }
090: }
091:
092: // Not a valid handler for this source
093: throw new IllegalArgumentException(
094: "The handler is not associated to this source");
095: }
096:
097: /**
098: * Always throw <code>UnsupportedOperationException</code>. To be redefined by
099: * implementations that support <code>cancel()</code>.
100: */
101: public void cancel(OutputStream stream) throws Exception {
102: throw new UnsupportedOperationException(
103: "Cancel is not implemented on "
104: + this .getClass().getName());
105: }
106:
107: /**
108: * Get a <code>ContentHandler</code> to write a SAX stream to this source. It
109: * uses either the 'xml' or 'html' serializer depending on the result of
110: * {@link #isHTMLContent()} to serialize events, and thus these serializers must
111: * exist in this source's component manager.
112: */
113: public ContentHandler getContentHandler() throws SAXException,
114: ProcessingException {
115:
116: Serializer serializer;
117: ComponentSelector selector;
118:
119: String serializerName = this .isHTMLContent() ? "html" : "xml";
120:
121: // Get the serializer
122: try {
123: selector = (ComponentSelector) this .manager
124: .lookup(Serializer.ROLE + "Selector");
125: serializer = (Serializer) selector.select(serializerName);
126: } catch (ComponentException ce) {
127: throw new ProcessingException("Cannot get '"
128: + serializerName + "' serializer");
129: }
130:
131: try {
132: return new WritingPipe(getOutputStream(), selector,
133: serializer);
134: } catch (IOException ioe) {
135: selector.release(serializer);
136: throw new ProcessingException("Cannot open stream for "
137: + this .getSystemId(), ioe);
138: }
139: }
140:
141: /**
142: * A pipe that closes the outputstream at the end of the document and handles cancel().
143: */
144: private class WritingPipe extends AbstractXMLPipe {
145:
146: // The output stream
147: private OutputStream output;
148:
149: // Serialier and its selector for proper release
150: private Serializer serializer;
151: private ComponentSelector selector;
152:
153: public WritingPipe(OutputStream output,
154: ComponentSelector selector, Serializer serializer)
155: throws IOException {
156: this .output = output;
157: this .selector = selector;
158: this .serializer = serializer;
159:
160: // Connect this pipe, the serializer and the output stream
161: this .setConsumer(this .serializer);
162: this .serializer.setOutputStream(this .output);
163: }
164:
165: public org.apache.cocoon.environment.WriteableSource getSource() {
166: return AbstractStreamWriteableSource.this ;
167: }
168:
169: /**
170: * Close the underlying stream
171: */
172: public void endDocument() throws SAXException {
173: super .endDocument();
174: try {
175: close();
176: } catch (Exception e) {
177: throw new SAXException(
178: "Error while closing output stream", e);
179: }
180: }
181:
182: public boolean canCancel() {
183: return this .output != null;
184: }
185:
186: /**
187: * Cancel the wrapped output stream
188: */
189: public void cancel() throws Exception {
190: AbstractStreamWriteableSource.this .cancel(output);
191: close();
192: }
193:
194: private void close() throws IOException {
195: if (this .serializer != null) {
196: // Disconnect serializer;
197: this .recycle();
198: // and release it
199: this .selector.release(this .serializer);
200: this .serializer = null;
201: }
202:
203: if (this .output != null) {
204: this .output.close();
205: this .output = null;
206: }
207: }
208:
209: // Ensure all is closed properly
210: protected void finalize() throws Throwable {
211: close();
212: super.finalize();
213: }
214: }
215: }
|