    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 * AbstractObjectDescription.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: AbstractObjectDescription.java,v 1.3 2005/11/14 10:58:37 mungady 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 *
    042 */
    043
    044package org.jfree.xml.factory.objects;
    045
    046import java.util.ArrayList;
    047import java.util.Collections;
    048import java.util.HashMap;
    049import java.util.Iterator;
    050
    051import org.jfree.util.Configuration;
    052import org.jfree.util.Log;
    053import org.jfree.util.ReadOnlyIterator;
    054
    055/**
    056 * An abstract base class for object descriptions.
    057 *
    058 * @author Thomas Morgner.
    059 */
    060public abstract class AbstractObjectDescription implements ObjectDescription, Cloneable {
    061
    062    /** The class. */
    063    private Class className;
    064
    065    /** Storage for parameters. */
    066    private HashMap parameters;
    067
    068    /** Storage for parameter definitions. */
    069    private HashMap parameterDefs;
    070
    071    /** The configuration for the object description. */
    072    private Configuration config;
    073
    074    /**
    075     * Creates a new object description.
    076     *
    077     * @param className  the class.
    078     */
    079    public AbstractObjectDescription(final Class className) {
    080        this.className = className;
    081        this.parameters = new HashMap();
    082        this.parameterDefs = new HashMap();
    083    }
    084
    085    /**
    086     * Returns a parameter class.
    087     *
    088     * @param name  the parameter definition.
    089     *
    090     * @return The class.
    091     */
    092    public Class getParameterDefinition(final String name) {
    093        return (Class) this.parameterDefs.get(name);
    094    }
    095
    096    /**
    097     * Sets the class for a parameter.
    098     *
    099     * @param name  the parameter name.
    100     * @param obj  the parameter class.
    101     */
    102    public void setParameterDefinition(final String name, final Class obj) {
    103        if (obj == null) {
    104            this.parameterDefs.remove(name);
    105        }
    106        else {
    107            this.parameterDefs.put(name, obj);
    108        }
    109    }
    110
    111    /**
    112     * Converts primitives to corresponding object class.
    113     *
    114     * @param obj  the class.
    115     *
    116     * @return The class.
    117     */
    118    public static Class convertPrimitiveClass(final Class obj) {
    119        if (!obj.isPrimitive()) {
    120            return obj;
    121        }
    122        if (obj == Boolean.TYPE) {
    123            return Boolean.class;
    124        }
    125        if (obj == Byte.TYPE) {
    126            return Byte.class;
    127        }
    128        if (obj == Character.TYPE) {
    129            return Character.class;
    130        }
    131        if (obj == Short.TYPE) {
    132            return Short.class;
    133        }
    134        if (obj == Integer.TYPE) {
    135            return Integer.class;
    136        }
    137        if (obj == Long.TYPE) {
    138            return Long.class;
    139        }
    140        if (obj == Float.TYPE) {
    141            return Float.class;
    142        }
    143        if (obj == Double.TYPE) {
    144            return Double.class;
    145        }
    146        throw new IllegalArgumentException("Class 'void' is not allowed here");
    147    }
    148
    149    /**
    150     * Sets a parameter.
    151     *
    152     * @param name  the name.
    153     * @param value  the value.
    154     */
    155    public void setParameter(final String name, final Object value) {
    156        if (getParameterDefinition(name) == null) {
    157            throw new IllegalArgumentException("No such Parameter defined: " + name
    158                + " in class " + getObjectClass());
    159        }
    160        final Class parameterClass = convertPrimitiveClass(getParameterDefinition(name));
    161        if (!parameterClass.isAssignableFrom(value.getClass())) {
    162            throw new ClassCastException("In Object " + getObjectClass()
    163                + ": Value is not assignable: " + value.getClass()
    164                + " is not assignable from " + parameterClass);
    165        }
    166        this.parameters.put(name, value);
    167    }
    168
    169    /**
    170     * Returns an iterator for the parameter names.
    171     *
    172     * @return The iterator.
    173     */
    174    public synchronized Iterator getParameterNames() {
    175        final ArrayList parameterNames = new ArrayList(this.parameterDefs.keySet());
    176        Collections.sort(parameterNames);
    177        return new ReadOnlyIterator (parameterNames.iterator());
    178    }
    179
    180    /**
    181     * Returns an iterator for the parameter names.
    182     *
    183     * @return The iterator.
    184     */
    185    protected Iterator getDefinedParameterNames() {
    186        return new ReadOnlyIterator (this.parameters.keySet().iterator());
    187    }
    188
    189    /**
    190     * Returns a parameter value.
    191     *
    192     * @param name  the parameter name.
    193     *
    194     * @return The parameter value.
    195     */
    196    public Object getParameter(final String name) {
    197        return this.parameters.get(name);
    198    }
    199
    200    /**
    201     * Returns the class for the object.
    202     *
    203     * @return The class.
    204     */
    205    public Class getObjectClass() {
    206        return this.className;
    207    }
    208
    209    /**
    210     * Returns a cloned instance of the object description. The contents
    211     * of the parameter objects collection are cloned too, so that any
    212     * already defined parameter value is copied to the new instance.
    213     * <p>
    214     * Parameter definitions are not cloned, as they are considered read-only.
    215     * <p>
    216     * The newly instantiated object description is not configured. If it
    217     * need to be configured, then you have to call configure on it.
    218     *
    219     * @return A cloned instance.
    220     */
    221    public ObjectDescription getInstance() {
    222        try {
    223            final AbstractObjectDescription c = (AbstractObjectDescription) super.clone();
    224            c.parameters = (HashMap) this.parameters.clone();
    225            return c;
    226        }
    227        catch (Exception e) {
    228            Log.error("Should not happen: Clone Error: ", e);
    229            return null;
    230        }
    231    }
    232
    233
    234    /**
    235     * Returns a cloned instance of the object description. The contents
    236     * of the parameter objects collection are cloned too, so that any
    237     * already defined parameter value is copied to the new instance.
    238     * <p>
    239     * Parameter definitions are not cloned, as they are considered read-only.
    240     * <p>
    241     * The newly instantiated object description is not configured. If it
    242     * need to be configured, then you have to call configure on it.
    243     *
    244     * @return A cloned instance.
    245     */
    246    public ObjectDescription getUnconfiguredInstance() {
    247        try {
    248            final AbstractObjectDescription c = (AbstractObjectDescription) super.clone();
    249            c.parameters = (HashMap) this.parameters.clone();
    250            c.config = null;
    251            return c;
    252        }
    253        catch (Exception e) {
    254            Log.error("Should not happen: Clone Error: ", e);
    255            return null;
    256        }
    257    }
    258
    259    /**
    260     * Configures this factory. The configuration contains several keys and
    261     * their defined values. The given reference to the configuration object
    262     * will remain valid until the report parsing or writing ends.
    263     * <p>
    264     * The configuration contents may change during the reporting.
    265     *
    266     * @param config the configuration, never null
    267     */
    268    public void configure(final Configuration config) {
    269        if (config == null) {
    270            throw new NullPointerException("The given configuration is null");
    271        }
    272        this.config = config;
    273    }
    274
    275    /**
    276     * Returns the configuration for that object description.
    277     *
    278     * @return the configuration or null, if not yet set.
    279     */
    280    public Configuration getConfig() {
    281        return this.config;
    282    }
    283
    284    /**
    285     * Tests for equality.
    286     *
    287     * @param o  the object to test.
    288     *
    289     * @return A boolean.
    290     */
    291    public boolean equals(final Object o) {
    292        if (this == o) {
    293            return true;
    294        }
    295        if (!(o instanceof AbstractObjectDescription)) {
    296            return false;
    297        }
    298
    299        final AbstractObjectDescription abstractObjectDescription = (AbstractObjectDescription) o;
    300
    301        if (!this.className.equals(abstractObjectDescription.className)) {
    302            return false;
    303        }
    304
    305        return true;
    306    }
    307
    308    /**
    309     * Returns a hash code for the object.
    310     *
    311     * @return The hash code.
    312     */
    313    public int hashCode() {
    314        return this.className.hashCode();
    315    }
    316}