Author: tchemit Date: 2009-01-05 08:40:44 +0000 (Mon, 05 Jan 2009) New Revision: 1284 Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/BeanPropertyLoador.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Creator.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/DBMapping.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Deletor.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityListUpdator.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityLoador.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Gettor.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/ListUpdator.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Loador.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/TopiaEntityHelper.java Modified: topia/trunk/topia-persistence/changelog.txt topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityAbstractGenerator.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityInterfaceGenerator.java topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/GeneratorUtil.java Log: - utilisation foreach dans les g?\195?\169n?\195?\169rateurs - ajout de m?\195?\169thode getXXXByTopiaId pour les attributs ?\195?\160 multiplicit?\195?\169 dans les entit?\195?\169s (interface et abstract) - fix generic dans les m?\195?\169thodes g?\195?\169n?\195?\169r?\195?\169es - ajout d'un tagValue i18n pour g?\195?\169n?\195?\169rer dans les entit?\195?\169s abstraites les chaines i18n - ajout d'un paquetage org.codelutin.topia.persistence.util avec du code utile :) (javadoc a faire...) Modified: topia/trunk/topia-persistence/changelog.txt =================================================================== --- topia/trunk/topia-persistence/changelog.txt 2008-12-19 13:23:10 UTC (rev 1283) +++ topia/trunk/topia-persistence/changelog.txt 2009-01-05 08:40:44 UTC (rev 1284) @@ -1,3 +1,10 @@ +2.1.2 ??? 200901?? +* 20090104 [chemit] - utilisation foreach dans les générateurs + - ajout de méthode getXXXByTopiaId pour les attributs à multiplicité dans les entités (interface et abstract) + - fix generic dans les méthodes générées + - ajout d'un tagValue i18n pour générer dans les entités abstraites les chaines i18n + - ajout d'un paquetage org.codelutin.topia.persistence.util avec du code utile :) (javadoc a faire...) + 2.1.1 chemit 20081215 * 20081215 [chemit] - new release for isis-fish :) * 20081212 [chemit] - add a InterfaceGenerator to generate simple with no stereotype interfaces. Modified: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityAbstractGenerator.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityAbstractGenerator.java 2008-12-19 13:23:10 UTC (rev 1283) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityAbstractGenerator.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -29,15 +29,6 @@ package org.codelutin.topia.generator; -import static org.codelutin.topia.generator.GeneratorUtil.TAG_ANNOTATION; -import static org.codelutin.topia.generator.GeneratorUtil.hasUnidirectionalRelationOnAbstractType; -import static org.codelutin.topia.generator.GeneratorUtil.shouldBeAbstract; - -import java.io.File; -import java.io.IOException; -import java.io.Writer; -import java.util.Iterator; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codelutin.generator.Generator; @@ -47,8 +38,16 @@ import org.codelutin.generator.models.object.ObjectModelAttribute; import org.codelutin.generator.models.object.ObjectModelClass; import org.codelutin.generator.models.object.ObjectModelClassifier; +import static org.codelutin.topia.generator.GeneratorUtil.TAG_ANNOTATION; +import static org.codelutin.topia.generator.GeneratorUtil.hasUnidirectionalRelationOnAbstractType; +import static org.codelutin.topia.generator.GeneratorUtil.shouldBeAbstract; import org.codelutin.topia.persistence.TopiaEntityAbstract; +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; + /** * Generateur d'entites abstraites. Il s'agit de l'implatation par defaut d'une * entite. Les classes generees sont surchargees par un XXXImpl lorsque l'entite @@ -56,9 +55,7 @@ */ public class EntityAbstractGenerator extends ObjectModelGenerator { - /** - * Logger for this class - */ + /** Logger for this class */ private static final Log log = LogFactory .getLog(EntityAbstractGenerator.class); @@ -99,8 +96,8 @@ * Implantation POJO pour l'entité <%=Util.capitalize(clazz.getName())%>. }*/ { -String dbName = clazz.getTagValue(GeneratorUtil.TAG_DB_NAME); - if (dbName!=null) { + String dbName = clazz.getTagValue(GeneratorUtil.TAG_DB_NAME); + if (dbName != null) { /*{ * * <p>Nom de l'entité en BD : <%=dbName%>.</p> }*/ @@ -109,14 +106,14 @@ /*{ *) public abstract class <%=clazz.getName()%>Abstract extends }*/ String extendClass = ""; - for (Iterator i=clazz.getSuperclasses().iterator(); i.hasNext();) { - ObjectModelClassifier parent = (ObjectModelClassifier)i.next(); + for (Iterator i = clazz.getSuperclasses().iterator(); i.hasNext();) { + ObjectModelClassifier parent = (ObjectModelClassifier) i.next(); extendClass += parent.getQualifiedName(); //Si une des classes parentes définies des méthodes abstraites, son // impl ne sera pas créé boolean abstractParent = false; if (parent instanceof ObjectModelClass) { - abstractParent = shouldBeAbstract((ObjectModelClass)parent); + abstractParent = shouldBeAbstract((ObjectModelClass) parent); } if (parent.hasStereotype(GeneratorUtil.STEREOTYPE_ENTITY)) { if (abstractParent) { @@ -145,7 +142,7 @@ } for (ObjectModelAttribute attr : clazz.getAttributes()) { ObjectModelAttribute reverse = attr.getReverseAttribute(); - + // pour les asso quoi qu'il arrive il faut les lier des 2 cotes // pour pouvoir supprimer en cascade l'asso lors de la suppression // d'un des cotes @@ -202,9 +199,8 @@ //Déclaration des attributs d'une classe d'associations if (clazz instanceof ObjectModelAssociationClass) { - ObjectModelAssociationClass assoc = (ObjectModelAssociationClass)clazz; - for (Iterator i = assoc.getParticipantsAttributes().iterator(); i.hasNext(); ) { - ObjectModelAttribute attr = (ObjectModelAttribute) i.next(); + ObjectModelAssociationClass assoc = (ObjectModelAssociationClass) clazz; + for (ObjectModelAttribute attr : assoc.getParticipantsAttributes()) { if (attr != null) { /*{ <%=attr.getVisibility()%> <%=attr.getType()%> <%=Util.toLowerCaseFirstLetter(attr.getName())%>; @@ -228,15 +224,14 @@ } }*/ - + /*{ public List<TopiaEntity> getAggregate() throws TopiaException { List<TopiaEntity> tmp = new ArrayList<TopiaEntity>(); // pour tous les attributs rechecher les composites et les class d'asso // on les ajoute dans tmp -}*/ - for (Iterator it = clazz.getAttributes().iterator(); it.hasNext();) { - ObjectModelAttribute attr = (ObjectModelAttribute)it.next(); +}*/ + for (ObjectModelAttribute attr : clazz.getAttributes()) { if (attr.referenceClassifier() && attr.getClassifier().hasStereotype(GeneratorUtil.STEREOTYPE_ENTITY)) { if (attr.isAggregate()) { if (Util.isNMultiplicity(attr)) { @@ -246,7 +241,7 @@ } else { /*{ tmp.add(get<%=Util.capitalize(attr.getName())%>()); -}*/ +}*/ } } } @@ -264,15 +259,14 @@ } }*/ - + /*{ public List<TopiaEntity> getComposite() throws TopiaException { List<TopiaEntity> tmp = new ArrayList<TopiaEntity>(); // pour tous les attributs rechecher les composites et les class d'asso // on les ajoute dans tmp -}*/ - for (Iterator it = clazz.getAttributes().iterator(); it.hasNext();) { - ObjectModelAttribute attr = (ObjectModelAttribute)it.next(); +}*/ + for (ObjectModelAttribute attr : clazz.getAttributes()) { ObjectModelAttribute reverse = attr.getReverseAttribute(); if (attr.referenceClassifier() && attr.getClassifier().hasStereotype(GeneratorUtil.STEREOTYPE_ENTITY)) { if (attr.isComposite()) { @@ -283,7 +277,7 @@ } else { /*{ tmp.add(get<%=Util.capitalize(attr.getName())%>()); -}*/ +}*/ } } else if (attr.hasAssociationClass()) { String assocAttrName = GeneratorUtil.getAssocAttrName(attr); @@ -308,7 +302,7 @@ tmp.addAll(((TopiaContextImplementor)getTopiaContext()) .getDAO(<%=attr.getAssociationClass().getQualifiedName()%>.class) .findAllByProperties("<%=reverse.getName()%>", this)); -}*/ +}*/ } } } @@ -329,10 +323,9 @@ }*/ - for (Iterator it = clazz.getAttributes().iterator(); it.hasNext();) { - ObjectModelAttribute attr = (ObjectModelAttribute)it.next(); + for (ObjectModelAttribute attr : clazz.getAttributes()) { ObjectModelAttribute reverse = attr.getReverseAttribute(); - + if (!(attr.isNavigable() || hasUnidirectionalRelationOnAbstractType(reverse, model))) { continue; @@ -362,7 +355,9 @@ }*/ } else { String assocAttrName = GeneratorUtil.getAssocAttrName(attr); - if (log.isTraceEnabled()) { log.trace("assocAttrName: " + assocAttrName); } + if (log.isTraceEnabled()) { + log.trace("assocAttrName: " + assocAttrName); + } /*{ /* (non-Javadoc) * @see <%=clazz.getQualifiedName()%>#set<%=Util.capitalize(assocAttrName)%>(<%=attr.getAssociationClass().getQualifiedName()%>) *) @@ -425,6 +420,13 @@ } /* (non-Javadoc) + * @see <%=clazz.getQualifiedName()%>#get<%=Util.capitalize(attr.getName())%>ByTopiaId(String) + *) + public <%=attr.getType()%> get<%=Util.capitalize(attr.getName())%>ByTopiaId(String topiaId) { + return org.codelutin.topia.persistence.util.TopiaEntityHelper.getEntityByTopiaId(<%=attr.getName()%>, topiaId); + } + + /* (non-Javadoc) * @see <%=clazz.getQualifiedName()%>#set<%=Util.capitalize(attr.getName())%>(<%=collectionInterface%><<%=attr.getType()%>>) *) public void set<%=Util.capitalize(attr.getName())%>(<%=collectionInterface%><<%=attr.getType()%>> values) { @@ -466,7 +468,7 @@ }*/ if (reverse != null && (reverse.isNavigable() || hasUnidirectionalRelationOnAbstractType(attr, model))) { - + /*{ for (<%=attr.getType()%> item : this.<%=attr.getName()%>) { }*/ if (!Util.isNMultiplicity(reverse)) { @@ -478,8 +480,8 @@ } /*{ } }*/ - } -/*{ <%=collectionInterface%> _oldValue = new <%=collectionObject%>(this.<%=attr.getName()%>); + } +/*{ <%=collectionInterface%><<%=attr.getType()%>> _oldValue = new <%=collectionObject%><<%=attr.getType()%>>(this.<%=attr.getName()%>); fireOnPreWrite("<%=attr.getName()%>", _oldValue, this.<%=attr.getName()%>); this.<%=attr.getName()%>.clear(); fireOnPostWrite("<%=attr.getName()%>", _oldValue, this.<%=attr.getName()%>); @@ -488,7 +490,9 @@ }*/ } else { String assocAttrName = GeneratorUtil.getAssocAttrName(attr); - if (log.isTraceEnabled()) { log.trace("assocAttrName: " + assocAttrName); } + if (log.isTraceEnabled()) { + log.trace("assocAttrName: " + assocAttrName); + } /*{ /* (non-Javadoc) * @see <%=clazz.getQualifiedName()%>#add<%=Util.capitalize(assocAttrName)%>(<%=attr.getAssociationClass().getQualifiedName()%>) *) @@ -508,6 +512,13 @@ } /* (non-Javadoc) + * @see <%=clazz.getQualifiedName()%>#get<%=Util.capitalize(attr.getName())%>ByTopiaId(String) + *) + public <%=attr.getType()%> get<%=Util.capitalize(attr.getName())%>ByTopiaId(String topiaId) { + return org.codelutin.topia.persistence.util.TopiaEntityHelper.getEntityByTopiaId(<%=attr.getName()%>, topiaId); + } + + /* (non-Javadoc) * @see <%=clazz.getQualifiedName()%>#addAll<%=Util.capitalize(assocAttrName)%>(<%=collectionInterface%><<%=attr.getAssociationClass().getQualifiedName()%>>() *) public void addAll<%=Util.capitalize(assocAttrName)%>(<%=collectionInterface%><<%=attr.getAssociationClass().getQualifiedName()%>> values) { @@ -564,7 +575,7 @@ } }*/ } -/*{ <%=collectionInterface%> _oldValue = new <%=collectionObject%>(this.<%=Util.toLowerCaseFirstLetter(assocAttrName)%>); +/*{ <%=collectionInterface%><<%=attr.getType()%>> _oldValue = new <%=collectionObject%><<%=attr.getType()%>>(this.<%=Util.toLowerCaseFirstLetter(assocAttrName)%>); fireOnPreWrite("<%=Util.toLowerCaseFirstLetter(assocAttrName)%>", _oldValue, null); this.<%=Util.toLowerCaseFirstLetter(assocAttrName)%>.clear(); fireOnPostWrite("<%=Util.toLowerCaseFirstLetter(assocAttrName)%>", _oldValue, null); @@ -593,7 +604,9 @@ }*/ } else { String assocAttrName = GeneratorUtil.getAssocAttrName(attr); - if (log.isTraceEnabled()) { log.trace("assocAttrName: " + assocAttrName); } + if (log.isTraceEnabled()) { + log.trace("assocAttrName: " + assocAttrName); + } /*{ /* (non-Javadoc) * @see <%=clazz.getQualifiedName()%>#get<%=Util.capitalize(assocAttrName)%>() *) @@ -633,13 +646,12 @@ //Méthodes d'accès aux attributs d'une classe d'associations if (clazz instanceof ObjectModelAssociationClass) { - ObjectModelAssociationClass assoc = (ObjectModelAssociationClass)clazz; - for (Iterator i = assoc.getParticipantsAttributes().iterator(); i.hasNext(); ) { - ObjectModelAttribute attr = (ObjectModelAttribute) i.next(); - if (attr != null) { - String type = attr.getType(); - String name = attr.getName(); - generateAssociationAccessors(output, name, type); + ObjectModelAssociationClass assoc = (ObjectModelAssociationClass) clazz; + for (ObjectModelAttribute attr : assoc.getParticipantsAttributes()) { + if (attr != null) { + String type = attr.getType(); + String name = attr.getName(); + generateAssociationAccessors(output, name, type); // //Ne sert plus à rien normalement avec la navigabilité // ObjectModelAttribute reverse = attr.getReverseAttribute(); // if (reverse == null) { @@ -647,7 +659,7 @@ // name = attr.getDeclaringElement().getName(); // generateAssociationAccessors(output, name, type); // } - } + } } } @@ -657,8 +669,7 @@ public String toString() { String result = new ToStringBuilder(this). }*/ - for (Iterator it = clazz.getAttributes().iterator(); it.hasNext();) { - ObjectModelAttribute attr = (ObjectModelAttribute)it.next(); + for (ObjectModelAttribute attr : clazz.getAttributes()) { //FIXME possibilité de boucles (non directes) ObjectModelClass attrEntity = null; if (model.hasClass(attr.getType())) { @@ -674,7 +685,13 @@ /*{ toString(); return result; } - +}*/ + String i18nPrefix = GeneratorUtil.getI18nPrefix(clazz, model); + if (i18nPrefix != null) { + // generate i18n prefix + generateI18n(output, i18nPrefix, clazz); + } +/*{ } //<%=clazz.getName()%>Abstract }*/ } @@ -700,4 +717,21 @@ }*/ } + private void generateI18n(Writer output, String i18nPrefix, ObjectModelClass clazz) throws IOException { +/*{ + static { +}*/ + StringBuilder buffer = new StringBuilder(); + addI18n(buffer, i18nPrefix, java.beans.Introspector.decapitalize(clazz.getName())); + for (ObjectModelAttribute attr : clazz.getAttributes()) { + addI18n(buffer, i18nPrefix, java.beans.Introspector.decapitalize(attr.getName())); + } +/*{<%=buffer.toString()%>} +}*/ + } + + private void addI18n(StringBuilder buffer, String i18nPrefix, String suffix) { + buffer.append(" org.codelutin.i18n.I18n.n_(\"").append(i18nPrefix).append(suffix).append("\");\n"); + } + } //EntityAbstractGenerator Modified: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityInterfaceGenerator.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityInterfaceGenerator.java 2008-12-19 13:23:10 UTC (rev 1283) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/EntityInterfaceGenerator.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -367,6 +367,15 @@ public <%=collectionInterface%><<%=attr.getType()%>> get<%=Util.capitalize(attr.getName())%>(); /** + * Recupère l'attribut <%=attr.getName()%> à partir de son topiaId. + * + * @param topiaId le topia id de l'entité recherchée + * + * @return l'attribut recherché, ou <code>null</code> s'il n'existe pas. + *) + public <%=attr.getType()%> get<%=Util.capitalize(attr.getName())%>ByTopiaId(String topiaId); + + /** * @return Le nombre d'éléments de la collection <%=attr.getName()%>. *) public int size<%=Util.capitalize(attr.getName())%>(); @@ -383,6 +392,15 @@ public <%=collectionInterface%><<%=attr.getAssociationClass().getQualifiedName()%>> get<%=Util.capitalize(assocAttrName)%>(); /** + * Recupère l'attribut <%=attr.getName()%> à partir de son topiaId. + * + * @param topiaId le topia id de l'attribut recherchée + * + * @return l'attribut recherché, ou <code>null</code> s'il n'existe pas. + *) + public <%=attr.getType()%> get<%=Util.capitalize(attr.getName())%>ByTopiaId(String topiaId); + + /** * @return L'attribut <%=attr.getAssociationClass().getName()%> associé à la valeur <code>value</code> de l'attribut <%=attr.getName()%>. *) public <%=attr.getAssociationClass().getQualifiedName()%> get<%=Util.capitalize(assocAttrName)%>(<%=attr.getType()%> value); Modified: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/GeneratorUtil.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/GeneratorUtil.java 2008-12-19 13:23:10 UTC (rev 1283) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/generator/GeneratorUtil.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -99,6 +99,9 @@ /** Tag pour specfier le type d'acces a un champ */ public static final String TAG_ACCESS = "access"; + /** Tag pour specfier si on doit générer i18n */ + public static final String TAG_I18N_PREFIX = "i18n"; + /** Type de persistence Hibernate */ public static final String PERSISTENCE_TYPE_HIBERNATE = "hibernate"; @@ -209,7 +212,7 @@ } /** - * Cherches et renvoie le schema a utiliser sur cet element, sinon sur le model. + * Cherche et renvoie le schema a utiliser sur cet element, sinon sur le model. * * @param element l'élément à tester * @param model le modele utilisé @@ -221,6 +224,18 @@ } /** + * Cherche et renvoie le prefixe i18n à utiliser sur cet element, sinon sur le model. + * + * @param element l'élément à tester + * @param model le modele utilisé + * @return le prefix i18n ou <code>null</code> si non spécifié + */ + public static String getI18nPrefix(ObjectModelElement element, + ObjectModel model) { + return findTagValue(TAG_I18N_PREFIX, element, model); + } + + /** * Cherches et renvoie le copyright a utiliser sur le model. * * @param model le modele utilisé Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/BeanPropertyLoador.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/BeanPropertyLoador.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/BeanPropertyLoador.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,154 @@ +package org.codelutin.topia.persistence.util; + +import org.apache.commons.beanutils.MethodUtils; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; + +/** @author chemit */ +public class BeanPropertyLoador<E> implements Loador<E> { + + public static <E> BeanPropertyLoador<E> newLoador(Class<E> klass, String... properties) { + return new BeanPropertyLoador<E>(klass, properties); + } + + private static final long serialVersionUID = 1L; + + protected static final Integer ZERO = 0; + protected static final Float ZEROF = 0f; + protected static final Long ZEROL = 0l; + protected static final Double ZEROD = 0.; + protected static final Byte ZEROB = 0; + + protected List<String> properties; + protected transient PropertyDescriptor[] descriptors; + protected Class<E> klass; + + protected BeanPropertyLoador(Class<E> klass, String... properties) { + this.properties = java.util.Collections.unmodifiableList(Arrays.asList(properties)); + this.klass = klass; + } + + public List<String> getProperties() { + return properties; + } + + public PropertyDescriptor[] getDescriptors() { + if (descriptors == null) { + try { + descriptors = new PropertyDescriptor[properties.size()]; + for (PropertyDescriptor propertydescriptor : Introspector.getBeanInfo(klass).getPropertyDescriptors()) { + int index = properties.indexOf(propertydescriptor.getName()); + if (index != -1) { + descriptors[index] = propertydescriptor; + } + } + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } + return descriptors; + } + + @Override + public void load(E from, E dst, boolean tech) { + if (from == null) { + // reset all fields + for (PropertyDescriptor descriptor : getDescriptors()) { + Object read = getNullValue(descriptor.getPropertyType()); + setProperty(dst, descriptor, read); + } + } else { + // set all fields from + for (PropertyDescriptor descriptor : getDescriptors()) { + try { + Object value = descriptor.getReadMethod().invoke(from); + setProperty(dst, descriptor, value); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } + } + + protected void setProperty(E dst, PropertyDescriptor descriptor, Object value) { + try { + descriptor.getWriteMethod().invoke(dst, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected static Object getNullValue(Class<?> type) { + if (type.isPrimitive()) { + type = MethodUtils.getPrimitiveWrapper(type); + if (Boolean.class.isAssignableFrom(type)) { + return Boolean.FALSE; + } + if (Integer.class.isAssignableFrom(type)) { + return ZERO; + } + if (Float.class.isAssignableFrom(type)) { + return ZEROF; + } + if (Long.class.isAssignableFrom(type)) { + return ZEROL; + } + if (Double.class.isAssignableFrom(type)) { + return ZEROD; + } + if (Byte.class.isAssignableFrom(type)) { + return ZEROB; + } + } + return null; + } + + public static boolean isNullValue(Object value) { + if (value == null) { + return true; + } + Class<?> type = value.getClass(); + if (type.isPrimitive()) { + type = MethodUtils.getPrimitiveWrapper(type); + } + if (Boolean.class.isAssignableFrom(type)) { + return Boolean.FALSE.equals(value); + } + if (Integer.class.isAssignableFrom(type)) { + return ZERO.equals(value); + } + if (Float.class.isAssignableFrom(type)) { + return ZEROF.equals(value); + } + if (Long.class.isAssignableFrom(type)) { + return ZEROL.equals(value); + } + if (Double.class.isAssignableFrom(type)) { + return ZEROD.equals(value); + } + return Byte.class.isAssignableFrom(type) && ZEROB.equals(value); + } + + protected void checkProperties() { + PropertyDescriptor[] descriptors = getDescriptors(); + for (int i = 0; i < descriptors.length; i++) { + PropertyDescriptor descriptor = descriptors[i]; + if (descriptor == null) { + throw new IllegalStateException("could not find descriptor for property " + properties.get(i) + " on " + klass); + } + if (descriptor.getReadMethod() == null) { + throw new IllegalStateException("property " + properties.get(i) + " is not readable on " + klass); + } + if (descriptor.getWriteMethod() == null) { + throw new IllegalStateException("property " + properties.get(i) + " is not writable on " + klass); + } + } + } +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Creator.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Creator.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Creator.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,8 @@ +package org.codelutin.topia.persistence.util; + +import org.codelutin.topia.TopiaException; + +/** @author chemit */ +public interface Creator<P, E> { + E create(DBMapping mapping, P parent, E from) throws TopiaException; +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/DBMapping.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/DBMapping.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/DBMapping.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,425 @@ +package org.codelutin.topia.persistence.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.topia.TopiaContext; +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.framework.TopiaContextImpl; +import org.codelutin.topia.persistence.TopiaEntity; +import org.hibernate.SQLQuery; +import org.hibernate.jdbc.Work; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Une classe qui permet d'obtenir les mapping de noms entre les entités et les objets de la base. + * <p/> + * On retrouve aussi ici des méthodes utils pour executer du code sql sur la base (notamment la gestion des séquences). + * + * @author chemit + */ +public abstract class DBMapping { + + /** log */ + protected static final Log log = LogFactory.getLog(DBMapping.class); + + protected static final String CLASS_PATTERN = "(.+)\\.class\\.tagvalue\\.dbName"; + + protected static final String DBNAME_ATTRIBUTE_PATTERN = "(.+).attribute.(\\w+)\\.tagvalue\\.dbName"; + + protected static final String SEQUENCE_ATTRIBUTE_PATTERN = "(.+).attribute.(\\w+)\\.tagvalue\\.sequence"; + + protected static final String CREATE_SEQUENCE_FORMAT = "create sequence %1$s%2$s_%3$s_sequence start (select max(%3$s) from %1$s%2$s);"; + + protected static final String UPDATE_SEQUENCE_FORMAT = "alter sequence %1$s%2$s_%3$s_sequence restart with (select max(%3$s) from %1$s%2$s);"; + + protected static final String CURRENT_VALUE_SEQUENCE_FORMAT = "select %1$s%2$s_%3$s_sequence.currval"; + + protected static final String NEXT_VALUE_SEQUENCE_FORMAT = "select %1$s%2$s_%3$s_sequence.nextval"; + + protected static final String SCHEMA_FORMAT = "model.tagvalue.dbSchema"; + + protected static final String DOT = "."; + + protected Map<String, String> mappingBeanToDb; + + protected Map<String, Class<? extends TopiaEntity>> sequences; + + protected String schema; + + protected abstract Class<? extends TopiaEntity> getContractClass(Class<? extends TopiaEntity> entityClass) throws TopiaException; + + public DBMapping(String propertyFile, String path) throws IOException { + mappingBeanToDb = new java.util.TreeMap<String, String>(); + sequences = new java.util.TreeMap<String, Class<? extends TopiaEntity>>(); + + if (propertyFile == null) { + propertyFile = path; + } + + InputStream stream = getClass().getResourceAsStream(propertyFile); + if (stream == null) { + throw new IllegalStateException("no tagsvalues defined (did not find the resource : " + propertyFile + ")"); + } + + Properties props = new Properties(); + + try { + + props.load(stream); + + initMapping(props); + + } finally { + props.clear(); + stream.close(); + } + } + + public void init(TopiaContext ctxt, boolean doCreate, boolean doUpdate) throws TopiaException { + if (sequences.isEmpty()) { + // no sequence registed + return; + } + String firstSequenceKey = sequences.keySet().iterator().next(); + TopiaContext newContext = ctxt.beginTransaction(); + boolean exists = existSequence(firstSequenceKey, newContext); + + if (!exists) { + if (!doCreate) { + // not exists and do not create + return; + } + createSequences(newContext); + } else { + if (doUpdate) { + updateSequences(newContext); + } + } + newContext.commitTransaction(); + newContext.closeContext(); + } + + public void createSequences(TopiaContext ctxt) throws TopiaException { + if (log.isInfoEnabled()) { + log.info("start create db sequences..."); + } + for (String sequenceKey : sequences.keySet()) { + createSequence(sequenceKey, ctxt, false); + } + } + + public void updateSequences(TopiaContext ctxt) throws TopiaException { + if (log.isInfoEnabled()) { + log.info("start update db sequences..."); + } + for (String sequenceKey : sequences.keySet()) { + updateSequence(sequenceKey, ctxt, false); + } + } + + public boolean existSequence(String sequenceKey, TopiaContext ctxt) throws TopiaException { + return existSequence(sequenceKey, ctxt, true); + } + + public void createSequence(String sequenceKey, TopiaContext ctxt) throws TopiaException { + createSequence(sequenceKey, ctxt, true); + } + + public void updateSequence(String sequenceKey, TopiaContext ctxt) throws TopiaException { + updateSequence(sequenceKey, ctxt, true); + } + + public BigInteger getCurrentValueFromSequence(String sequenceKey, TopiaContext ctxt) throws TopiaException { + return getCurrentValueFromSequence(sequenceKey, ctxt, true); + } + + public BigInteger getNextValueFromSequence(String sequenceKey, TopiaContext ctxt) throws TopiaException { + return getNextValueFromSequence(sequenceKey, ctxt, true); + } + + public boolean existSequence(Class<? extends TopiaEntity> entityClass, String propertyName, TopiaContext ctxt) throws TopiaException { + String sequenceKey = checkSequence(entityClass, propertyName); + return existSequence(sequenceKey, ctxt, false); + } + + public void createSequence(Class<? extends TopiaEntity> entityClass, String propertyName, TopiaContext ctxt) throws TopiaException { + String sequenceKey = checkSequence(entityClass, propertyName); + createSequence(sequenceKey, ctxt, false); + } + + public void updateSequence(Class<? extends TopiaEntity> entityClass, String propertyName, TopiaContext ctxt) throws TopiaException { + String sequenceKey = checkSequence(entityClass, propertyName); + updateSequence(sequenceKey, ctxt, false); + } + + public BigInteger getCurrentValueFromSequence(Class<? extends TopiaEntity> entityClass, String propertyName, TopiaContext ctxt) throws TopiaException { + String sequenceKey = checkSequence(entityClass, propertyName); + return getCurrentValueFromSequence(sequenceKey, ctxt, false); + } + + public BigInteger getNextValueFromSequence(Class<? extends TopiaEntity> entityClass, String propertyName, TopiaContext ctxt) throws TopiaException { + String sequenceKey = checkSequence(entityClass, propertyName); + return getNextValueFromSequence(sequenceKey, ctxt, false); + } + + public Iterator<String> getSequenceKeysIterator() { + return sequences.keySet().iterator(); + } + + public boolean existSequence(String sequenceKey, TopiaContext ctxt, boolean check) throws TopiaException { + if (check) { + checkSequence(sequenceKey); + } + try { + getCurrentValueFromSequence(sequenceKey, ctxt, false); + + } catch (TopiaException e) { + // the sequence's name does not exist in database, so it is a grammer exception + if (e.getCause() != null && e.getCause().getClass() == org.hibernate.exception.SQLGrammarException.class) { + return false; + } + throw e; + } + return true; + } + + public void createSequence(String sequenceKey, TopiaContext ctxt, boolean check) throws TopiaException { + if (check) { + checkSequence(sequenceKey); + } + final String sql = getSequenceSQL(CREATE_SEQUENCE_FORMAT, sequenceKey); + doSQLWork(ctxt, sql); + BigInteger currentValue = getNextValueFromSequence(sequenceKey, ctxt, false); + + if (log.isDebugEnabled()) { + log.debug(sequenceKey + " currentValue " + currentValue.intValue()); + } + } + + public void updateSequence(String sequenceKey, TopiaContext ctxt, boolean check) throws TopiaException { + if (check) { + checkSequence(sequenceKey); + } + final String sql = getSequenceSQL(UPDATE_SEQUENCE_FORMAT, sequenceKey); + doSQLWork(ctxt, sql); + BigInteger currentValue = getNextValueFromSequence(sequenceKey, ctxt, false); + if (log.isDebugEnabled()) { + log.debug(sequenceKey + " currentValue " + currentValue.intValue()); + } + } + + public BigInteger getCurrentValueFromSequence(String sequenceKey, TopiaContext ctxt, boolean check) throws TopiaException { + if (check) { + checkSequence(sequenceKey); + } + String sql = getSequenceSQL(CURRENT_VALUE_SEQUENCE_FORMAT, sequenceKey); + TopiaContext newCtxt = ctxt.beginTransaction(); + BigInteger bigInteger = getBigInteger(newCtxt, sql, BigInteger.ZERO); + newCtxt.closeContext(); + return bigInteger; + } + + public BigInteger getNextValueFromSequence(String sequenceKey, TopiaContext ctxt, boolean check) throws TopiaException { + if (check) { + checkSequence(sequenceKey); + } + String sql = getSequenceSQL(NEXT_VALUE_SEQUENCE_FORMAT, sequenceKey); + return getBigInteger(ctxt, sql, BigInteger.ZERO); + } + + /** + * @param entityClass the seek entity class + * @param property the name of the property to translate + * @return the DB name for the given property + * @throws org.codelutin.topia.TopiaException + * if any db pb + */ + protected String getDBProperty(Class<? extends TopiaEntity> entityClass, String property) throws TopiaException { + Class<? extends TopiaEntity> contractClass = getContractClass(entityClass); + String key = contractClass.getName() + DOT + property; + + String colName = mappingBeanToDb.get(key); + if (colName == null) { + colName = property; + } + return colName; + } + + /** + * @param entityClass the seek entity class + * @return the DB name for the given property + * @throws org.codelutin.topia.TopiaException + * if any db pb + */ + protected String getDBTable(Class<? extends TopiaEntity> entityClass) throws TopiaException { + Class<? extends TopiaEntity> contractClass = getContractClass(entityClass); + String key = contractClass.getName(); + String colName = mappingBeanToDb.get(key); + + if (colName == null) { + colName = contractClass.getSimpleName().toLowerCase(); + } + return colName; + } + + protected String getSequenceSQL(String pattern, Class<? extends TopiaEntity> entityClass, String propertyName) throws TopiaException { + String dbTable = getDBTable(entityClass); + String dbPropertyName = getDBProperty(entityClass, propertyName); + String sql = String.format(pattern, schema, dbTable, dbPropertyName); + if (log.isTraceEnabled()) { + log.trace("sql : " + sql); + } + return sql; + } + + protected String getSequenceSQL(String pattern, String sequenceKey) throws TopiaException { + Class<? extends TopiaEntity> entityClass = sequences.get(sequenceKey); + String dbTable = getDBTable(entityClass); + String propertyName = getSequencePropertyName(sequenceKey); + String dbPropertyName = getDBProperty(entityClass, propertyName); + String sql = String.format(pattern, schema, dbTable, dbPropertyName); + if (log.isTraceEnabled()) { + log.trace("sql : " + sql); + } + return sql; + } + + protected BigInteger getBigInteger(TopiaContext ctxt, String sql, BigInteger defaultSize) throws TopiaException { + BigInteger size = defaultSize; + if (ctxt != null) { + try { + SQLQuery query = ((TopiaContextImpl) ctxt).getHibernate().createSQLQuery(sql); + size = (BigInteger) query.list().get(0); + } catch (org.hibernate.exception.SQLGrammarException e) { + // could not obtain sequence + throw new TopiaException(e); + } + } + return size; + } + + protected void doSQLWork(TopiaContext ctxt, final String sql) throws TopiaException { + if (ctxt != null) { + //ctxt.beginTransaction(); + ((TopiaContextImpl) ctxt).getHibernate().doWork(new Work() { + public void execute(Connection connection) throws SQLException { + if (log.isDebugEnabled()) { + log.debug(sql); + } + Statement stmt = connection.createStatement(); + stmt.execute(sql); + } + }); + //ctxt.commitTransaction(); + } + } + + protected String getSequencePropertyName(String sequenceKey) { + int dotIndex = sequenceKey.lastIndexOf(DOT); + return sequenceKey.substring(dotIndex + 1); + } + + protected String checkSequence(Class<? extends TopiaEntity> entityClass, String propertyName) throws IllegalArgumentException, TopiaException { + Class<? extends TopiaEntity> contractClass = getContractClass(entityClass); + String sequenceKey = contractClass.getName() + DOT + propertyName; + if (!sequences.containsKey(sequenceKey)) { + throw new IllegalArgumentException("could not find the sequence " + sequenceKey); + } + return sequenceKey; + } + + protected String checkSequence(String sequenceKey) throws IllegalArgumentException, TopiaException { + if (!sequences.containsKey(sequenceKey)) { + throw new IllegalArgumentException("could not find the sequence " + sequenceKey); + } + return sequenceKey; + } + + @SuppressWarnings({"unchecked"}) + protected void initMapping(Properties props) throws IOException { + + if (props.containsKey(SCHEMA_FORMAT)) { + schema = props.getProperty(SCHEMA_FORMAT) + DOT; + } else { + schema = ""; + } + + Pattern classPattern = Pattern.compile(CLASS_PATTERN); + + Pattern dbNameAttributePattern = Pattern.compile(DBNAME_ATTRIBUTE_PATTERN); + + Pattern sequenceAttributePattern = Pattern.compile(SEQUENCE_ATTRIBUTE_PATTERN); + + for (Entry<Object, Object> entry : props.entrySet()) { + String key = String.valueOf(entry.getKey()); + String value = String.valueOf(entry.getValue()); + Matcher matcher; + + matcher = dbNameAttributePattern.matcher(key); + if (matcher.matches()) { + // find a attribute property + String clazz = matcher.group(1); + String attribute = matcher.group(2); + mappingBeanToDb.put(clazz + "." + attribute, value); + + continue; + } + matcher = classPattern.matcher(key); + if (matcher.matches()) { + // find a class property + String clazz = matcher.group(1); + mappingBeanToDb.put(clazz, value); + continue; + } + matcher = sequenceAttributePattern.matcher(key); + if (matcher.matches()) { + // find a attribute property + String clazz = matcher.group(1); + String attribute = matcher.group(2); + try { + boolean useSequence = Boolean.valueOf(value); + if (useSequence) { + Class<?> value1 = Class.forName(clazz); + if (TopiaEntity.class.isAssignableFrom(value1)) { + sequences.put(clazz + "." + attribute, (Class<? extends TopiaEntity>) value1); + } else { + log.warn("can not create a sequence on a non TopiaEntity class " + clazz); + } + + } + } catch (Exception e) { + log.warn("could not convert sequence value for entry " + key+" for reason "+e.getMessage()); + } + + } + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + close(); + } + + public void close() { + if (mappingBeanToDb != null) { + mappingBeanToDb.clear(); + } + if (sequences != null) { + sequences.clear(); + } + } + +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Deletor.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Deletor.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Deletor.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,6 @@ +package org.codelutin.topia.persistence.util; + +/** @author chemit */ +public interface Deletor<P, E> { + void delete(P parent, E from); +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityListUpdator.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityListUpdator.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityListUpdator.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,90 @@ +package org.codelutin.topia.persistence.util; + +import org.apache.commons.beanutils.PropertyUtilsBean; +import org.apache.commons.lang.StringUtils; +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.persistence.TopiaEntity; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; + +/** @author chemit */ +public class EntityListUpdator<P extends TopiaEntity, E extends TopiaEntity> implements ListUpdator<P, E> { + + public static <P extends TopiaEntity, E extends TopiaEntity> EntityListUpdator<P, E> newEntityListUpdator(Class<P> parentClass, Class<E> childClass, String propertyName) { + return new EntityListUpdator<P, E>(parentClass, childClass, propertyName); + } + + protected String propertyName; + + protected PropertyDescriptor descriptor; + protected Method getMethod; + protected Method addMethod; + protected Method removeMethod; + + protected EntityListUpdator(Class<P> parentClass, Class<E> childClass, String propertyName) { + this.propertyName = propertyName; + + for (PropertyDescriptor propertyDescriptor : new PropertyUtilsBean().getPropertyDescriptors(parentClass)) { + if (propertyDescriptor.getName().equals(propertyName)) { + descriptor = propertyDescriptor; + } + } + String cap = StringUtils.capitalize(propertyName); + try { + getMethod = parentClass.getMethod("get" + cap + "ByTopiaId", String.class); + addMethod = parentClass.getMethod("add" + cap, childClass); + removeMethod = parentClass.getMethod("remove" + cap, childClass); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + @Override + public E getChild(P parent, String topiaId) { + return EntityListUpdator.<E>invokeWithResult(getMethod, parent, topiaId); + } + + @Override + public Collection<E> getChilds(P parent) { + return EntityListUpdator.invokeWithResult(descriptor.getReadMethod(), parent); + } + + @Override + public void setChilds(P parent, Collection<E> childs) { + invoke(descriptor.getWriteMethod(), parent, childs); + } + + @Override + public void addToList(P parent, E bean) throws TopiaException { + invoke(addMethod, parent, bean); + } + + @Override + public void removeFromList(P parent, E bean) throws TopiaException { + invoke(removeMethod, parent, bean); + } + + protected static void invoke(Method m, Object bean, Object... args) { + try { + m.invoke(bean, args); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings({"unchecked"}) + protected static <V> V invokeWithResult(Method m, Object bean, Object... args) { + try { + return (V) m.invoke(bean, args); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityLoador.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityLoador.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/EntityLoador.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,37 @@ +package org.codelutin.topia.persistence.util; + +import org.codelutin.topia.persistence.TopiaEntity; + +/** @author chemit */ +public class EntityLoador<E extends TopiaEntity> extends BeanPropertyLoador<E> { + private static final long serialVersionUID = 1L; + + protected E empty; + + public static <E extends TopiaEntity> EntityLoador<E> newEntityLoador(Class<E> klass, E empty, String... properties) { + return new EntityLoador<E>(klass, empty, properties); + } + + public static <E extends TopiaEntity> EntityLoador<E> newEntityLoador(Class<E> klass, String... properties) { + return newEntityLoador(klass, null, properties); + } + + + @Override + public void load(E from, E dst, boolean tech) { + if (from == null) { + from = empty; + } + if (tech) { + TopiaEntityHelper.bindTechnical(from, dst); + } + super.load(from, dst, tech); + } + + protected EntityLoador(Class<E> klass, E empty, String... properties) { + super(klass, properties); + this.empty = empty; + // check properties + checkProperties(); + } +} \ No newline at end of file Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Gettor.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Gettor.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Gettor.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,6 @@ +package org.codelutin.topia.persistence.util; + +/** @author chemit */ +public interface Gettor<P, E> { + E get(P parent, String topiaId); +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/ListUpdator.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/ListUpdator.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/ListUpdator.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,19 @@ +package org.codelutin.topia.persistence.util; + +import org.codelutin.topia.TopiaException; + +import java.util.Collection; + +/** @author chemit */ +public interface ListUpdator<P, E> { + + E getChild(P parent, String topiaId); + + Collection<E> getChilds(P parent); + + void setChilds(P parent, Collection<E> childs); + + void addToList(P parent, E bean) throws TopiaException; + + void removeFromList(P parent, E bean) throws TopiaException; +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Loador.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Loador.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/Loador.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,7 @@ +package org.codelutin.topia.persistence.util; + +/** @author chemit */ +public interface Loador<E> extends java.io.Serializable { + + void load(E from, E dst, boolean tech); +} Added: topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/TopiaEntityHelper.java =================================================================== --- topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/TopiaEntityHelper.java (rev 0) +++ topia/trunk/topia-persistence/src/main/java/org/codelutin/topia/persistence/util/TopiaEntityHelper.java 2009-01-05 08:40:44 UTC (rev 1284) @@ -0,0 +1,215 @@ +package org.codelutin.topia.persistence.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.topia.TopiaContext; +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.persistence.TopiaDAO; +import org.codelutin.topia.persistence.TopiaEntity; +import org.codelutin.util.IOUtils; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.util.Collection; + +/** + * Une classe avec des méthodes utiles sur les entités. + * + * @author chemit + */ +public class TopiaEntityHelper { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(TopiaEntityHelper.class); + + /** + * Bind les valeurs techniques depuis une entitée vers une autre. + * + * @param from l'entité source + * @param dst l'entité destination + */ + public static void bindTechnical(TopiaEntity from, TopiaEntity dst) { + if (from == null) { + dst.setTopiaId(null); + dst.setTopiaVersion(0); + dst.setTopiaCreateDate(null); + } else { + dst.setTopiaId(from.getTopiaId()); + dst.setTopiaVersion(from.getTopiaVersion()); + dst.setTopiaCreateDate(from.getTopiaCreateDate()); + } + } + + /** + * Récupère une entité qui doit exister à partir de son id. + * <p/> + * Si l'entité n'existe pas, on déclanche une exception {@link IllegalArgumentException}. + * + * @param dao la dao pour récupérer la valeur + * @param topiaId l'id de l'entité recherchée + * @param <E> le type de l'entité + * @return l'entité recherché + * @throws TopiaException pour tout pb lors de la récupération de l'entité + * @throws IllegalArgumentException si l'entité n'existe pas. + */ + public static <E extends TopiaEntity> E getExistingEntity(TopiaDAO<E> dao, String topiaId) throws TopiaException, IllegalArgumentException { + E entity = dao.findByTopiaId(topiaId); + if (entity == null) { + throw new IllegalArgumentException("could not find entity with topiaId " + topiaId); + } + return entity; + } + + /** + * Récupère une entité dans une liste d'entité. + * + * @param entities la liste des entités à scanner + * @param topiaId l'id de l'entité recherchée + * @param <E> le type de l'entité + * @return l'entité trouvée, ou <code<null</code< si elle n'est pas trouvée. + */ + public static <E extends TopiaEntity> E getEntityByTopiaId(Collection<E> entities, String topiaId) { + if (entities != null) { + for (E e : entities) { + if (topiaId.equals(e.getTopiaId())) { + return e; + } + } + } + return null; + } + + /** + * Teste si une entité possède un topiaId. + * + * @param paramName le nom du paramètre à afficher en casd'erreur + * @param bean l'entité à tester + * @param <E> le type de l'entité + * @throws IllegalStateException si l'entité n'a pas de topiaId + * @throws NullPointerException si l'entité est null + */ + public static <E extends TopiaEntity> void checkNotNullAndExistingEntity(String paramName, E bean) throws IllegalStateException, NullPointerException { + if (bean == null) { + throw new NullPointerException(paramName + " can not be null"); + } + if (bean.getTopiaId() == null) { + // can not create bean here + throw new IllegalStateException("can not create " + bean.getClass() + " here..."); + } + } + + /** + * Teste si une entité ne possède pas un topiaId. + * + * @param paramName le nom de paramètre à afficher en cas d'erreur + * @param bean l'entité à tester + * @param <E> le type del'entité + * @throws NullPointerException si l'entité est nulle + * @throws IllegalStateException si l'entité possède un topiaId. + */ + public static <E extends TopiaEntity> void checkNotNullAndNoneExistingEntity(String paramName, E bean) throws NullPointerException, IllegalStateException { + if (bean == null) { + throw new NullPointerException(paramName + " can not be null"); + } + if (bean.getTopiaId() != null) { + // can not create bean here + throw new IllegalStateException("can not update " + bean.getClass() + " here..."); + } + } + + /** + * Create a new database from a sql dump locating in a gzip file. + * + * @param dbDirectory the directory where to create the db + * @param topiaContext the topiaContext to use to create the databse + * @param resource the url of the sql dump gzip file to use + * @throws TopiaException if any pb while creating db + * @throws IOException if any io exception + * @throws NullPointerException if parameters are null + */ + public static void createDBFromSQL(File dbDirectory, TopiaContext topiaContext, URI resource) throws IOException, TopiaException, NullPointerException { + if (dbDirectory == null) { + throw new NullPointerException("dbDirectory can not be null"); + } + if (topiaContext == null) { + throw new NullPointerException("topiaContext can not be null"); + } + if (resource == null) { + throw new NullPointerException("resource can not be null"); + } + + File databaseDump; + if (resource.isOpaque()) { + + ByteArrayOutputStream output = IOUtils.readBytesFrom(resource.toURL().openStream(), 8048); + File tempFile = File.createTempFile("topiaDumpDatabase", ".sql.gz"); + + output.writeTo(new FileOutputStream(tempFile)); + + tempFile.deleteOnExit(); + databaseDump = tempFile; + + } else { + + databaseDump = new File(resource); + } + + if (!dbDirectory.exists()) { + if (!dbDirectory.mkdirs()) { + throw new IOException("could not create directory " + dbDirectory); + } + } + + log.info("create database from [" + databaseDump + "] at [" + dbDirectory + "]"); + + TopiaContext ctxt = topiaContext.beginTransaction(); + + try { + ctxt.restore(databaseDump); + ctxt.commitTransaction(); + } catch (TopiaException e) { + ctxt.rollbackTransaction(); + throw e; + } finally { + ctxt.closeContext(); + } + } + + /** + * Save the given database to a gzip file. + * + * @param gzipFile the file where to store db + * @param topiaContext the topiaContext of the db to store + * @throws TopiaException if any pb while saving db + * @throws NullPointerException if parameters are null + * @throws IOException if could not create gzipFile container directory + */ + public static void saveDB(File gzipFile, TopiaContext topiaContext) throws TopiaException, IOException, NullPointerException { + if (gzipFile == null) { + throw new NullPointerException("gzipFile can not be null"); + } + if (topiaContext == null) { + throw new NullPointerException("topiaContext can not be null"); + } + if (!gzipFile.getParentFile().exists()) { + if (!gzipFile.getParentFile().mkdirs()) { + throw new IOException("could not create directory " + gzipFile.getParentFile()); + } + } + log.info("store database to [" + gzipFile + "]"); + + TopiaContext ctxt = null; + + try { + ctxt = topiaContext.beginTransaction(); + ctxt.backup(gzipFile, true); + } finally { + if (ctxt != null) { + ctxt.closeContext(); + } + } + } +}