/*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/exse/ lat/lon GmbH http://www.lat-lon.de It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite Institut de Recherche pour le D�veloppement / US-Espace mailto:seasnet@teledetection.fr 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53115 Bonn Germany E-Mail: poth@lat-lon.de Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: klaus.greve@uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.model.csct.resources; // Standard set of Java objects. import java.util.Date; /** * Transforme un objet d'une classe vers une autre. Cette classe sert principalement * � convertir en {@link Number} des objets d'une autre classe, par exemple {@link Date}. Une m�thode * statique, {@link #toNumber}, se charge d'effectuer ce genre de conversion en prenant en compte toutes * les classes qui auront �t� d�clar�es � <code>ClassChanger</code>. * <br><br> * Pour d�clarer une nouvelle classe, on peut proc�der comme suit. L'exemple ci-dessous * inscrit une classe qui convertira des objets {@link Date} en objets {@link Long}. Notez qu'il ne s'agit * que d'un exemple. Ce convertisseur n'a pas besoin d'�tre d�clar� car <code>ClassChanger</code> comprend * d�j� les objets {@link Date} par d�faut.</p> * * <blockquote><pre> *  ClassChanger.register(new ClassChanger(Date.class, Long.class) *  { *   protected Number convert(final Comparable o) *   {return new Long(((Date) o).getTime());} *   *   protected Comparable inverseConvert(final Number number) *   {return new Date(number.longValue());} *  }); * </pre></blockquote> * * @version 1.0 * @author Martin Desruisseaux */ public abstract class ClassChanger { /** * Liste des classes d'objets pouvant �tre convertis en nombre. Cette liste contiendra * par d�faut quelques instances de {@link ClassChanger} pour quelques classes standards * du Java, telle que {@link Date}. Toutefois, d'autres objets pourront �tre ajout�s par * la suite. Cette liste est <u>ordonn�e</u>. Les classe le plus hautes dans la hierarchie * (les classes parentes) doivent appara�tre � la fin. */ private static ClassChanger[] list=new ClassChanger[] { new ClassChanger(Date.class, Long.class) { protected Number convert(final Comparable object) {return new Long(((Date) object).getTime());} protected Comparable inverseConvert(final Number value) {return new Date(value.longValue());} } }; /** * Parent class for {@link #convert}'s input objects. */ private final Class source; /** * Parent class for {@link #convert}'s output objects. */ private final Class target; /** * Construct a new class changer. * * @param source Parent class for {@link #convert}'s input objects. * @param target Parent class for {@link #convert}'s output objects. */ protected ClassChanger(final Class source, final Class target) { this.source = source; this.target = target; if (!Comparable.class.isAssignableFrom(source)) { throw new IllegalArgumentException(String.valueOf(source)); } if (!Number.class.isAssignableFrom(target)) { throw new IllegalArgumentException(String.valueOf(target)); } } /** * Returns the numerical value for an object. * * @param object Object to convert (may be null). * @return The object's numerical value. * @throws ClassCastException if <code>object</code> is not of the expected class. */ protected abstract Number convert(final Comparable object) throws ClassCastException; /** * Returns an instance of the converted classe from a numerical value. * * @param value The value to wrap. * @return An instance of the source classe. */ protected abstract Comparable inverseConvert(final Number value); /** * Returns a string representation for this class changer. */ public String toString() {return "ClassChanger["+source.getName()+"\u00A0\u21E8\u00A0"+target.getName()+']';} /** * Inscrit un nouvel objet <code>ClassChanger</code>. Les objets <code>ClassChanger</code> inscrits * ici seront pris en compte par la m�thode {@link #toNumber}. Si un objet <code>ClassChanger</code> * existait d�j� pour une m�me classe, une exception sera lanc�e. Cette sp�cification est justifi�e * par le fait qu'on enregistre souvent un objet <code>ClassChanger</code> lors de l'initialisation * d'une classe qui vient d'�tre charg�e pour la premi�re fois. En interdisant tout changements aux * objets <code>ClassChanger</code> apr�s l'initialisation d'une classe, on �vite que la fa�on de * convertir des objets en nombres r�els ne change au cours d'une ex�cution de la machine virtuelle. * Notez que si <code>converter</code> ne peut pas prendre en charge une m�me classe que celle d'un * autre objet <code>ClassChanger</code>, il peut toutefois prendre en charge une classe parente ou * une classe fille. * * @param converter Convertisseur � ajouter � la liste des convertisseurs d�j� existants. * @throws IllegalStateException si un autre objet <code>ClassChanger</code> prennait d�j� * en charge la m�me classe (l'argument <code>classe</code> d�clar� au constructeur) * que <code>converter</code>. */ public static synchronized void register(final ClassChanger converter) throws IllegalStateException { int i; for (i=0; i<list.length; i++) { if (list[i].source.isAssignableFrom(converter.source)) { /* * On a trouv� un convertisseur qui utilisait * une classe parente. Le nouveau convertisseur * devra s'ins�rer avant son parent. Mais on va * d'abord s'assurer qu'il n'existait pas d�j� * un convertisseur pour cette classe. */ for (int j=i; j<list.length; j++) { if (list[j].source.equals(converter.source)) { throw new IllegalStateException(list[j].toString()); } } break; } } list = (ClassChanger[]) XArray.insert(list, i, 1); list[i] = converter; } /** * Returns the class changer for the specified classe. * * @throws ClassNotFoundException if <code>source</code> is not a registered class. */ private static synchronized ClassChanger getClassChanger(final Class source) throws ClassNotFoundException { for (int i=0; i<list.length; i++) if (list[i].source.isAssignableFrom(source)) return list[i]; throw new ClassNotFoundException(source.getName()); } /** * Returns the target class for the specified source class, if a suitable transformation is known. * The source class is a {@link Comparable} subclass that will be specified as input to {@link #convert}. * The target class is a {@link Number} subclass that wimm be returned as output by {@link #convert}. * If no suitable mapping is found, then <code>source</code> is returned. */ public static Class getTransformedClass(final Class source) { if (source!=null) for (int i=0; i<list.length; i++) if (list[i].source.isAssignableFrom(source)) return list[i].target; return source; } /** * Returns the numeric value for the specified object. For example the code * <code>toNumber(new Date())</code> returns the {@link Date#getTime()} * value of the specified date object as a {@link Long}. * * @param object Object to convert (may be null). * @return <code>null</code> if <code>object</code> was null; otherwise * <code>object</code> if the supplied object is already an instance * of {@link Number}; otherwise a new number with the numerical value. * @throws ClassNotFoundException if <code>object</code> is not an instance of a registered class. */ public static Number toNumber(final Comparable object) throws ClassNotFoundException { if (object!=null) { if (object instanceof Number) { return (Number) object; } return getClassChanger(object.getClass()).convert(object); } return null; } /** * Wrap the specified number as an instance of the specified classe. * For example <code>toComparable(Date.class, new Long(time))</code> * is equivalent to <code>new Date(time)</code>. There is of course no * point to use this method if the destination class is know at compile time. * This method is useful for creating instance of classes choosen dynamically * at run time. * * @param value The numerical value (may be null). * @param classe The desired classe for return value. * @throws ClassNotFoundException if <code>classe</code> is not a registered class. */ public static Comparable toComparable(final Number value, final Class classe) throws ClassNotFoundException { if (value!=null) { if (Number.class.isAssignableFrom(classe)) { return (Comparable)value; } return getClassChanger(classe).inverseConvert(value); } return null; } }