content: /* ========================================================================
   * JCommon : a free general purpose class library for the Java(tm) platform
   * ========================================================================
   *
   * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   * 
   * Project Info:  http://www.jfree.org/jcommon/index.html
   *
   * This library is free software; you can redistribute it and/or modify it 
   * under the terms of the GNU Lesser General Public License as published by 
   * the Free Software Foundation; either version 2.1 of the License, or 
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but 
   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
   * License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
   * USA.  
   *
   * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
   * in the United States and other countries.]
   * 
   * ------------------------------
   * AbstractObjectDescription.java
   * ------------------------------
   * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
   *
   * Original Author:  Thomas Morgner;
   * Contributor(s):   David Gilbert (for Object Refinery Limited);
   *
   * $Id: AbstractObjectDescription.java,v 1.3 2005/11/14 10:58:37 mungady Exp $
   *
   * Changes (from 19-Feb-2003)
   * -------------------------
   * 19-Feb-2003 : Added standard header and Javadocs (DG);
   * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
   *
   */
  
  package org.jfree.xml.factory.objects;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.jfree.util.Configuration;
  import org.jfree.util.Log;
  import org.jfree.util.ReadOnlyIterator;
  
  /**
   * An abstract base class for object descriptions.
   *
   * @author Thomas Morgner.
   */
  public abstract class AbstractObjectDescription implements ObjectDescription, Cloneable {
  
      /** The class. */
      private Class className;
  
      /** Storage for parameters. */
      private HashMap parameters;
  
      /** Storage for parameter definitions. */
      private HashMap parameterDefs;
  
      /** The configuration for the object description. */
      private Configuration config;
  
      /**
       * Creates a new object description.
       *
       * @param className  the class.
       */
      public AbstractObjectDescription(final Class className) {
          this.className = className;
          this.parameters = new HashMap();
          this.parameterDefs = new HashMap();
      }
  
      /**
       * Returns a parameter class.
       *
       * @param name  the parameter definition.
       *
       * @return The class.
       */
      public Class getParameterDefinition(final String name) {
          return (Class) this.parameterDefs.get(name);
      }
  
      /**
       * Sets the class for a parameter.
       *
       * @param name  the parameter name.
       * @param obj  the parameter class.
       */
      public void setParameterDefinition(final String name, final Class obj) {
          if (obj == null) {
              this.parameterDefs.remove(name);
          }
          else {
              this.parameterDefs.put(name, obj);
          }
      }
  
      /**
       * Converts primitives to corresponding object class.
       *
       * @param obj  the class.
       *
       * @return The class.
       */
      public static Class convertPrimitiveClass(final Class obj) {
          if (!obj.isPrimitive()) {
              return obj;
          }
          if (obj == Boolean.TYPE) {
              return Boolean.class;
          }
          if (obj == Byte.TYPE) {
              return Byte.class;
          }
          if (obj == Character.TYPE) {
              return Character.class;
          }
          if (obj == Short.TYPE) {
              return Short.class;
          }
          if (obj == Integer.TYPE) {
              return Integer.class;
          }
          if (obj == Long.TYPE) {
              return Long.class;
          }
          if (obj == Float.TYPE) {
              return Float.class;
          }
          if (obj == Double.TYPE) {
              return Double.class;
          }
          throw new IllegalArgumentException("Class 'void' is not allowed here");
      }
  
      /**
       * Sets a parameter.
       *
       * @param name  the name.
       * @param value  the value.
       */
      public void setParameter(final String name, final Object value) {
          if (getParameterDefinition(name) == null) {
              throw new IllegalArgumentException("No such Parameter defined: " + name
                  + " in class " + getObjectClass());
          }
          final Class parameterClass = convertPrimitiveClass(getParameterDefinition(name));
          if (!parameterClass.isAssignableFrom(value.getClass())) {
              throw new ClassCastException("In Object " + getObjectClass()
                  + ": Value is not assignable: " + value.getClass()
                  + " is not assignable from " + parameterClass);
          }
          this.parameters.put(name, value);
      }
  
      /**
       * Returns an iterator for the parameter names.
       *
       * @return The iterator.
       */
      public synchronized Iterator getParameterNames() {
          final ArrayList parameterNames = new ArrayList(this.parameterDefs.keySet());
          Collections.sort(parameterNames);
          return new ReadOnlyIterator (parameterNames.iterator());
      }
  
      /**
       * Returns an iterator for the parameter names.
       *
       * @return The iterator.
       */
      protected Iterator getDefinedParameterNames() {
          return new ReadOnlyIterator (this.parameters.keySet().iterator());
      }
  
      /**
       * Returns a parameter value.
       *
       * @param name  the parameter name.
       *
       * @return The parameter value.
       */
      public Object getParameter(final String name) {
          return this.parameters.get(name);
      }
  
      /**
       * Returns the class for the object.
       *
       * @return The class.
       */
      public Class getObjectClass() {
          return this.className;
      }
  
      /**
       * Returns a cloned instance of the object description. The contents
       * of the parameter objects collection are cloned too, so that any
       * already defined parameter value is copied to the new instance.
       * <p>
       * Parameter definitions are not cloned, as they are considered read-only.
       * <p>
       * The newly instantiated object description is not configured. If it
       * need to be configured, then you have to call configure on it.
       *
       * @return A cloned instance.
       */
      public ObjectDescription getInstance() {
          try {
              final AbstractObjectDescription c = (AbstractObjectDescription) super.clone();
              c.parameters = (HashMap) this.parameters.clone();
              return c;
          }
          catch (Exception e) {
              Log.error("Should not happen: Clone Error: ", e);
              return null;
          }
      }
  
  
      /**
       * Returns a cloned instance of the object description. The contents
       * of the parameter objects collection are cloned too, so that any
       * already defined parameter value is copied to the new instance.
       * <p>
       * Parameter definitions are not cloned, as they are considered read-only.
       * <p>
       * The newly instantiated object description is not configured. If it
       * need to be configured, then you have to call configure on it.
       *
       * @return A cloned instance.
       */
      public ObjectDescription getUnconfiguredInstance() {
          try {
              final AbstractObjectDescription c = (AbstractObjectDescription) super.clone();
              c.parameters = (HashMap) this.parameters.clone();
              c.config = null;
              return c;
          }
          catch (Exception e) {
              Log.error("Should not happen: Clone Error: ", e);
              return null;
          }
      }
  
      /**
       * Configures this factory. The configuration contains several keys and
       * their defined values. The given reference to the configuration object
       * will remain valid until the report parsing or writing ends.
       * <p>
       * The configuration contents may change during the reporting.
       *
       * @param config the configuration, never null
       */
      public void configure(final Configuration config) {
          if (config == null) {
              throw new NullPointerException("The given configuration is null");
          }
          this.config = config;
      }
  
      /**
       * Returns the configuration for that object description.
       *
       * @return the configuration or null, if not yet set.
       */
      public Configuration getConfig() {
          return this.config;
      }
  
      /**
       * Tests for equality.
       * 
       * @param o  the object to test.
       * 
       * @return A boolean.
       */
      public boolean equals(final Object o) {
          if (this == o) {
              return true;
          }
          if (!(o instanceof AbstractObjectDescription)) {
              return false;
          }
  
          final AbstractObjectDescription abstractObjectDescription = (AbstractObjectDescription) o;
  
          if (!this.className.equals(abstractObjectDescription.className)) {
              return false;
          }
  
          return true;
      }
  
      /**
       * Returns a hash code for the object.
       * 
       * @return The hash code.
       */
      public int hashCode() {
          return this.className.hashCode();
      }
  }
  