/* * 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.elementprocessor.impl.poi.hssf.elements; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.cocoon.CascadingIOException; import org.apache.cocoon.components.elementprocessor.ElementProcessor; import org.apache.cocoon.components.elementprocessor.impl.poi.POIFSElementProcessor; import org.apache.cocoon.components.elementprocessor.types.Attribute; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** * The BaseElementProcessor class provides default behavior for * classes that can handle a particular XML element's content. * * It is intended that all ElementProcessors should extend this class. * This class is declared Abstract although it has no abstract * methods. It can be used 'as is' for a no-op ElementProcessor, and * an ElementProcessor that chooses to simply extend this class with * no overrides will be a no-op ElementProcessor. * * @author Marc Johnson (marc_johnson27591@hotmail.com) * @version CVS $Id$ */ public abstract class BaseElementProcessor extends AbstractLogEnabled implements POIFSElementProcessor { private Map _attributes; private POIFSFileSystem _filesystem; private BaseElementProcessor _parent; private StringBuffer _data; /** * Constructor * * @param implied_attributes an array of Attributes which might * not appear in the initialization call * because they are implied, and the SAX * processor will not automatically * generate them. */ protected BaseElementProcessor(final Attribute [] implied_attributes) { _attributes = new HashMap(); _filesystem = null; _parent = null; _data = new StringBuffer(); if (implied_attributes != null) { for (int k = 0; k < implied_attributes.length; k++) { _attributes.put(implied_attributes[ k ].getName(), implied_attributes[ k ]); } } } /** * @return the Attributes managed by this ElementProcessor. May be * empty, but never null */ protected Iterator getAttributes() { return _attributes.values().iterator(); } /** * Get the value of an attribute * * @param name the name of the attribute to look up * * @return the value of the specified attribute; will be null if * the attribute doesn't exist */ protected String getValue(final String name) { String value = null; Attribute attr = ( Attribute ) _attributes.get(name); if (attr != null) { value = attr.getValue(); } return value; } /** * @return the POIFSFileSystem object */ protected POIFSFileSystem getFilesystem() { return _filesystem; } /** * @return the parent ElementProcessor; may be null */ protected ElementProcessor getParent() { return _parent; } /** * get the nearest ancestor that happens to be an instance of the * specified class * * @param theclass the class we're looking for * * @return an ancestor of the specified class; null if no such * ancestor exists */ protected ElementProcessor getAncestor(final Class theclass) { ElementProcessor parent = getParent(); if (parent == null || parent.getClass().equals(theclass)) { return parent; } else { return ((BaseElementProcessor)parent).getAncestor(theclass); } } /** * @return the data, both regular characters and whitespace * characters, collected so far */ protected String getData() { return _data.toString().trim(); } /** * get the workbook we're working on. If it isn't in this * instance, check the parent * * @return the workbook we're working on. Never null * * @exception IOException if the workbook is missing */ protected Workbook getWorkbook() throws IOException { if (_parent != null) { return _parent.getWorkbook(); } else { // hit the end of the containment hierarchy without // finding it. This Is Bad throw new IOException("Cannot find the workbook object"); } } /** * get the current sheet we're working on. If it isn't in this * instance, check the parent * * @return the current sheet we're working on. Never null * * @exception IOException if the sheet is missing */ protected Sheet getSheet() throws IOException { if (_parent != null) { return _parent.getSheet(); } else { // hit the end of the containment hierarchy without // finding it. This Is Bad throw new IOException("Cannot find the sheet object"); } } /** * get the current cell we're working on. If it isn't in this * instance, check the parent * * @return the current cell we're working on. Never null * * @exception IOException if the cell is missing */ protected Cell getCell() throws IOException { if (_parent != null) { return _parent.getCell(); } else { // hit the end of the containment hierarchy without // finding it. This Is Bad throw new IOException("Cannot find the cell object"); } } /* ********** START implementation of ElementProcessor ********** */ /** * The implementation should walk the array of attributes and * perform appropriate actions based on that data. The array of * attributes is guaranteed never to be null, but it can be * empty. An implementation can expect code like this to work * without throwing runtime exceptions: * <br> * <code> * for (int k = 0; k < attributes.length; k++)<br> * {<br> *     Attribute attr = attributes[ k ];<br> *     // process attribute</br> * }</br> * </code> * <br> * <b>NOTE: if the XML DTD or schema includes <i>IMPLIED</i> * attributes for an element, those attributes are not included in * the Attribute array - they're not in the data provided in the * startElement call. The constructor for the ElementProcessor * should set those implied attributes itself, and allow them to * be overridden if the XML source provided <i>explicit</i> values * for them.</b> * <br> * The parent ElementProcessor is a reference to the * ElementProcessor whose corresponding XML element contains this * ElementProcessor's corresponding XML element. It will not be * null unless this ElementProcessor's corresponding XML element * is the top-level element in the XML document. Whether this * ElementProcessor needs to establish a containment relationship * with its parent or not, and whether it needs to do so at the * beginning, middle, or end of its life cycle, are private * matters left to the discretion of the individual * ElementProcessor implementation. If the ElementProcessor needs * to interact with its parent ElementProcessor, but is not ready * to do so when the initialize method is called, it must cache * the reference to its parent. * <br> * * @param attributes the array of Attribute instances; may be * empty, will never be null * @param parent the parent ElementProcessor; may be null * * @exception IOException if anything is wrong */ public void initialize(final Attribute [] attributes, final ElementProcessor parent) throws IOException { try { _parent = ( BaseElementProcessor ) parent; } catch (ClassCastException ignored) { throw new CascadingIOException( "parent is not compatible with this serializer", ignored); } // can't trust the guarantee -- an overriding implementation // may have screwed this up if (attributes != null) { for (int k = 0; k < attributes.length; k++) { _attributes.put(attributes[ k ].getName(), attributes[ k ]); } } } /** * The data provided in this method call comes from the * corresponding XML element's contents. The array is guaranteed * not to be null and will never be empty. * <br> * The POIFSSerializer will make 0 to many calls to this method; * all such calls will occur after the initialize method is called * and before the endProcessing method is called. * <br> * Calls to this method may be interleaved with calls to * acceptWhitespaceCharacters. All calls to acceptCharacters and * acceptWhitespaceCharacters are guaranteed to be in the same * order as their data is in the element. * * @param data the character data */ public void acceptCharacters(final char [] data) { if (data != null) { _data.append(data); } } /** * The data provided in this method call comes from the * corresponding XML element's contents. The array is guaranteed * not to be null and will never be empty. * <br> * The POIFSSerializer will make 0 to many calls to this method; * all such calls will occur after the initialize method is called * and before the endProcessing method is called. * <br> * Calls to this method may be interleaved with calls to * acceptCharacters. All calls to acceptCharacters and * acceptWhitespaceCharacters are guaranteed to be in the same * order as their data is in the element. * * @param data the whitespace characters */ public void acceptWhitespaceCharacters(final char [] data) { if (data != null) { _data.append(data); } } /** * This is the last method call executed by the * POIFSSerializer. When this method is called, the * ElementProcessor should finish its work and perform its final * interactions with its parent ElementProcessor and the * filesystem, if necessary. * <br> * If the implementation cached the parent ElementProcessor * reference, the filesystem reference, or both, when the * initialize method was called, it should null out those * references. * * @exception IOException */ public void endProcessing() throws IOException { _filesystem = null; _parent = null; } /* ********** END implementation of ElementProcessor ********** */ /* ********** START implementation of POIFSElementProcessor ********** */ /** * Set the POIFSFileSystem for the element processor * * @param fs the POIFSFileSystem instance */ public void setFilesystem(POIFSFileSystem fs) { _filesystem = fs; } /* ********** END implementation of POIFSElementProcessor ********** */ } // end package scope abstract class BaseElementProcessor