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 CVS $Id: ElementProcessorSerializer.java 433543 2006-08-22 06:22:54Z crossley $
052: */
053: public abstract class ElementProcessorSerializer extends
054: AbstractLogEnabled implements Serializer, Serviceable {
055: private static final boolean _should_set_content_length = false;
056: private OutputStream _output_stream;
057: private Stack _open_elements;
058: private Locator _locator;
059: /** Service Manager */
060: protected ServiceManager manager = null;
061:
062: /**
063: * Constructor
064: */
065:
066: public ElementProcessorSerializer() {
067: _output_stream = null;
068: _open_elements = new Stack();
069: _locator = null;
070: }
071:
072: public void service(ServiceManager manager) {
073: this .manager = manager;
074: }
075:
076: /**
077: * get the appropriate ElementProcessorFactory
078: *
079: * @return an ElementProcessorFactory suitable for the file type
080: */
081:
082: protected abstract ElementProcessorFactory getElementProcessorFactory();
083:
084: /**
085: * perform whatever pre-initialization seems good on the
086: * ElementProcessor
087: *
088: * @param processor the processor to be initialized
089: *
090: * @exception SAXException on errors
091: */
092:
093: protected abstract void doPreInitialization(
094: ElementProcessor processor) throws SAXException;
095:
096: /**
097: * @return the output stream
098: */
099:
100: protected OutputStream getOutputStream() {
101: return _output_stream;
102: }
103:
104: /**
105: * Create a new SAXException
106: *
107: * @param message the exception message
108: * @param e the underlying exception (may be null)
109: *
110: * @return new SAXException
111: */
112:
113: protected SAXException SAXExceptionFactory(final String message,
114: final Exception e) {
115: StringBuffer message_buffer = new StringBuffer();
116:
117: message_buffer.append((message == null) ? "" : message);
118: if (_locator != null) {
119: message_buffer.append("; System id: \"");
120: message_buffer.append(_locator.getSystemId());
121: message_buffer.append("\"; public id: \"");
122: message_buffer.append(_locator.getPublicId());
123: message_buffer.append("\"; line number: ");
124: message_buffer.append(_locator.getLineNumber());
125: message_buffer.append("; column number: ");
126: message_buffer.append(_locator.getColumnNumber());
127: }
128: SAXException rval = null;
129:
130: if (e != null) {
131: rval = new SAXException(message_buffer.toString(), e);
132: } else {
133: rval = new SAXException(message_buffer.toString());
134: }
135: return rval;
136: }
137:
138: /**
139: * Create a SAXException
140: *
141: * @param message the exception message
142: *
143: * @return new SAXException
144: */
145:
146: protected SAXException SAXExceptionFactory(final String message) {
147: return SAXExceptionFactory(message, null);
148: }
149:
150: private ElementProcessor getCurrentElementProcessor() {
151: return _open_elements.empty() ? null
152: : (ElementProcessor) _open_elements.peek();
153: }
154:
155: private char[] cleanupArray(final char[] array, final int start,
156: final int length) {
157: char[] output = new char[length];
158:
159: System.arraycopy(array, start, output, 0, length);
160: return output;
161: }
162:
163: /* ********** START implementation of SitemapOutputComponent ********** */
164:
165: /**
166: * Set the OutputStream where the requested resource should be
167: * serialized.
168: *
169: * @param out the OutputStream to which the serialized data will
170: * be written
171: */
172:
173: public void setOutputStream(final OutputStream out) {
174: _output_stream = out;
175: }
176:
177: /**
178: * Test if the component wants to set the content length.
179: *
180: * @return false
181: */
182:
183: public boolean shouldSetContentLength() {
184: return _should_set_content_length;
185: }
186:
187: /* ********** END implementation of SitemapOutputComponent ********** */
188: /* ********** START implementation of LexicalHandler ********** */
189:
190: /**
191: * Report an XML comment anywhere in the document. We don't really
192: * care.
193: *
194: * @param ignored_ch
195: * @param ignored_start
196: * @param ignored_length
197: */
198:
199: public void comment(final char[] ignored_ch,
200: final int ignored_start, final int ignored_length) {
201: }
202:
203: /**
204: * Report the end of a CDATA section. We don't really care.
205: */
206:
207: public void endCDATA() {
208: }
209:
210: /**
211: * Report the end of DTD declarations. We don't really care.
212: */
213:
214: public void endDTD() {
215: }
216:
217: /**
218: * Report the end of an entity. We don't really care.
219: *
220: * @param ignored_name
221: */
222:
223: public void endEntity(final String ignored_name) {
224: }
225:
226: /**
227: * Report the start of a CDATA section. We don't really care.
228: */
229:
230: public void startCDATA() {
231: }
232:
233: /**
234: * Report the start of DTD declarations, if any. We don't really
235: * care.
236: *
237: * @param ignored_name
238: * @param ignored_publicId
239: * @param ignored_systemId
240: */
241:
242: public void startDTD(final String ignored_name,
243: final String ignored_publicId, final String ignored_systemId) {
244: }
245:
246: /**
247: * Report the beginning of some internal and external XML
248: * entities. We don't really care.
249: *
250: * @param ignored_name
251: */
252:
253: public void startEntity(final String ignored_name) {
254: }
255:
256: /* ********** END implementation of LexicalHandler ********** */
257: /* ********** START implementation of ContentHandler ********** */
258:
259: /**
260: * Receive notification of character data.
261: *
262: * @param ch the character array
263: * @param start the start index in ch
264: * @param length the length of the valid part of ch
265: *
266: * @exception SAXException if anything goes wrong in processing
267: * the character data
268: */
269:
270: public void characters(final char[] ch, final int start,
271: final int length) throws SAXException {
272: try {
273: getCurrentElementProcessor().acceptCharacters(
274: cleanupArray(ch, start, length));
275: } catch (Exception e) {
276: throw SAXExceptionFactory(
277: "could not process characters event", e);
278: }
279: }
280:
281: /**
282: * Receive notification of the end of an element.
283: *
284: * @param ignored_namespaceURI
285: * @param ignored_localName
286: * @param ignored_qName
287: *
288: * @exception SAXException on any errors processing the event.
289: */
290:
291: public void endElement(final String ignored_namespaceURI,
292: final String ignored_localName, final String ignored_qName)
293: throws SAXException {
294: try {
295: getCurrentElementProcessor().endProcessing();
296: _open_elements.pop();
297: } catch (Exception e) {
298: throw SAXExceptionFactory(
299: "could not process endElement event", e);
300: }
301: }
302:
303: /**
304: * End the scope of a prefix-URI mapping. We don't really care.
305: *
306: * @param ignored_prefix
307: */
308:
309: public void endPrefixMapping(final String ignored_prefix) {
310: }
311:
312: /**
313: * Receive notification of ignorable whitespace in element
314: * content.
315: *
316: * @param ch the character array
317: * @param start the start index in ch
318: * @param length the length of the valid part of ch
319: *
320: * @exception SAXException if anything goes wrong in processing
321: * the character data
322: */
323:
324: public void ignorableWhitespace(final char[] ch, final int start,
325: final int length) throws SAXException {
326: try {
327: getCurrentElementProcessor().acceptWhitespaceCharacters(
328: cleanupArray(ch, start, length));
329: } catch (Exception e) {
330: throw SAXExceptionFactory(
331: "could not process ignorableWhitespace event", e);
332: }
333: }
334:
335: /**
336: * Receive notification of a processing instruction. We don't
337: * really care.
338: *
339: * @param ignored_target
340: * @param ignored_data
341: */
342:
343: public void processingInstruction(final String ignored_target,
344: final String ignored_data) {
345: }
346:
347: /**
348: * Receive an object for locating the origin of SAX document
349: * events.
350: *
351: * @param locator the Locator object
352: */
353:
354: public void setDocumentLocator(final Locator locator) {
355: _locator = locator;
356: }
357:
358: /**
359: * Receive notification of a skipped entity. We don't really care.
360: *
361: * @param ignored_name
362: */
363:
364: public void skippedEntity(final String ignored_name) {
365: }
366:
367: /**
368: * Receive notification of the beginning of a document.
369: */
370:
371: public void startDocument() {
372: // nothing to do; should be ready as soon as we were
373: // constructed
374: }
375:
376: /**
377: * Receive notification of the beginning of an element.
378: *
379: * @param namespaceURI the namespace this element is in
380: * @param localName the local name of the element
381: * @param qName the qualified name of the element
382: * @param atts the Attributes, if any, of the element
383: *
384: * @exception SAXException if we cannot create an ElementProcessor
385: * to handle the element
386: */
387:
388: public void startElement(final String namespaceURI,
389: final String localName, final String qName,
390: final Attributes atts) throws SAXException {
391: String name = "";
392:
393: if ((localName != null) && (localName.length() != 0)) {
394: name = localName;
395: } else if ((qName != null) && (qName.length() != 0)) {
396: name = qName;
397: }
398: ElementProcessor processor;
399:
400: try {
401: processor = getElementProcessorFactory()
402: .createElementProcessor(name);
403: } catch (CannotCreateElementProcessorException e) {
404: throw SAXExceptionFactory(
405: "could not process startElement event", e);
406: }
407: doPreInitialization(processor);
408: Attribute[] attributes = (atts == null) ? new Attribute[0]
409: : new Attribute[atts.getLength()];
410:
411: for (int j = 0; j < attributes.length; j++) {
412: attributes[j] = new Attribute(atts.getQName(j), atts
413: .getValue(j));
414: }
415: try {
416: processor.initialize(attributes,
417: getCurrentElementProcessor());
418: } catch (IOException e) {
419: throw SAXExceptionFactory(
420: "Exception processing startElement", e);
421: }
422: _open_elements.push(processor);
423: }
424:
425: /**
426: * Begin the scope of a prefix-URI Namespace mapping. We don't
427: * really care.
428: *
429: * @param ignored_prefix
430: * @param ignored_uri
431: */
432:
433: public void startPrefixMapping(final String ignored_prefix,
434: final String ignored_uri) {
435: }
436: /* ********** END implementation of ContentHandler ********** */
437: } // end public abstract class ElementProcessorSerializer
|