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 * ClassFactoryImpl.java
029 * ---------------------
030 * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
031 *
032 * Original Author:  Thomas Morgner;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *
035 * $Id: ClassFactoryImpl.java,v 1.6 2006/01/25 23:15:03 taqua Exp $
036 *
037 * Changes (from 19-Feb-2003)
038 * -------------------------
039 * 19-Feb-2003 : Added standard header and Javadocs (DG);
040 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
041 * 29-Jul-2004 : Replaced 'enum' variable name (reserved word in JDK 1.5) (DG);
042 *
043 */
044
045package org.jfree.xml.factory.objects;
046
047import java.util.HashMap;
048import java.util.Iterator;
049
050import org.jfree.util.Configuration;
051import org.jfree.util.ClassComparator;
052/**
053 * An abstract class that implements the {@link ClassFactory} interface.
054 *
055 * @author Thomas Morgner.
056 */
057public abstract class ClassFactoryImpl implements ClassFactory {
058
059    /** Storage for the classes. */
060    private HashMap classes;
061    /** A class comparator for searching the super class */
062    private ClassComparator comparator;
063    /** The parser/report configuration */
064    private Configuration config;
065
066    /**
067     * Creates a new class factory.
068     */
069    public ClassFactoryImpl() {
070        this.classes = new HashMap();
071        this.comparator = new ClassComparator();
072    }
073
074    /**
075     * Returns the class comparator used to sort the super classes of an object.
076     *
077     * @return the class comparator.
078     */
079    public ClassComparator getComparator() {
080        return this.comparator;
081    }
082
083    /**
084     * Returns an object-description for a class.
085     *
086     * @param c  the class.
087     *
088     * @return An object description.
089     */
090    public ObjectDescription getDescriptionForClass(final Class c) {
091        final ObjectDescription od = (ObjectDescription) this.classes.get(c);
092        if (od == null) {
093            return null;
094        }
095        return od.getInstance();
096    }
097
098    /**
099     * Returns the most concrete object-description for the super class of a class.
100     *
101     * @param d  the class.
102     * @param knownSuperClass a known supported superclass or null, if no superclass
103     * is known yet.
104     *
105     * @return The object description.
106     */
107    public ObjectDescription getSuperClassObjectDescription
108        (final Class d, ObjectDescription knownSuperClass) {
109
110        if (d == null) {
111            throw new NullPointerException("Description class must not be null.");
112        }
113        final Iterator iterator = this.classes.keySet().iterator();
114        while (iterator.hasNext()) {
115            final Class keyClass = (Class) iterator.next();
116            if (keyClass.isAssignableFrom(d)) {
117                final ObjectDescription od = (ObjectDescription) this.classes.get(keyClass);
118                if (knownSuperClass == null) {
119                    knownSuperClass = od;
120                }
121                else {
122                    if (this.comparator.isComparable
123                        (knownSuperClass.getObjectClass(), od.getObjectClass())) {
124                        if (this.comparator.compare
125                            (knownSuperClass.getObjectClass(), od.getObjectClass()) < 0) {
126                            knownSuperClass = od;
127                        }
128                    }
129                }
130            }
131        }
132        if (knownSuperClass == null) {
133            return null;
134        }
135        return knownSuperClass.getInstance();
136    }
137
138    /**
139     * Registers an object description with the factory.
140     *
141     * @param key  the key.
142     * @param od  the object description.
143     */
144    protected void registerClass(final Class key, final ObjectDescription od) {
145        this.classes.put(key, od);
146        if (this.config != null) {
147            od.configure(this.config);
148        }
149    }
150
151    /**
152     * Returns an iterator that provides access to the registered object definitions.
153     *
154     * @return The iterator.
155     */
156    public Iterator getRegisteredClasses() {
157        return this.classes.keySet().iterator();
158    }
159
160
161    /**
162     * Configures this factory. The configuration contains several keys and
163     * their defined values. The given reference to the configuration object
164     * will remain valid until the report parsing or writing ends.
165     * <p>
166     * The configuration contents may change during the reporting.
167     *
168     * @param config the configuration, never null
169     */
170    public void configure(final Configuration config) {
171        if (config == null) {
172            throw new NullPointerException("The given configuration is null");
173        }
174        if (this.config != null) {
175            // already configured ... ignored
176            return;
177        }
178
179        this.config = config;
180        final Iterator it = this.classes.values().iterator();
181        while (it.hasNext()) {
182            final ObjectDescription od = (ObjectDescription) it.next();
183            od.configure(config);
184        }
185    }
186
187    /**
188     * Returns the currently set configuration or null, if none was set.
189     *
190     * @return the configuration.
191     */
192    public Configuration getConfig() {
193        return this.config;
194    }
195
196    /**
197     * Tests for equality.
198     * 
199     * @param o  the object to test.
200     * 
201     * @return A boolean.
202     */
203    public boolean equals(final Object o) {
204        if (this == o) {
205            return true;
206        }
207        if (!(o instanceof ClassFactoryImpl)) {
208            return false;
209        }
210
211        final ClassFactoryImpl classFactory = (ClassFactoryImpl) o;
212
213        if (!this.classes.equals(classFactory.classes)) {
214            return false;
215        }
216
217        return true;
218    }
219
220    /**
221     * Returns a hash code.
222     * 
223     * @return A hash code.
224     */
225    public int hashCode() {
226        return this.classes.hashCode();
227    }
228}