001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/resources/ClassChanger.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/exse/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification 012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) 013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite 014 Institut de Recherche pour le D�veloppement / US-Espace 015 mailto:seasnet@teledetection.fr 016 017 018 This library is free software; you can redistribute it and/or 019 modify it under the terms of the GNU Lesser General Public 020 License as published by the Free Software Foundation; either 021 version 2.1 of the License, or (at your option) any later version. 022 023 This library is distributed in the hope that it will be useful, 024 but WITHOUT ANY WARRANTY; without even the implied warranty of 025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 026 Lesser General Public License for more details. 027 028 You should have received a copy of the GNU Lesser General Public 029 License along with this library; if not, write to the Free Software 030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 031 032 Contact: 033 034 Andreas Poth 035 lat/lon GmbH 036 Aennchenstr. 19 037 53115 Bonn 038 Germany 039 E-Mail: poth@lat-lon.de 040 041 Klaus Greve 042 Department of Geography 043 University of Bonn 044 Meckenheimer Allee 166 045 53115 Bonn 046 Germany 047 E-Mail: klaus.greve@uni-bonn.de 048 049 050 ---------------------------------------------------------------------------*/ 051 package org.deegree.model.csct.resources; 052 053 // Standard set of Java objects. 054 import java.util.Date; 055 056 /** 057 * Transforme un objet d'une classe vers une autre. Cette classe sert principalement � convertir en 058 * {@link Number} des objets d'une autre classe, par exemple {@link Date}. Une m�thode statique, 059 * {@link #toNumber}, se charge d'effectuer ce genre de conversion en prenant en compte toutes les 060 * classes qui auront �t� d�clar�es � <code>ClassChanger</code>. <br> 061 * <br> 062 * Pour d�clarer une nouvelle classe, on peut proc�der comme suit. L'exemple ci-dessous inscrit une 063 * classe qui convertira des objets {@link Date} en objets {@link Long}. Notez qu'il ne s'agit que 064 * d'un exemple. Ce convertisseur n'a pas besoin d'�tre d�clar� car <code>ClassChanger</code> 065 * comprend d�j� les objets {@link Date} par d�faut. 066 * </p> 067 * 068 * <blockquote> 069 * 070 * <pre> 071 * ClassChanger.register( new ClassChanger( Date.class, Long.class ) { 072 * protected Number convert( final Comparable o ) { 073 * return new Long( ( (Date) o ).getTime() ); 074 * } 075 * 076 * protected Comparable inverseConvert( final Number number ) { 077 * return new Date( number.longValue() ); 078 * } 079 * } ); 080 * </pre> 081 * 082 * </blockquote> 083 * 084 * @version 1.0 085 * @author Martin Desruisseaux 086 */ 087 public abstract class ClassChanger { 088 /** 089 * Liste des classes d'objets pouvant �tre convertis en nombre. Cette liste contiendra par 090 * d�faut quelques instances de {@link ClassChanger} pour quelques classes standards du Java, 091 * telle que {@link Date}. Toutefois, d'autres objets pourront �tre ajout�s par la suite. Cette 092 * liste est <u>ordonn�e</u>. Les classe le plus hautes dans la hierarchie (les classes 093 * parentes) doivent appara�tre � la fin. 094 */ 095 private static ClassChanger[] list = new ClassChanger[] { new ClassChanger( Date.class, Long.class ) { 096 protected Number convert( final Comparable object ) { 097 return new Long( ( (Date) object ).getTime() ); 098 } 099 100 protected Comparable inverseConvert( final Number value ) { 101 return new Date( value.longValue() ); 102 } 103 } }; 104 105 /** 106 * Parent class for {@link #convert}'s input objects. 107 */ 108 private final Class source; 109 110 /** 111 * Parent class for {@link #convert}'s output objects. 112 */ 113 private final Class target; 114 115 /** 116 * Construct a new class changer. 117 * 118 * @param source 119 * Parent class for {@link #convert}'s input objects. 120 * @param target 121 * Parent class for {@link #convert}'s output objects. 122 */ 123 protected ClassChanger( final Class source, final Class target ) { 124 this.source = source; 125 this.target = target; 126 if ( !Comparable.class.isAssignableFrom( source ) ) { 127 throw new IllegalArgumentException( String.valueOf( source ) ); 128 } 129 if ( !Number.class.isAssignableFrom( target ) ) { 130 throw new IllegalArgumentException( String.valueOf( target ) ); 131 } 132 } 133 134 /** 135 * Returns the numerical value for an object. 136 * 137 * @param object 138 * Object to convert (may be null). 139 * @return The object's numerical value. 140 * @throws ClassCastException 141 * if <code>object</code> is not of the expected class. 142 */ 143 protected abstract Number convert( final Comparable object ) 144 throws ClassCastException; 145 146 /** 147 * Returns an instance of the converted classe from a numerical value. 148 * 149 * @param value 150 * The value to wrap. 151 * @return An instance of the source classe. 152 */ 153 protected abstract Comparable inverseConvert( final Number value ); 154 155 /** 156 * Returns a string representation for this class changer. 157 */ 158 public String toString() { 159 return "ClassChanger[" + source.getName() + "\u00A0\u21E8\u00A0" + target.getName() + ']'; 160 } 161 162 /** 163 * Inscrit un nouvel objet <code>ClassChanger</code>. Les objets <code>ClassChanger</code> 164 * inscrits ici seront pris en compte par la m�thode {@link #toNumber}. Si un objet 165 * <code>ClassChanger</code> existait d�j� pour une m�me classe, une exception sera lanc�e. 166 * Cette sp�cification est justifi�e par le fait qu'on enregistre souvent un objet 167 * <code>ClassChanger</code> lors de l'initialisation d'une classe qui vient d'�tre charg�e 168 * pour la premi�re fois. En interdisant tout changements aux objets <code>ClassChanger</code> 169 * apr�s l'initialisation d'une classe, on �vite que la fa�on de convertir des objets en nombres 170 * r�els ne change au cours d'une ex�cution de la machine virtuelle. Notez que si 171 * <code>converter</code> ne peut pas prendre en charge une m�me classe que celle d'un autre 172 * objet <code>ClassChanger</code>, il peut toutefois prendre en charge une classe parente ou 173 * une classe fille. 174 * 175 * @param converter 176 * Convertisseur � ajouter � la liste des convertisseurs d�j� existants. 177 * @throws IllegalStateException 178 * si un autre objet <code>ClassChanger</code> prennait d�j� en charge la m�me 179 * classe (l'argument <code>classe</code> d�clar� au constructeur) que 180 * <code>converter</code>. 181 */ 182 public static synchronized void register( final ClassChanger converter ) 183 throws IllegalStateException { 184 int i; 185 for ( i = 0; i < list.length; i++ ) { 186 if ( list[i].source.isAssignableFrom( converter.source ) ) { 187 /* 188 * On a trouv� un convertisseur qui utilisait une classe parente. Le nouveau 189 * convertisseur devra s'ins�rer avant son parent. Mais on va d'abord s'assurer 190 * qu'il n'existait pas d�j� un convertisseur pour cette classe. 191 */ 192 for ( int j = i; j < list.length; j++ ) { 193 if ( list[j].source.equals( converter.source ) ) { 194 throw new IllegalStateException( list[j].toString() ); 195 } 196 } 197 break; 198 } 199 } 200 list = (ClassChanger[]) XArray.insert( list, i, 1 ); 201 list[i] = converter; 202 } 203 204 /** 205 * Returns the class changer for the specified classe. 206 * 207 * @throws ClassNotFoundException 208 * if <code>source</code> is not a registered class. 209 */ 210 private static synchronized ClassChanger getClassChanger( final Class source ) 211 throws ClassNotFoundException { 212 for ( int i = 0; i < list.length; i++ ) 213 if ( list[i].source.isAssignableFrom( source ) ) 214 return list[i]; 215 throw new ClassNotFoundException( source.getName() ); 216 } 217 218 /** 219 * Returns the target class for the specified source class, if a suitable transformation is 220 * known. The source class is a {@link Comparable} subclass that will be specified as input to 221 * {@link #convert}. The target class is a {@link Number} subclass that wimm be returned as 222 * output by {@link #convert}. If no suitable mapping is found, then <code>source</code> is 223 * returned. 224 */ 225 public static Class getTransformedClass( final Class source ) { 226 if ( source != null ) 227 for ( int i = 0; i < list.length; i++ ) 228 if ( list[i].source.isAssignableFrom( source ) ) 229 return list[i].target; 230 return source; 231 } 232 233 /** 234 * Returns the numeric value for the specified object. For example the code 235 * <code>toNumber(new Date())</code> returns the {@link Date#getTime()} value of the 236 * specified date object as a {@link Long}. 237 * 238 * @param object 239 * Object to convert (may be null). 240 * @return <code>null</code> if <code>object</code> was null; otherwise <code>object</code> 241 * if the supplied object is already an instance of {@link Number}; otherwise a new 242 * number with the numerical value. 243 * @throws ClassNotFoundException 244 * if <code>object</code> is not an instance of a registered class. 245 */ 246 public static Number toNumber( final Comparable object ) 247 throws ClassNotFoundException { 248 if ( object != null ) { 249 if ( object instanceof Number ) { 250 return (Number) object; 251 } 252 return getClassChanger( object.getClass() ).convert( object ); 253 } 254 return null; 255 } 256 257 /** 258 * Wrap the specified number as an instance of the specified classe. For example 259 * <code>toComparable(Date.class, new Long(time))</code> is equivalent to 260 * <code>new Date(time)</code>. There is of course no point to use this method if the 261 * destination class is know at compile time. This method is useful for creating instance of 262 * classes choosen dynamically at run time. 263 * 264 * @param value 265 * The numerical value (may be null). 266 * @param classe 267 * The desired classe for return value. 268 * @throws ClassNotFoundException 269 * if <code>classe</code> is not a registered class. 270 */ 271 public static Comparable toComparable( final Number value, final Class classe ) 272 throws ClassNotFoundException { 273 if ( value != null ) { 274 if ( Number.class.isAssignableFrom( classe ) ) { 275 return (Comparable) value; 276 } 277 return getClassChanger( classe ).inverseConvert( value ); 278 } 279 return null; 280 } 281 }