Index: lutinutil/src/java/org/codelutin/util/FormatConverter.java diff -u /dev/null lutinutil/src/java/org/codelutin/util/FormatConverter.java:1.1 --- /dev/null Tue Sep 20 14:32:21 2005 +++ lutinutil/src/java/org/codelutin/util/FormatConverter.java Tue Sep 20 14:32:16 2005 @@ -0,0 +1,94 @@ +/* *##% + * Copyright (C) 2005 + * Code Lutin, Cédric Pineau, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ + +/* * + * FormatConverter.java + * + * Created: 14 septembre 2005 00:55:19 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/09/20 14:32:16 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.util; + +import java.util.Map; +import org.codelutin.util.FormatMap.Format; + +/** +* Un converter est un objet qui permet de passé d'une representation d'un +* objet vers une autre representation. Le mininum que converter doit savoir +* faire, est de converter une representation Java vers le format qu'il +* gère et inversement. Pour des raisons d'optimisation, il est possible +* qu'un converter sache passé d'un autre type que java vers sa representation +* pour eviter une conversion supplémentaire qui pourrait-etre couteuse. +*/ +public interface FormatConverter { // FormatConverter + + static final public Format FORMAT_JAVA = new Format("Format Java"); + + /** + * Convertie une valeur vers la representation FORMAT géré par cette classe + * @param factory la factory utilisable pour rechercher d'autre converter + * si la representation Java n'est pas presente dans values et que l'on + * en a besoin + * @param format le format souhaité en sortie + * @param values une map contenant les différentes representation de la + * meme valeur. Les cles de la map sont les valeurs retournés par la + * methode {@link #getFormat()}. + * @param args des arguments qui peuvent-être utile pour la conversion. + * par exemple si dans une application on a construit son propre + * converter et que pour la conversion, on a besoin d'un Context applicatif + * il peut-etre passé dans les args. Si le converter a besoin d'autre + * converter les memes args lui seront passé. + * @return l'objet dans la representation demandés par type + * @throws IllegalArgumentException si auncun moyen n'est trouve pour + * convertir une des valeurs de values dans le format géré par cette classe. + * Ou s'il manque dans les args des objets utils pour la conversion. + */ + public Object convert(FormatConverterFactory factory, + Format format, FormatMap values, Object ... args); + + /** + * Convertie une valeur vers le Java + * @param factory la factory utilisable pour rechercher d'autre converter + * si la representation Java n'est pas presente dans values et que l'on + * en a besoin + * @param format le format à utiliser comme valeur d'entré + * @param values une map contenant les différentes representation de la + * meme valeur. La valeur interessante dans la map pour cette methode + * est celle retournée par values.get(getFormat()) si cet appel, ne + * retourne pas quelque chose de valid, la methode doit lever une exception + * @param args des arguments qui peuvent-être utile pour la conversion. + * par exemple si dans une application on a construit son propre + * converter et que pour la conversion, on a besoin d'un Context applicatif + * il peut-etre passé dans les args. Si le converter a besoin d'autre + * converter les memes args lui seront passé. + * @throws IllegalArgumentException si le format géré par cette classe n'est + * pas trouvé dans les values. Ou s'il manque dans les args des objets utils + * pour la conversion. + */ + public Object unconvert(FormatConverterFactory factory, + Format format, FormatMap values, Object ... args); + +} // FormatConverter + Index: lutinutil/src/java/org/codelutin/util/FormatConverterFactory.java diff -u /dev/null lutinutil/src/java/org/codelutin/util/FormatConverterFactory.java:1.1 --- /dev/null Tue Sep 20 14:32:21 2005 +++ lutinutil/src/java/org/codelutin/util/FormatConverterFactory.java Tue Sep 20 14:32:16 2005 @@ -0,0 +1,194 @@ +/* *##% + * Copyright (C) 2005 + * Code Lutin, Cédric Pineau, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ + +/* * + * FormatConverterFactory.java + * + * Created: 14 septembre 2005 00:19:51 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/09/20 14:32:16 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.util; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import org.apache.commons.collections.map.MultiKeyMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.util.FormatMap.Format; + +/** +* Factory permet d'enregistrer des objets de changement de format, et de +* les recupérer pour les utiliser. +* Les objets converter doivent au moins savoir convertir les objets depuis +* une representation Java. Pour des raisons d'optimisation, il est possible +* qu'il sache aussi convertir a partir d'autre representation, qui si elle +* existe sont moins couteuse a convertir. +* Il faut aussi que les converter sache convertir de leur representation vers +* un objet Java. +* par exemple si on enregistre les converiseurs suivant: +*
+* addConverter(new MatrixToXMLFormatConverter());
+* addConverter(new MatrixToSQLFormatConverter());
+* FormatConverterFactory.convert(Matrix.class, MatrixToXMLFormatConverter.TYPE,
+*    values, AppContext);
+* 
+* Dans ce cas pour des raisons d'optimisation +*/ +public class FormatConverterFactory { // FormatConverterFactory + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(FormatConverterFactory.class); + + static protected FormatConverterFactory instance = null; + /** FormatConverter> */ + protected MultiKeyMap converters = new MultiKeyMap(); + + synchronized static public FormatConverterFactory getInstance(){ + if (instance == null) { + instance = new FormatConverterFactory(); + } + return instance; + } + + /** + * Permet d'enregitrer un converter pour permettre la convertion d'une + * certain type Java d'une representation vers une autre. + * par exemple le type String d'un objet Java vers une chaine XML + * @param clazz la class de la representation Java de l'objet + * @param format le format géré par le FormatConverter + * @param c le converter a enregistrer + */ + public void addConverter(Class clazz, Format format, FormatConverter c) { + converters.put(clazz, format, c); + } + + /** + * permet de recupere le converter pour la classe souhaitée. + * @param clazz la classe de l'objet dont on souhaite le converter + * @param format qui doit être géré par le converter + * @param defaultConverter si aucun converter trouvé, ce converter est + * retourné + * @return le converter souhaité ou defaultConverter + */ + public FormatConverter getConverter(Class clazz, Format format, + FormatConverter defaultConverter) { + FormatConverter result = (FormatConverter)converters.get(clazz, format); + if(result == null){ + result = defaultConverter; + } + return result; + } + + /** + * @return retourne null si aucun converter trouvé + * @see #getConverter(Class, Object, FormatConverter) + */ + public FormatConverter getConverter(Class clazz, Format format){ + return getConverter(clazz, format, null); + } + + /** + * Permet de retrouver le meilleur converter disponible pour l'argument + * clazz + * @param clazz la classe de l'objet dont on souhaite le converter + * @param format qui doit être géré par le converter + * @param defaultConverter si aucun converter trouvé, ce converter est + * retourné + * @return le converter souhaité ou defaultConverter + */ + public FormatConverter findConverter(Class clazz, Format format, + FormatConverter defaultConverter) { + FormatConverter result = null; + + LinkedList interfaces = new LinkedList(); + // On recherche la le transformer le plus spécifique sur les Class + Class parent = clazz; + while(result == null && parent != null){ + Collections.addAll(interfaces, parent.getInterfaces()); + result = getConverter(parent, format); + parent = parent.getSuperclass(); + } + + // Si on a pas encore trouve de transformer on recherche + // un encodeur/decodeur pour les interfaces + for(Iterator i=interfaces.iterator(); result==null && i.hasNext();){ + result = getConverter(i.next(), format); + } + + if (result == null) { + log.warn("Aucun converter trouvé pour le type: " + clazz); + result = defaultConverter; + } + log.debug("converter " + result + " utilisé pour le type: " + clazz); + + return result; + } + + /** + * @return retourne null si aucun converter trouvé + * @see #findConverter(Class, Object, FormatConverter) + */ + public FormatConverter findConverter(Class clazz, Format format) { + return findConverter(clazz, format, null); + } + + public Object convert(Format format, FormatMap values, Object ... args) { + FormatConverter c = findConverter(values.getType(), format); + if(c == null){ + throw new IllegalArgumentException("Aucun converter utilisable pour les arguments donnés class: " + values.getType().getName() + " format: " + format); + } + return c.convert(this, format, values, args); + } + + public Object unconvert(Format format, FormatMap values, Object ... args) { + FormatConverter c = findConverter(values.getType(), format); + if(c == null){ + throw new IllegalArgumentException("Aucun converter utilisable pour les arguments donnés"); + } + return c.unconvert(this, format, values, args); + } + + public Object convert(FormatConverter defaultConverter, + Format format, FormatMap values, Object ... args) { + FormatConverter c = findConverter(values.getType(), format); + if(c == null){ + c = defaultConverter; + } + return c.convert(this, format, values, args); + } + + public Object unconvert(FormatConverter defaultConverter, + Format format, FormatMap values, Object ... args) { + FormatConverter c = findConverter(values.getType(), format); + if(c == null){ + c = defaultConverter; + } + return c.unconvert(this, format, values, args); + } + +} // FormatConverterFactory + Index: lutinutil/src/java/org/codelutin/util/FormatMap.java diff -u /dev/null lutinutil/src/java/org/codelutin/util/FormatMap.java:1.1 --- /dev/null Tue Sep 20 14:32:21 2005 +++ lutinutil/src/java/org/codelutin/util/FormatMap.java Tue Sep 20 14:32:16 2005 @@ -0,0 +1,169 @@ +/* *##% + * Copyright (C) 2005 + * Code Lutin, Cédric Pineau, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ + +/* * + * FormatMap.java + * + * Created: 16 septembre 2005 10:41:58 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/09/20 14:32:16 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.util; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.util.FormatMap.Format; +/** +* Classe servant de conteneur pour les différentes representation d'un objet +* Les representations doivents être des instances de {@link #Format}. Le mieux +* est lors de l'ecriture des convertisseurs pour un nouveau format est de +* créer une instance final static de {@link #Format} Format pour representer +* ce format +* +*

Utilisation

+*
+* FormatMap values = new FormatMap(MonObject.class);
+* values.put(FormatConverter.FORMAT_JAVA, monInstance);
+* Element xml = (Element)values.convert(XMLConverter.FORMAT_XML);
+* Object sql = values.convert(SQLConverter.FORMAT_SQL);
+* 
+*
+* FormatMap values = new FormatMap(MonObject.class);
+* values.put(FormatConverter.FORMAT_XML, monInstanceEnXML);
+* Object sql = values.convert(SQLConverter.FORMAT_SQL);
+* 
+* Dans ce second cas, la demande de la version SQL, transforme automatiquement +* la representation XML qui est la seul presente en Java, puis a partir de +* cette representation Java, on recupere la representation SQL. Bien sur +* Si le convertisseur SQL, peut directement convertir le XML en SQL, alors +* la conversion Java ne sera pas faite. +*

+* Il est souvent plus simple de faire une petite classe avec les methodes +* getSQL() et getXML(), qui retourne les valeurs directement dans le bon type +* et qui n'ont pas besoin d'argument. +*/ +public class FormatMap extends HashMap { // FormatMap + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(FormatMap.class); + + static public class Format { + protected String name = null; + public Format(String name) { + this.name = name; + } + public String toString(){ + return name; + } + } + + protected Class clazz = null; + + public FormatMap(Class clazz){ + this.clazz = clazz; + } + + public Class getType(){ + return clazz; + } + + /** + * Utilise le FormatConverterFactory par defaut pour la conversion + */ + public Object convert(Format format, Object ... args){ + return convert(FormatConverterFactory.getInstance(), format, args); + } + + /** + * Recupere la valeur dans le format demandé + * @param factory la FormatConverterFactory a utiliser + * @param format le format souhaité + * @param args des arguments facultatifs en fonction du context d'utilisation + */ + public Object convert(FormatConverterFactory factory, Format format, + Object ... args){ + Object result = null; + Map values = this; + //if (!values.containsKey(format) || + // !format.equals(FormatConverter.FORMAT_JAVA)) { + // throw new IllegalArgumentException("Aucun valeur disponible"); + //} + + if (values.containsKey(format)) { + result = values.get(format); + } else if (format.equals(FormatConverter.FORMAT_JAVA)) { + // on recherche une representation, que l'on convertie en Java + if (values.isEmpty()){ + throw new IllegalArgumentException("Aucun valeur disponible"); + } + Format otherFormat = values.keySet().iterator().next(); + result = unconvert(factory, otherFormat, args); + values.put(format, result); + } else { + result = factory.convert(format, this, args); + // on stocke la valeur trouver pour les prochaines fois + values.put(format, result); + } + + return result; + } + + /** + * Utilise le FormatConverterFactory par defaut pour la conversion + */ + public Object unconvert(Format format, Object ... args){ + return unconvert(FormatConverterFactory.getInstance(), format, args); + } + + /** + * Donne la representation Java de l'objet en essayant de partir de la + * representation passé en parametre. + * @param factory la factory a utiliser + * @param format le format de départ souhaité + * @param args des arguments facultatifs en fonction du context d'utilisation + */ + public Object unconvert(FormatConverterFactory factory, Format format, + Object ... args){ + Object result = null; + Map values = this; + if (!values.containsKey(format) && + !values.containsKey(FormatConverter.FORMAT_JAVA)) { + throw new IllegalArgumentException("Aucun valeur disponible"); + } + + // si on a deja la representation Java on la retourne tout de suite + if (values.containsKey(FormatConverter.FORMAT_JAVA)) { + result = values.get(FormatConverter.FORMAT_JAVA); + } else if (values.containsKey(format)){ + result = factory.unconvert(format, this, args); + values.put(FormatConverter.FORMAT_JAVA, result); + } + + return result; + } + +} // FormatMap +