001    /* ========================================================================
002     * JCommon : a free general purpose class library for the Java(tm) platform
003     * ========================================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     * 
007     * Project Info:  http://www.jfree.org/jcommon/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     * 
027     * -----------------------
028     * GenericReadHandler.java
029     * -----------------------
030     * (C)opyright 2003, by Thomas Morgner and Contributors.
031     *
032     * Original Author:  Thomas Morgner;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *
035     * $Id: GenericReadHandler.java,v 1.5 2005/10/18 13:33:32 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 23-Sep-2003 : Initial version
040     *
041     */
042    
043    package org.jfree.xml.parser.coretypes;
044    
045    import java.util.ArrayList;
046    import java.util.HashMap;
047    
048    import org.jfree.util.Log;
049    import org.jfree.xml.parser.AbstractXmlReadHandler;
050    import org.jfree.xml.parser.RootXmlReadHandler;
051    import org.jfree.xml.parser.XmlReadHandler;
052    import org.jfree.xml.parser.XmlReaderException;
053    import org.jfree.xml.util.AttributeDefinition;
054    import org.jfree.xml.util.ConstructorDefinition;
055    import org.jfree.xml.util.GenericObjectFactory;
056    import org.jfree.xml.util.LookupDefinition;
057    import org.jfree.xml.util.ObjectDescriptionException;
058    import org.jfree.xml.util.PropertyDefinition;
059    import org.xml.sax.Attributes;
060    import org.xml.sax.SAXException;
061    
062    /**
063     * A SAX handler for reading a generic object from an XML element.
064     */
065    public class GenericReadHandler extends AbstractXmlReadHandler {
066    
067        /** The object under construction. */
068        private Object object;
069        
070        /** The generic object factory. */
071        private GenericObjectFactory objectFactory;
072        
073        /** The object reference handlers. */
074        private ArrayList objectRefHandlers;
075        
076        /** The created handler. */
077        private HashMap createdHandler;
078    
079        /**
080         * Creates a new handler.
081         *
082         * @param factory  the generic object factory.
083         */
084        public GenericReadHandler(final GenericObjectFactory factory) {
085            this.createdHandler = new HashMap();
086            this.objectRefHandlers = new ArrayList();
087            this.objectFactory = factory;
088        }
089    
090        /**
091         * Called at the start of parsing.
092         * 
093         * @param attrs  the attributes.
094         * 
095         * @throws SAXException if there is a parsing error.
096         */
097        protected void startParsing(final Attributes attrs) throws SAXException {
098    
099            try {
100                final AttributeDefinition[] attribs = this.objectFactory.getAttributeDefinitions();
101                for (int i = 0; i < attribs.length; i++) {
102                    final AttributeDefinition attrDef = attribs[i];
103                    final String value = attrs.getValue(attrDef.getAttributeName());
104                    if (value == null) {
105                        continue;
106                    }
107                    final Object o = attrDef.getHandler().toPropertyValue(value);
108                    this.objectFactory.setProperty(attrDef.getPropertyName(), o);
109                }
110            }
111            catch (ObjectDescriptionException ode) {
112                throw new SAXException(ode);
113            }
114        }
115    
116        /**
117         * Returns the child handler.
118         * 
119         * @param tagName  the tag name.
120         * @param atts  the attributes.
121         * 
122         * @return The handler.
123         * 
124         * @throws SAXException if there is a parsing problem.
125         */
126        protected XmlReadHandler getHandlerForChild(final String tagName, final Attributes atts)
127            throws SAXException {
128            try {
129                if (tagName.equals("objectRef")) {
130                    // store them all and copy the properties later when the object is created
131                    final XmlReadHandler handler = new ObjectRefHandler();
132                    this.objectRefHandlers.add(handler);
133                    return handler;
134                }
135                final XmlReadHandler handler = getRootHandler().createHandler
136                    (this.objectFactory.getTypeForTagName(tagName), tagName, atts);
137                if (handler != null) {
138                    this.createdHandler.put(tagName, handler);
139                }
140                // will throw exception if handler is null...
141                return handler;
142            }
143            catch (ObjectDescriptionException ode) {
144                Log.debug ("Failed to get handler for child: ", ode);
145                throw new SAXException(ode);
146            }
147        }
148    
149        /**
150         * Returns the object.
151         * 
152         * @return The object.
153         * 
154         * @throws XmlReaderException ???
155         */
156        public Object getObject() throws XmlReaderException {
157    
158            if (this.object != null) {
159                return this.object;
160            }
161            final RootXmlReadHandler rootHandler = getRootHandler();
162            try {
163                for (int i = 0; i < this.objectRefHandlers.size(); i++) {
164                    final ObjectRefHandler handler = (ObjectRefHandler) this.objectRefHandlers.get(i);
165                    this.objectFactory.setProperty(handler.getPropertyName(), handler.getObject());
166                }
167    
168                final ArrayList lookups = new ArrayList();
169                final LookupDefinition[] lookupDefs = this.objectFactory.getLookupDefinitions();
170                for (int i = 0; i < lookupDefs.length; i++) {
171                    final LookupDefinition ldef = lookupDefs[i];
172                    lookups.add(ldef.getPropertyName());
173                    Log.debug ("lookup object: " + ldef.getPropertyName());
174    
175                    final Object value = rootHandler.getHelperObject(ldef.getRegistryKey());
176                    if (value == null) {
177                        // todo may or may not be fatal -> define it in the xml?
178                        Log.warn ("Failed to lookup object: " + value);
179                    }
180                    else {
181                        this.objectFactory.setProperty(ldef.getPropertyName(), value);
182                    }
183                }
184    
185                final ConstructorDefinition[] conDefs = this.objectFactory.getConstructorDefinitions();
186                for (int i = 0; i < conDefs.length; i++) {
187                    final ConstructorDefinition cDef = conDefs[i];
188                    // if this is a lookup, then ignore
189                    if (lookups.contains(cDef.getPropertyName())) {
190                        continue;
191                    }
192                    if (this.objectFactory.isPropertyDefinition(cDef.getPropertyName())) {
193                        final PropertyDefinition pd = this.objectFactory.getPropertyDefinitionByPropertyName(
194                            cDef.getPropertyName()
195                        );
196                        final XmlReadHandler handler = (XmlReadHandler) this.createdHandler.get(
197                            pd.getElementName()
198                        );
199                        if (handler != null) {
200                            this.objectFactory.setProperty(pd.getPropertyName(), handler.getObject());
201                        }
202                    }
203                    // hoping that the attribute is set ..
204                }
205    
206                this.object = this.objectFactory.createObject();
207                Object oldValue = null;
208                if (this.objectFactory.getRegisterName() != null) {
209                    oldValue = rootHandler.getHelperObject(this.objectFactory.getRegisterName());
210                    rootHandler.setHelperObject(this.objectFactory.getRegisterName(), this.object);
211                }
212    
213                final PropertyDefinition[] propertyDefs = this.objectFactory.getPropertyDefinitions();
214                for (int i = 0; i < propertyDefs.length; i++) {
215                    final PropertyDefinition pdef = propertyDefs[i];
216                    final XmlReadHandler handler = (XmlReadHandler) this.createdHandler.get(
217                        pdef.getElementName()
218                    );
219                    if (handler == null) {
220                        continue;
221                    }
222                    this.objectFactory.setProperty(pdef.getPropertyName(), handler.getObject());
223                }
224    
225                this.objectFactory.writeObjectProperties(this.object);
226    
227                if (this.objectFactory.getRegisterName() != null) {
228                    rootHandler.setHelperObject(this.objectFactory.getRegisterName(), oldValue);
229                }
230            }
231            catch (ObjectDescriptionException ode) {
232                Log.error ("Unable to create object.", ode);
233                throw new XmlReaderException("Unable to create object.", ode);
234            }
235            return this.object;
236        }
237    
238    }