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.serialization;
018:
019: import java.io.IOException;
020: import java.io.OutputStream;
021: import java.util.Stack;
022:
023: import org.apache.avalon.framework.logger.AbstractLogEnabled;
024: import org.apache.avalon.framework.service.ServiceManager;
025: import org.apache.avalon.framework.service.Serviceable;
026:
027: import org.apache.cocoon.components.elementprocessor.CannotCreateElementProcessorException;
028: import org.apache.cocoon.components.elementprocessor.ElementProcessor;
029: import org.apache.cocoon.components.elementprocessor.ElementProcessorFactory;
030: import org.apache.cocoon.components.elementprocessor.types.Attribute;
031:
032: import org.xml.sax.Attributes;
033: import org.xml.sax.Locator;
034: import org.xml.sax.SAXException;
035:
036: /**
037: * An implementation of nearly all of the methods included in the
038: * org.apache.poi.serialization.Serializer interface
039: *
040: * This is an abstract class. Concrete extensions need to implement
041: * the following methods:
042: * <ul>
043: * <li>String getMimeType()</li>
044: * <li>void endDocument()</li>
045: * <li>ElementProcessorFactory getElementProcessorFactory()</li>
046: * <li>void doPreInitialization(ElementProcessor processor)</li>
047: * </ul>
048: *
049: * @author Marc Johnson (marc_johnson27591@hotmail.com)
050: * @author Nicola Ken Barozzi (nicolaken@apache.org)
051: * @version $Id: ElementProcessorSerializer.java 523500 2007-03-28 23:06:39Z joerg $
052: */
053: public abstract class ElementProcessorSerializer extends
054: AbstractLogEnabled implements Serializer, Serviceable {
055:
056: private final Stack openElements;
057:
058: protected ServiceManager manager;
059:
060: private OutputStream outputStream;
061: private Locator locator;
062:
063: /**
064: * Constructor
065: */
066: public ElementProcessorSerializer() {
067: this .openElements = new Stack();
068: }
069:
070: public void service(ServiceManager manager) {
071: this .manager = manager;
072: }
073:
074: /**
075: * get the appropriate ElementProcessorFactory
076: *
077: * @return an ElementProcessorFactory suitable for the file type
078: */
079: protected abstract ElementProcessorFactory getElementProcessorFactory();
080:
081: /**
082: * perform whatever pre-initialization seems good on the
083: * ElementProcessor
084: *
085: * @param processor the processor to be initialized
086: *
087: * @exception SAXException on errors
088: */
089: protected abstract void doPreInitialization(
090: ElementProcessor processor) throws SAXException;
091:
092: /**
093: * @return the output stream
094: */
095: protected OutputStream getOutputStream() {
096: return this .outputStream;
097: }
098:
099: /**
100: * Create a new SAXException
101: *
102: * @param message the exception message
103: * @param e the underlying exception (may be null)
104: *
105: * @return new SAXException
106: */
107: protected SAXException SAXExceptionFactory(final String message,
108: final Exception e) {
109: StringBuffer message_buffer = new StringBuffer();
110:
111: message_buffer.append((message == null) ? "" : message);
112: if (this .locator != null) {
113: message_buffer.append("; System id: \"");
114: message_buffer.append(this .locator.getSystemId());
115: message_buffer.append("\"; public id: \"");
116: message_buffer.append(this .locator.getPublicId());
117: message_buffer.append("\"; line number: ");
118: message_buffer.append(this .locator.getLineNumber());
119: message_buffer.append("; column number: ");
120: message_buffer.append(this .locator.getColumnNumber());
121: }
122: SAXException rval = null;
123:
124: if (e != null) {
125: rval = new SAXException(message_buffer.toString(), e);
126: } else {
127: rval = new SAXException(message_buffer.toString());
128: }
129: return rval;
130: }
131:
132: /**
133: * Create a SAXException
134: *
135: * @param message the exception message
136: *
137: * @return new SAXException
138: */
139: protected SAXException SAXExceptionFactory(final String message) {
140: return SAXExceptionFactory(message, null);
141: }
142:
143: private ElementProcessor getCurrentElementProcessor() {
144: return this .openElements.empty() ? null
145: : (ElementProcessor) this .openElements.peek();
146: }
147:
148: private char[] cleanupArray(final char[] array, final int start,
149: final int length) {
150: char[] output = new char[length];
151: System.arraycopy(array, start, output, 0, length);
152: return output;
153: }
154:
155: /* ********** START implementation of SitemapOutputComponent ********** */
156:
157: /**
158: * Set the OutputStream where the requested resource should be
159: * serialized.
160: *
161: * @param out the OutputStream to which the serialized data will
162: * be written
163: */
164: public void setOutputStream(final OutputStream out) {
165: this .outputStream = out;
166: }
167:
168: /**
169: * Test if the component wants to set the content length.
170: *
171: * @return false
172: */
173: public boolean shouldSetContentLength() {
174: return false;
175: }
176:
177: /* ********** END implementation of SitemapOutputComponent ********** */
178: /* ********** START implementation of LexicalHandler ********** */
179:
180: /**
181: * Report an XML comment anywhere in the document. We don't really
182: * care.
183: */
184: public void comment(final char[] ch, final int start,
185: final int length) {
186: }
187:
188: /**
189: * Report the end of a CDATA section. We don't really care.
190: */
191: public void endCDATA() {
192: }
193:
194: /**
195: * Report the end of DTD declarations. We don't really care.
196: */
197: public void endDTD() {
198: }
199:
200: /**
201: * Report the end of an entity. We don't really care.
202: */
203: public void endEntity(final String name) {
204: }
205:
206: /**
207: * Report the start of a CDATA section. We don't really care.
208: */
209: public void startCDATA() {
210: }
211:
212: /**
213: * Report the start of DTD declarations, if any. We don't really
214: * care.
215: */
216: public void startDTD(final String name, final String publicId,
217: final String systemId) {
218: }
219:
220: /**
221: * Report the beginning of some internal and external XML
222: * entities. We don't really care.
223: */
224: public void startEntity(final String name) {
225: }
226:
227: /* ********** END implementation of LexicalHandler ********** */
228: /* ********** START implementation of ContentHandler ********** */
229:
230: /**
231: * Receive notification of character data.
232: *
233: * @param ch the character array
234: * @param start the start index in ch
235: * @param length the length of the valid part of ch
236: *
237: * @exception SAXException if anything goes wrong in processing
238: * the character data
239: */
240: public void characters(final char[] ch, final int start,
241: final int length) throws SAXException {
242: ElementProcessor currentElementProcessor = getCurrentElementProcessor();
243: if (currentElementProcessor != null) {
244: currentElementProcessor.acceptCharacters(cleanupArray(ch,
245: start, length));
246: }
247: }
248:
249: /**
250: * Receive notification of the end of an element.
251: *
252: * @exception SAXException on any errors processing the event.
253: */
254: public void endElement(final String namespaceURI,
255: final String localName, final String qName)
256: throws SAXException {
257: try {
258: getCurrentElementProcessor().endProcessing();
259: this .openElements.pop();
260: } catch (IOException e) {
261: throw SAXExceptionFactory(
262: "could not process endElement event", e);
263: }
264: }
265:
266: /**
267: * End the scope of a prefix-URI mapping. We don't really care.
268: */
269: public void endPrefixMapping(final String prefix) {
270: }
271:
272: /**
273: * Receive notification of ignorable whitespace in element
274: * content.
275: *
276: * @param ch the character array
277: * @param start the start index in ch
278: * @param length the length of the valid part of ch
279: *
280: * @exception SAXException if anything goes wrong in processing
281: * the character data
282: */
283: public void ignorableWhitespace(final char[] ch, final int start,
284: final int length) throws SAXException {
285: ElementProcessor currentElementProcessor = getCurrentElementProcessor();
286: if (currentElementProcessor != null) {
287: currentElementProcessor
288: .acceptWhitespaceCharacters(cleanupArray(ch, start,
289: length));
290: }
291: }
292:
293: /**
294: * Receive notification of a processing instruction. We don't
295: * really care.
296: */
297: public void processingInstruction(final String target,
298: final String data) {
299: }
300:
301: /**
302: * Receive an object for locating the origin of SAX document
303: * events.
304: *
305: * @param locator the Locator object
306: */
307: public void setDocumentLocator(final Locator locator) {
308: this .locator = locator;
309: }
310:
311: /**
312: * Receive notification of a skipped entity. We don't really care.
313: */
314: public void skippedEntity(final String name) {
315: }
316:
317: /**
318: * Receive notification of the beginning of a document.
319: */
320: public void startDocument() {
321: // nothing to do; should be ready as soon as we were
322: // constructed
323: }
324:
325: /**
326: * Receive notification of the beginning of an element.
327: *
328: * @param namespaceURI the namespace this element is in
329: * @param localName the local name of the element
330: * @param qName the qualified name of the element
331: * @param atts the Attributes, if any, of the element
332: *
333: * @exception SAXException if we cannot create an ElementProcessor
334: * to handle the element
335: */
336: public void startElement(final String namespaceURI,
337: final String localName, final String qName,
338: final Attributes atts) throws SAXException {
339: String name = "";
340:
341: if (localName != null && localName.length() != 0) {
342: name = localName;
343: } else if (qName != null && qName.length() != 0) {
344: name = qName;
345: }
346: ElementProcessor processor;
347:
348: try {
349: processor = getElementProcessorFactory()
350: .createElementProcessor(name);
351: } catch (CannotCreateElementProcessorException e) {
352: throw SAXExceptionFactory(
353: "could not process startElement event", e);
354: }
355: doPreInitialization(processor);
356: Attribute[] attributes = (atts == null) ? new Attribute[0]
357: : new Attribute[atts.getLength()];
358:
359: for (int j = 0; j < attributes.length; j++) {
360: attributes[j] = new Attribute(atts.getQName(j), atts
361: .getValue(j));
362: }
363: try {
364: processor.initialize(attributes,
365: getCurrentElementProcessor());
366: } catch (IOException e) {
367: throw SAXExceptionFactory(
368: "Exception processing startElement", e);
369: }
370: this .openElements.push(processor);
371: }
372:
373: /**
374: * Begin the scope of a prefix-URI Namespace mapping. We don't
375: * really care.
376: */
377: public void startPrefixMapping(final String prefix, final String uri) {
378: }
379: /* ********** END implementation of ContentHandler ********** */
380:
381: } // end public abstract class ElementProcessorSerializer
|