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    
044    package org.jfree.xml.factory.objects;
045    
046    import java.util.ArrayList;
047    import java.util.Collections;
048    import java.util.HashMap;
049    import java.util.Iterator;
050    
051    import org.jfree.util.Configuration;
052    import org.jfree.util.Log;
053    import org.jfree.util.ReadOnlyIterator;
054    
055    /**
056     * An abstract base class for object descriptions.
057     *
058     * @author Thomas Morgner.
059     */
060    public 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    }