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.transformation;
018:
019: import java.io.IOException;
020: import java.io.OutputStream;
021: import java.util.Map;
022:
023: import javax.xml.transform.TransformerConfigurationException;
024: import javax.xml.transform.TransformerFactory;
025: import javax.xml.transform.TransformerFactoryConfigurationError;
026: import javax.xml.transform.sax.SAXTransformerFactory;
027: import javax.xml.transform.sax.TransformerHandler;
028: import javax.xml.transform.stream.StreamResult;
029:
030: import org.apache.avalon.framework.CascadingRuntimeException;
031: import org.apache.avalon.framework.configuration.Configuration;
032: import org.apache.avalon.framework.configuration.ConfigurationException;
033: import org.apache.avalon.framework.parameters.Parameters;
034: import org.apache.cocoon.ProcessingException;
035: import org.apache.cocoon.components.source.SourceUtil;
036: import org.apache.cocoon.environment.SourceResolver;
037: import org.apache.cocoon.util.ClassUtils;
038: import org.apache.excalibur.source.ModifiableSource;
039: import org.apache.excalibur.source.Source;
040: import org.apache.excalibur.source.SourceException;
041: import org.xml.sax.Attributes;
042: import org.xml.sax.Locator;
043: import org.xml.sax.SAXException;
044:
045: /**
046: * @cocoon.sitemap.component.name tee
047: * @cocoon.sitemap.component.logger sitemap.transformer.tee
048: * @cocoon.sitemap.component.pooling.max 16
049: *
050: * The Teetransformer serializes SAX events as-is to the {@link org.apache.excalibur.source.ModifiableSource}
051: * specified by its <code>src</code> parameter.
052: * It does not in any way change the events.
053: * <p/>
054: * This transformer works just like the unix "tee" command and is useful for debugging
055: * received XML streams.
056: * <p/>
057: * Usage:<br>
058: * <pre>
059: * <map:transform type="tee" src="url"/>
060: * </pre>
061: *
062: * @version $Id: TeeTransformer.java 437305 2006-08-27 06:09:16Z antonio $
063: */
064: public class TeeTransformer extends AbstractSAXTransformer {
065:
066: /** the serializer */
067: private TransformerHandler serializer;
068:
069: /** the transformer factory to use */
070: private SAXTransformerFactory transformerFactory;
071:
072: /** the resolver */
073: private SourceResolver resolver;
074:
075: private OutputStream os;
076:
077: /*
078: * (non-Javadoc)
079: *
080: * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver,
081: * java.util.Map, java.lang.String,
082: * org.apache.avalon.framework.parameters.Parameters)
083: */
084: public void setup(SourceResolver resolver, Map objectModel,
085: String src, Parameters parameters)
086: throws ProcessingException, SAXException, IOException {
087:
088: super .setup(resolver, objectModel, src, parameters);
089:
090: Source source = null;
091: try {
092: this .resolver = resolver;
093: source = this .resolver.resolveURI(src);
094: String systemId = source.getURI();
095: if (!(source instanceof ModifiableSource)) {
096: throw new ProcessingException("Source '" + systemId
097: + "' is not writeable.");
098: }
099: this .serializer = this .transformerFactory
100: .newTransformerHandler();
101: os = ((ModifiableSource) source).getOutputStream();
102: this .serializer.setResult(new StreamResult(os));
103: } catch (SourceException e) {
104: throw SourceUtil.handle(e);
105: } catch (TransformerConfigurationException e) {
106: throw new ProcessingException(e);
107: } catch (TransformerFactoryConfigurationError error) {
108: throw new ProcessingException(error.getException());
109: } finally {
110: if (source != null) {
111: this .resolver.release(source);
112: }
113: }
114: }
115:
116: /*
117: * (non-Javadoc)
118: *
119: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
120: */
121: public void configure(Configuration configuration)
122: throws ConfigurationException {
123: String tFactoryClass = configuration.getChild(
124: "transformer-factory").getValue(null);
125: if (tFactoryClass != null) {
126: try {
127: this .transformerFactory = (SAXTransformerFactory) ClassUtils
128: .newInstance(tFactoryClass);
129: if (getLogger().isDebugEnabled()) {
130: getLogger().debug(
131: "Using transformer factory "
132: + tFactoryClass);
133: }
134: } catch (Exception e) {
135: throw new ConfigurationException(
136: "Cannot load transformer factory "
137: + tFactoryClass, e);
138: }
139: } else {
140: this .transformerFactory = (SAXTransformerFactory) TransformerFactory
141: .newInstance();
142:
143: }
144: }
145:
146: /**
147: * Receive an object for locating the origin of SAX document events.
148: */
149: public void setDocumentLocator(Locator locator) {
150: super .contentHandler.setDocumentLocator(locator);
151: this .serializer.setDocumentLocator(locator);
152: }
153:
154: /**
155: * Receive notification of the beginning of a document.
156: */
157: public void startDocument() throws SAXException {
158: super .contentHandler.startDocument();
159: this .serializer.startDocument();
160: }
161:
162: /**
163: * Receive notification of the end of a document.
164: */
165: public void endDocument() throws SAXException {
166: super .contentHandler.endDocument();
167: this .serializer.endDocument();
168: if (os != null) {
169: try {
170: os.close();
171: } catch (IOException e) {
172: throw new CascadingRuntimeException(
173: "Error closing output stream.", e);
174: }
175: }
176: }
177:
178: /**
179: * Begin the scope of a prefix-URI Namespace mapping.
180: */
181: public void startPrefixMapping(String prefix, String uri)
182: throws SAXException {
183: super .contentHandler.startPrefixMapping(prefix, uri);
184: this .serializer.startPrefixMapping(prefix, uri);
185: }
186:
187: /**
188: * End the scope of a prefix-URI mapping.
189: */
190: public void endPrefixMapping(String prefix) throws SAXException {
191: super .contentHandler.endPrefixMapping(prefix);
192: this .serializer.endPrefixMapping(prefix);
193: }
194:
195: /**
196: * Receive notification of the beginning of an element.
197: */
198: public void startElement(String uri, String loc, String raw,
199: Attributes a) throws SAXException {
200: super .contentHandler.startElement(uri, loc, raw, a);
201: this .serializer.startElement(uri, loc, raw, a);
202: }
203:
204: /**
205: * Receive notification of the end of an element.
206: */
207: public void endElement(String uri, String loc, String raw)
208: throws SAXException {
209: super .contentHandler.endElement(uri, loc, raw);
210: this .serializer.endElement(uri, loc, raw);
211: }
212:
213: /**
214: * Receive notification of character data.
215: */
216: public void characters(char ch[], int start, int len)
217: throws SAXException {
218: super .contentHandler.characters(ch, start, len);
219: this .serializer.characters(ch, start, len);
220: }
221:
222: /**
223: * Receive notification of ignorable whitespace in element content.
224: */
225: public void ignorableWhitespace(char ch[], int start, int len)
226: throws SAXException {
227: super .contentHandler.ignorableWhitespace(ch, start, len);
228: this .serializer.ignorableWhitespace(ch, start, len);
229: }
230:
231: /**
232: * Receive notification of a processing instruction.
233: */
234: public void processingInstruction(String target, String data)
235: throws SAXException {
236: super .contentHandler.processingInstruction(target, data);
237: this .serializer.processingInstruction(target, data);
238: }
239:
240: /**
241: * Receive notification of a skipped entity.
242: */
243: public void skippedEntity(String name) throws SAXException {
244: super .contentHandler.skippedEntity(name);
245: this .serializer.skippedEntity(name);
246: }
247:
248: /**
249: * Report the start of DTD declarations, if any.
250: */
251: public void startDTD(String name, String publicId, String systemId)
252: throws SAXException {
253: super .lexicalHandler.startDTD(name, publicId, systemId);
254: this .serializer.startDTD(name, publicId, systemId);
255: }
256:
257: /**
258: * Report the end of DTD declarations.
259: */
260: public void endDTD() throws SAXException {
261: super .lexicalHandler.endDTD();
262: this .serializer.endDTD();
263: }
264:
265: /**
266: * Report the beginning of an entity.
267: */
268: public void startEntity(String name) throws SAXException {
269: super .lexicalHandler.startEntity(name);
270: this .serializer.startEntity(name);
271: }
272:
273: /**
274: * Report the end of an entity.
275: */
276: public void endEntity(String name) throws SAXException {
277: super .lexicalHandler.endEntity(name);
278: this .serializer.endEntity(name);
279: }
280:
281: /**
282: * Report the start of a CDATA section.
283: */
284: public void startCDATA() throws SAXException {
285: super .lexicalHandler.startCDATA();
286: this .serializer.startCDATA();
287: }
288:
289: /**
290: * Report the end of a CDATA section.
291: */
292: public void endCDATA() throws SAXException {
293: super .lexicalHandler.endCDATA();
294: this .serializer.endCDATA();
295: }
296:
297: /**
298: * Report an XML comment anywhere in the document.
299: */
300: public void comment(char ch[], int start, int len)
301: throws SAXException {
302: super .lexicalHandler.comment(ch, start, len);
303: this .serializer.comment(ch, start, len);
304: }
305:
306: /*
307: * (non-Javadoc)
308: *
309: * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
310: */
311: public void recycle() {
312: super.recycle();
313: this.serializer = null;
314: }
315: }
|