View Javadoc
1   /*
2    * #%L
3    * ToPIA :: Persistence
4    * $Id$
5    * $HeadURL$
6    * %%
7    * Copyright (C) 2004 - 2019 CodeLutin
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as 
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  package org.nuiton.topia.generator;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.commons.lang3.builder.ToStringBuilder;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.codehaus.plexus.component.annotations.Component;
31  import org.nuiton.eugene.EugeneCoreTagValues;
32  import org.nuiton.eugene.Template;
33  import org.nuiton.eugene.java.ObjectModelTransformerToJava;
34  import org.nuiton.eugene.models.object.ObjectModelAssociationClass;
35  import org.nuiton.eugene.models.object.ObjectModelAttribute;
36  import org.nuiton.eugene.models.object.ObjectModelClass;
37  import org.nuiton.eugene.models.object.ObjectModelClassifier;
38  import org.nuiton.eugene.models.object.ObjectModelInterface;
39  import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
40  import org.nuiton.eugene.models.object.ObjectModelModifier;
41  import org.nuiton.eugene.models.object.ObjectModelOperation;
42  import org.nuiton.eugene.models.object.ObjectModelParameter;
43  import org.nuiton.topia.TopiaException;
44  import org.nuiton.topia.framework.TopiaContextImplementor;
45  import org.nuiton.topia.persistence.EntityVisitor;
46  import org.nuiton.topia.persistence.TopiaEntity;
47  import org.nuiton.topia.persistence.TopiaEntityAbstract;
48  import org.nuiton.topia.persistence.TopiaEntityContextable;
49  import org.nuiton.topia.persistence.util.TopiaEntityHelper;
50  
51  import java.util.ArrayList;
52  import java.util.Collection;
53  import java.util.LinkedList;
54  import java.util.List;
55  import java.util.Set;
56  
57  import static org.nuiton.topia.generator.TopiaGeneratorUtil.hasUnidirectionalRelationOnAbstractType;
58  
59  /*{generator option: parentheses = false}*/
60  /*{generator option: writeString = +}*/
61  
62  /**
63   * A template to generate all the {@link TopiaEntity} api for all classifier
64   * with a {@code entity} stereotype.
65   *
66   * For example, given a {@code House} entity, it will generates :
67   * <ul>
68   * <li>{@code House} : contract of entity</li>
69   * <li>{@code AbstractHouse} : default abstract implementation of entity</li>
70   * <li>{@code HouseImpl} : default impl of abstract entity</li>
71   * </ul>
72   *
73   * <b>Note: </b> The impl will ony be generated in these cases :
74   * <ul>
75   * <li>There is no abstract method</li>
76   * <li>There is no already defined such class in class-path</li>
77   * </ul>
78   *
79   * @author tchemit &lt;chemit@codelutin.com&gt;
80   * @since 2.3.4
81   */
82  @Component(role = Template.class, hint = "org.nuiton.topia.generator.EntityTransformer")
83  public class EntityTransformer extends ObjectModelTransformerToJava {
84  
85      /** Logger */
86      private static final Log log = LogFactory.getLog(EntityTransformer.class);
87  
88      protected ObjectModelInterface outputInterface;
89  
90      protected ObjectModelClass outputAbstract;
91  
92      protected ObjectModelClass outputImpl;
93  
94      private boolean associationClass;
95  
96      protected boolean generateInterface;
97  
98      protected boolean generateAbstract;
99  
100     protected boolean generateImpl;
101 
102     protected boolean generateBooleanGetMethods;
103 
104     protected void clean() {
105         outputInterface = null;
106         outputAbstract = null;
107         outputImpl = null;
108     }
109 
110     @Override
111     public void transformFromClass(ObjectModelClass input) {
112 
113         if (!TopiaGeneratorUtil.isEntity(input)) {
114 
115             // not an entity, skip class.
116             return;
117         }
118 
119         if (log.isDebugEnabled()) {
120             log.debug("for entity : " + input.getQualifiedName());
121             log.debug("Will use classLoader " + getClassLoader());
122         }
123         
124         // fix once for all the constant prefix to use
125         String prefix = getConstantPrefix(input);
126         if (StringUtils.isEmpty(prefix)) {
127 
128             // no specific prefix, so no prefix
129             if (log.isWarnEnabled()) {
130                 log.warn("[" + input.getName() + "] Will generate constants with NO prefix, not a good idea... \n" +
131                          "Use '" + EugeneCoreTagValues.Store.constantPrefix +
132                          "' tagvalue in your xmi properties. For example " +
133                          "for all the model : model.tagvalue." + EugeneCoreTagValues.Store.constantPrefix + "=PROPERTY_");
134             }
135         }
136         setConstantPrefix(prefix);
137 
138         generateInterface = isGenerateInterface(input);
139         generateAbstract = isGenerateAbstract(input);
140         generateImpl = isGenerateImpl(input);
141 
142         generateBooleanGetMethods = eugeneTagValues.isGenerateBooleanGetMethods(input, null, model);
143 
144         if (generateInterface) {
145             
146             // Create Entity Interface and its header
147             createEntityInterface(input);
148         }
149 
150         if (generateAbstract) {
151 
152             // Create Entity Abstract class and its header
153             createEntityAbstractClass(input);
154         }
155 
156         // Generate i18n block
157         String i18nPrefix = eugeneTagValues.getI18nPrefixTagValue(input, null, model);
158         if (!StringUtils.isEmpty(i18nPrefix)) {
159             generateI18nBlock(input, outputAbstract, i18nPrefix);
160         }
161 
162         // Create accept operation, will be updated during property generation
163         createAcceptOperation();
164         createAcceptInternalOperation(input);
165 
166         // Add constant, attribute and operations for each property
167         generateProperties(input.getAttributes());
168 
169         // Case of association class : properties from participants/extremities
170         // of the association class.
171         if (input instanceof ObjectModelAssociationClass) {
172             ObjectModelAssociationClass association =
173                     (ObjectModelAssociationClass)input;
174             associationClass = true;
175             generateProperties(association.getParticipantsAttributes());
176             associationClass = false;
177         }
178 
179         closeAcceptInternalOperation();
180 
181         // Add extra constants (from uml dependency)
182         generateExtraConstants(input);
183 
184         // Add extra operations (defined on the entity)
185         generateExtraOperations(input);
186 
187         // Implement aggregate and composite operations
188         generateAggregateOperation(input);
189         generateCompositeOperation(input);
190 
191         // Implement toString operation
192         if (TopiaGeneratorUtil.generateToString(input, model)) {
193             generateToStringOperation(input);
194         }
195 
196         // Generate serialVersionUID on abstract class
197         generateSerialVersionUID(input, outputAbstract);
198 
199         // Generate Entity Implementation class
200         if (generateImpl) {
201             generateImpl(input);
202             generateSerialVersionUID(input, outputImpl);
203         }
204 
205 
206 
207         // Clean data output after transformation
208         clean();
209     }
210 
211     protected void generateSerialVersionUID(ObjectModelClass input,
212                                             ObjectModelClass ouput) {
213 
214         // serialVersionUID
215         String svUID = TopiaGeneratorUtil.findTagValue(TopiaGeneratorUtil.SERIAL_VERSION_UID,
216                                                        input,
217                                                        model
218         );
219         if (svUID == null) {
220 
221             // use a default one
222             svUID = TopiaGeneratorUtil.generateSerialVersionUID(ouput) + "L";
223         }
224         addConstant(ouput, TopiaGeneratorUtil.SERIAL_VERSION_UID, long.class, svUID,
225                         ObjectModelJavaModifier.PRIVATE);
226     }
227 
228     protected void createEntityInterface(ObjectModelClass input) {
229 
230         outputInterface = createInterface(input.getName(),
231                                           input.getPackageName());
232 
233         // Documentation
234         if (TopiaGeneratorUtil.hasDocumentation(input)) {
235             setDocumentation(outputInterface, input.getDocumentation());
236         }
237 
238         if (log.isTraceEnabled()) {
239             log.trace("Will add interfaces on " +
240                       outputInterface.getQualifiedName());
241         }
242 
243         List<String> interfaceAlreadyDone = new LinkedList<String> ();
244         // Extends
245         for (ObjectModelClassifier parent : input.getInterfaces()) {
246             addInterface(interfaceAlreadyDone, outputInterface, parent);
247         }
248 
249         // Extends from inheritance
250         boolean needTopiaEntity = true;
251         for (ObjectModelClassifier parent : input.getSuperclasses()) {
252             if (TopiaGeneratorUtil.isEntity(parent)) {
253                 addInterface(interfaceAlreadyDone, outputInterface, parent);
254                 needTopiaEntity = false;
255             }
256         }
257 
258         // Extends TopiaEntity (only if hasn't parent entity)
259         if (needTopiaEntity) {
260 
261             Class<?> interfaze = TopiaEntity.class;
262 
263             if (TopiaGeneratorUtil.isContextable(input)) {
264                 interfaze = TopiaEntityContextable.class;
265             }
266             
267             addInterface(interfaceAlreadyDone,
268                          outputInterface,
269                          interfaze);
270         }
271     }
272 
273     protected void createEntityAbstractClass(ObjectModelClass input) {
274 
275         outputAbstract = createAbstractClass(input.getName() + "Abstract",
276                 input.getPackageName());
277 
278         // Documentation
279         StringBuilder doc = new StringBuilder();
280         doc.append("Implantation POJO pour l'entité {@link ");
281         doc.append(StringUtils.capitalize(outputInterface.getName()));
282         doc.append("}\n");
283 
284         String dbName = TopiaGeneratorUtil.getDbName(input);
285         if (dbName != null) {
286             doc.append("<p>Nom de l'entité en BD : ");
287             doc.append(dbName);
288             doc.append(".</p>");
289         }
290 
291         setDocumentation(outputAbstract, doc.toString());
292 
293         // Implements
294         addInterface(outputAbstract, outputInterface.getName());
295 
296         // Extends
297         for (ObjectModelClass parent : input.getSuperclasses()) {
298             //tchemit-2011-09-12 What ever abstract or not, we alwyas use an Impl, moreover use the util method instead
299             String extendClass = TopiaGeneratorUtil.getDOType(parent, model);
300 //            String extendClass = parent.getQualifiedName();
301 //            //Si une des classes parentes définies des méthodes abstraites, son
302 //            // impl ne sera pas créé
303 //            boolean abstractParent = TopiaGeneratorUtil.shouldBeAbstract(parent);
304 //            if (TopiaGeneratorUtil.isEntity(parent)) {
305 //                if (abstractParent) {
306 //                    extendClass += "Abstract";
307 //                } else {
308 //                    extendClass += "Impl";
309 //                }
310 //            }
311             setSuperClass(outputAbstract, extendClass);
312         }
313 
314         // Extends TopiaEntityAbstract (only if hasn't parent entity)
315         if (outputAbstract.getSuperclasses().isEmpty()) {
316             setSuperClass(outputAbstract, TopiaEntityAbstract.class);
317         }
318 
319         addContextableMethods(input, outputAbstract);
320     }
321 
322     /**
323      * Ajout les methodes necessaire à l'interface {@link TopiaEntityContextable}
324      * si le tagValue {@link TopiaTagValues#TAG_CONTEXTABLE} est renseigné.
325      * @param input
326      * @param outputAbstract
327      */
328     protected void addContextableMethods(ObjectModelClass input,
329                                          ObjectModelClass outputAbstract) {
330 
331         if (TopiaGeneratorUtil.isContextable(input)) {
332 
333             addImport(outputAbstract, TopiaContextImplementor.class);
334 
335             ObjectModelOperation op = addOperation(outputAbstract, "update", "void",
336                     ObjectModelJavaModifier.PUBLIC);
337             addException(op, TopiaException.class);
338 //            setDocumentation(op,"@since 2.5.3");
339             addAnnotation(outputAbstract, op, Override.class.getSimpleName());
340             setOperationBody(op, ""
341 /*{
342         ((TopiaContextImplementor)getTopiaContext()).getDAO(<%=input.getName()%>.class).update(this);
343 }*/
344             );
345             
346             op = addOperation(outputAbstract, "delete", "void", ObjectModelJavaModifier.PUBLIC);
347             addException(op, TopiaException.class);
348 //            setDocumentation(op,"@since 2.5.3");
349             addAnnotation(outputAbstract, op, Override.class.getSimpleName());
350             setOperationBody(op, ""
351 /*{
352         ((TopiaContextImplementor)getTopiaContext()).getDAO(<%=input.getName()%>.class).delete(this);
353 }*/
354             );
355         }
356     }
357 
358     protected boolean isGenerateInterface(ObjectModelClass input) {
359 
360         boolean alreadyInClassPath = !isInClassPath(input);
361         return  alreadyInClassPath;
362     }
363 
364     protected boolean isGenerateAbstract(ObjectModelClass input) {
365 
366         String fqn = input.getQualifiedName() + " Abstract";
367         boolean alreadyInClassPath = !isInClassPath(fqn);
368         return  alreadyInClassPath;
369     }
370 
371     protected boolean isGenerateImpl(ObjectModelClass input) {
372 
373         Collection<ObjectModelOperation> operations = input.getOperations();
374         String fqn = input.getQualifiedName() + "Impl";
375 
376         boolean alreadyInClassPath = isInClassPath(fqn);
377         if (alreadyInClassPath) {
378 
379             return false;
380         }
381 
382         // On ne génère pas le impl si l'entité a des opérations
383         if (!operations.isEmpty()) {
384 
385             log.info("Will not generate [" + fqn + "], there is some operations to manually implement");
386             return false;
387         }
388 
389         //De même, on ne génère pas le impl si il y a des opérations venant des
390         // superclasses non implémentées
391         for (ObjectModelOperation otherOp : input.getAllOtherOperations(false)) {
392             if (otherOp.isAbstract()) {
393                 log.info("Will not generate [" + fqn + "], there is an abstract operation [" + otherOp.getName() + "] in allOtherOperations.");
394                 return false;
395             }
396         }
397 
398         return true;
399     }
400 
401     protected void generateImpl(ObjectModelClass input) {
402 
403         String implName = input.getName() + "Impl";
404         String packageName = input.getPackageName();
405         if (isVerbose()) {
406             log.info("Will generate [" + implName + "]");
407         }
408 
409         if (isAbstract(input)) {
410             outputImpl = createAbstractClass(implName, packageName);
411         } else {
412             outputImpl = createClass(implName, packageName);
413         }
414 
415         setDocumentation(outputImpl, "Implantation des operations pour l'entité " +
416                                  input.getName() + ".");
417         setSuperClass(outputImpl, input.getQualifiedName() + "Abstract");
418     }
419 
420     /**
421      * Generate extra constants if {@code input} has dependencies on
422      * enum used as constant injector.
423      *
424      * @param input Entity class to treate
425      */
426     protected void generateExtraConstants(ObjectModelClass input) {
427         Set<String> constants = addConstantsFromDependency(input, outputInterface);
428 
429         if (log.isDebugEnabled()) {
430             log.debug("Add constants from dependency : " + constants);
431         }
432     }
433 
434     protected void generateExtraOperations(ObjectModelClass input) {
435         for (ObjectModelOperation operation : input.getOperations()) {
436 
437             String opName = operation.getName();
438             String opType = operation.getReturnType();
439             ObjectModelModifier visibility =
440                     ObjectModelJavaModifier.fromVisibility(operation.getVisibility());
441 
442             if (log.isDebugEnabled()) {
443                 log.debug("Extra operation for : " + input.getQualifiedName() +
444                         " - method : " + opName +
445                         " - returnType : " + opType +
446                         " - visibility : " + visibility);
447             }
448 
449             // Deprecated from 2.3.4
450             // Pas de génération des signatures de méthodes pour celles à intégrer au DAO de l'entité
451             if (TopiaGeneratorUtil.hasDaoStereotype(operation)) {
452                 return;
453 
454             // Generate entity methods which have not a public visibility.
455             // Only in abstract entity class as abstract operation.
456             } else if (!visibility.equals(ObjectModelJavaModifier.PUBLIC)) {
457                 addOperation(outputAbstract, opName, opType, visibility,
458                         ObjectModelJavaModifier.ABSTRACT);
459 
460             // Other operations, only in entity interface, implementations
461             // need to be done in implementation class created by developper
462             } else {
463                 cloneOperationSignature(operation, outputInterface, true);
464             }
465         }
466     }
467 
468     /**
469      * Generate properties from {@code attributes}. Generate
470      * constant, attribute and operations for each property.
471      *
472      * @param attributes Input attributes
473      */
474     protected void generateProperties(Collection<ObjectModelAttribute> attributes) {
475         for (ObjectModelAttribute attribute : attributes) {
476 
477             if (!associationClass) {
478 
479                 // FIXME-fdesbois-2010-06-25 : Strange behavior to keep those links, will break hibernate, may be a problem in mapping
480                 if (!attribute.isNavigable() && attribute.hasAssociationClass()) {
481                     generatePropertyConstant(attribute);
482 
483                     generatePropertyAttribute(attribute);
484 
485                     // 20161004 poussin
486                     // If attribute is not navigable then visitor must not try to visit it
487                     // updateAcceptOperation(attribute);
488                 }
489 
490                 if (!attribute.isNavigable() &&
491                         !TopiaGeneratorUtil.hasUnidirectionalRelationOnAbstractType(
492                                 attribute.getReverseAttribute(), model)) {
493                     continue;
494                 }
495             }
496 
497             // constant
498             generatePropertyConstant(attribute);
499 
500             // attribute
501             generatePropertyAttribute(attribute);
502 
503             // operations
504             generatePropertyOperations(attribute);
505 
506             // update accept body
507             updateAcceptOperation(attribute);
508         }
509     }
510 
511     // -------------------------------------------------------------------------
512     // Generate for property
513     // -------------------------------------------------------------------------
514 
515     /**
516      * Generate constant in interface for {@code attribute}.
517      *
518      * @param attribute Input attribute to treate
519      * @see #getPropertyName(ObjectModelAttribute)
520      */
521     protected void generatePropertyConstant(ObjectModelAttribute attribute) {
522         String attrName = getPropertyName(attribute);
523 
524         if (log.isDebugEnabled()) {
525             log.debug("Generate constant for property : " + attrName);
526         }
527 
528         addAttribute(outputInterface, getConstantName(attrName), String.class,
529                 "\"" + attrName + "\"");
530     }
531 
532     protected void generatePropertyAttribute(ObjectModelAttribute attribute) {
533 
534         String attrName = getPropertyName(attribute);
535         String attrType = getPropertyType(attribute);
536         String collectionType = getCollectionType(attribute);
537 
538         if (collectionType != null) {
539             attrType = collectionType + "<" + attrType + ">";
540         }
541 
542         //String attrVisibility = attr.getVisibility();
543 
544         // Declaration
545         ObjectModelAttribute property =
546                 addAttribute(outputAbstract, attrName, attrType, null,
547                 //ObjectModelJavaModifier.toValue(attrVisibility),
548                 ObjectModelJavaModifier.PROTECTED
549         );
550 
551         // Documentation
552         StringBuilder buffer = new StringBuilder();
553         if (TopiaGeneratorUtil.hasDocumentation(attribute)) {
554             String attrDocumentation = attribute.getDocumentation();
555             buffer.append(attrDocumentation).append('\n');
556         }
557 
558         String dbName = TopiaGeneratorUtil.getDbName(attribute);
559         if (!StringUtils.isEmpty(dbName)) {
560             buffer.append("Nom de l'attribut en BD : ").append(dbName).append('\n');
561         }
562         setDocumentation(property, buffer.toString());
563 
564         // Annotation
565         String annotation =  TopiaGeneratorUtil.getAnnotationTagValue(attribute);
566         if (!StringUtils.isEmpty(annotation)) {
567             //FIXME Make annotation works...
568             //TODO tchemit 20100513 Test it still works
569             addAnnotation(outputAbstract, property, annotation);
570         }
571     }
572 
573     /**
574      * Generation operations for {@code attributes}.
575      * One method exists for each operation to generate. Methods starting
576      * with 'addSingle' is for maxMultiplicity attribute = 1 and for collection
577      * case, methods start with 'addMultiple'. Other case are take care in each
578      * method (association class, reverse, entity reference, ...).
579      *
580      * @param attribute Input attribute to treate
581      * @see #addSingleGetOperation(ObjectModelAttribute, String, String)
582      * @see #addSingleSetOperation(ObjectModelAttribute)
583      * @see #addMultipleAddOperation(ObjectModelAttribute, String)
584      * @see #addMultipleAddAllOperation(ObjectModelAttribute, String)
585      * @see #addMultipleSetOperation(ObjectModelAttribute, String, String)
586      * @see #addMultipleRemoveOperation(ObjectModelAttribute)
587      * @see #addMultipleClearOperation(ObjectModelAttribute, String, String)
588      * @see #addMultipleGetOperation(ObjectModelAttribute, String)
589      * @see #addMultipleGetTopiaIdOperation(ObjectModelAttribute)
590      * @see #addMultipleGetOperationFromEntity(ObjectModelAttribute)
591      * @see #addMultipleSizeOperation(ObjectModelAttribute)
592      * @see #addMultipleIsEmptyOperation(ObjectModelAttribute)
593      */
594     protected void generatePropertyOperations(ObjectModelAttribute attribute) {
595 
596         if (attribute.getMaxMultiplicity() == 1 || associationClass) {
597 
598             // setXXX
599             addSingleSetOperation(attribute);
600 
601             boolean booleanProperty =
602                     TopiaGeneratorUtil.isBooleanPrimitive(attribute);
603             
604             String attrType = getPropertyType(attribute);
605 
606             if (booleanProperty) {
607 
608                 // isXXX
609                 addSingleGetOperation(
610                         attribute,
611                         attrType,
612                         TopiaGeneratorUtil.OPERATION_GETTER_BOOLEAN_PREFIX);
613             }
614 
615             if (!booleanProperty || generateBooleanGetMethods) {
616                 
617                 // getXXX
618                 addSingleGetOperation(
619                         attribute,
620                         attrType,
621                         TopiaGeneratorUtil.OPERATION_GETTER_DEFAULT_PREFIX);
622             }
623 
624         } else {
625 
626             // List, Set or Collection ?
627             String collectionInterface =
628                     TopiaGeneratorUtil.getNMultiplicityInterfaceType(attribute);
629             String collectionImpl =
630                     TopiaGeneratorUtil.getNMultiplicityObjectType(attribute);
631 
632             addImport(outputInterface, collectionInterface);
633             addImport(outputAbstract, collectionInterface);
634             addImport(outputAbstract, collectionImpl);
635 
636             collectionInterface =
637                     TopiaGeneratorUtil.getSimpleName(collectionInterface);
638             collectionImpl =
639                     TopiaGeneratorUtil.getSimpleName(collectionImpl);
640 
641             // addXXX
642             addMultipleAddOperation(attribute, collectionImpl);
643 
644             // addAllXXX
645             addMultipleAddAllOperation(attribute, collectionInterface);
646 
647             // setXXX
648             addMultipleSetOperation(attribute, collectionInterface, collectionImpl);
649 
650             // removeXXX
651             addMultipleRemoveOperation(attribute);
652 
653             // clearXXX
654             addMultipleClearOperation(attribute, collectionInterface, collectionImpl);
655 
656             // getXXX
657             addMultipleGetOperation(attribute, collectionInterface);
658 
659             if (TopiaGeneratorUtil.isEntity(attribute, model)) {
660 
661                 // getXXXByTopiaId
662                 addMultipleGetTopiaIdOperation(attribute);
663             }
664 
665             if (attribute.hasAssociationClass()) {
666                 // getXXX with entity parameter
667                 addMultipleGetOperationFromEntity(attribute);
668             }
669 
670             // sizeXXX
671             addMultipleSizeOperation(attribute);
672 
673             // isXXXEmpty
674             addMultipleIsEmptyOperation(attribute);
675         }
676     }
677 
678     protected void addSingleSetOperation(ObjectModelAttribute attribute) {
679 
680         String attrName = getPropertyName(attribute);
681         String attrType = getPropertyType(attribute);
682 
683         if (log.isDebugEnabled()) {
684             log.debug("Generate single 'set' operation for property : " + attrName +
685                     " [" + attrType + "]");
686         }
687 
688         // Interface operation
689         ObjectModelOperation interfaceOperation =
690                 createPropertySetterSignature(outputInterface, attrType, attrName,
691                         "");
692 
693         // Implementation
694         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
695 
696         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
697 
698         String constantName  = getConstantName(attrName);
699 
700         setOperationBody(implOperation, ""
701 /*{
702         <%=attrType%> oldValue = this.<%=attrName%>;
703         fireOnPreWrite(<%=constantName%>, oldValue, <%=attrName%>);
704         this.<%=attrName%> = <%=attrName%>;
705         fireOnPostWrite(<%=constantName%>, oldValue, <%=attrName%>);
706     }*/
707         );
708     }
709 
710     /**
711      * Add getter for simple property (neither association nor multiple).
712      * Will add two different operations for boolean case ('is' method and
713      * 'get' method). This method add the operation in both {@code
714      * outputAbstract} and {@code outputInterface}.
715      *
716      * @param attribute         ObjectModelAttribute for getter operation
717      * @param attrType          type of the attribute
718      * @param operationPrefix   Operation prefix : 'get' by default, if prefix
719      *                          is null
720      */
721     protected void addSingleGetOperation(ObjectModelAttribute attribute,
722                                          String attrType,
723                                          String operationPrefix) {
724 
725         String attrName = getPropertyName(attribute);
726 
727         if (log.isDebugEnabled()) {
728             log.debug("Generate single '" + operationPrefix + "' operation for property : "
729                     + attrName + " [" + attrType + "]");
730         }
731 
732         String constantName  = getConstantName(attrName);
733         
734         // Interface operation
735         ObjectModelOperation interfaceOperation =
736                 addOperation(outputInterface, getJavaBeanMethodName(operationPrefix, attrName),
737                     attrType, ObjectModelJavaModifier.PACKAGE);
738 
739         boolean generateReadListeners = !TopiaGeneratorUtil.isDoNotGenerateReadListeners(attribute, model);
740 
741         // Implementation
742         ObjectModelOperation implOperation =
743                 createImplOperation(interfaceOperation);
744 
745         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
746 
747         StringBuilder body = new StringBuilder();
748         if (generateReadListeners) {
749             body.append(""
750 /*{
751         fireOnPreRead(<%=constantName%>, <%=attrName%>);
752 }*/);
753         }
754 
755         body.append(""
756 /*{
757         <%=attrType%> result = this.<%=attrName%>;
758 }*/);
759         
760         if (generateReadListeners) {
761             body.append(""
762 /*{
763         fireOnPostRead(<%=constantName%>, <%=attrName%>);
764 }*/);
765         }
766 
767         body.append(""
768 /*{
769         return result;
770     }*/);
771         setOperationBody(implOperation, body.toString());
772     }
773 
774     protected void addMultipleAddOperation(ObjectModelAttribute attribute,
775                                            String collectionImpl) {
776 
777         String attrName = getPropertyName(attribute);
778         String attrType = getPropertyType(attribute);
779         ObjectModelAttribute reverse = attribute.getReverseAttribute();
780 
781         if (log.isDebugEnabled()) {
782             log.debug("Generate multiple 'add' operation for property : " + attrName +
783                     " [" + attrType + "]");
784         }
785 
786         String constantName = getConstantName(attrName);
787         
788         // Interface operation
789         ObjectModelOperation interfaceOperation =
790                 addOperation(outputInterface, getJavaBeanMethodName("add", attrName),
791                         void.class, ObjectModelJavaModifier.PACKAGE);
792         ObjectModelParameter param =
793                 addParameter(interfaceOperation, attrType, attrName);
794 
795         // Implementation
796         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
797 
798         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
799 
800         StringBuilder body = new StringBuilder();
801 
802         body.append(""
803 /*{
804         fireOnPreWrite(<%=constantName%>, null, <%=attrName%>);
805         if (this.<%=attrName%> == null) {
806             this.<%=attrName%> = new <%=collectionImpl%><<%=attrType%>>();
807         }
808 }*/
809         );
810 
811         if (reverse != null && (reverse.isNavigable() ||
812                 hasUnidirectionalRelationOnAbstractType(attribute, model))) {
813             String getterName = getJavaBeanMethodName("get", reverse.getName());
814             String setterName = getJavaBeanMethodName("set", reverse.getName());
815 
816             String reverseAttrType = TopiaGeneratorUtil.getSimpleName(reverse.getType());
817             
818             if (!TopiaGeneratorUtil.isNMultiplicity(reverse)) {
819                 body.append(""
820 /*{
821         <%=attrName%>.<%=setterName%>(this);
822 }*/
823             );
824         // Don't manage reverse attribute add if attribute has associationClass
825         } else if (!attribute.hasAssociationClass()) {
826             body.append(""
827 /*{
828         if (<%=attrName%>.<%=getterName%>() == null) {
829             <%=attrName%>.<%=setterName%>(new <%=collectionImpl%><<%=reverseAttrType%>>());
830         }
831         <%=attrName%>.<%=getterName%>().add(this);
832 }*/
833                 );
834             }
835         }
836         body.append(""
837 /*{
838         this.<%=attrName%>.add(<%=attrName%>);
839         fireOnPostWrite(<%=constantName%>, this.<%=attrName%>.size(), null, <%=attrName%>);
840     }*/
841         );
842         setOperationBody(implOperation, body.toString());
843     }
844 
845     protected void addMultipleAddAllOperation(ObjectModelAttribute attribute,
846                                               String collectionInterface) {
847 
848         String attrName = getPropertyName(attribute);
849         String attrType = getPropertyType(attribute);
850 
851         if (log.isDebugEnabled()) {
852             log.debug("Generate multiple 'addAll' operation for property : " + attrName +
853                     " [" + attrType + "]");
854         }
855 
856         // Interface operation
857         ObjectModelOperation interfaceOperation =
858                 addOperation(outputInterface, getJavaBeanMethodName("addAll", attrName),
859                         void.class, ObjectModelJavaModifier.PACKAGE);
860         ObjectModelParameter param =
861                 addParameter(interfaceOperation, collectionInterface + "<" + attrType + ">", attrName);
862 
863         // Implementation
864         ObjectModelOperation implOperation =
865                 createImplOperation(interfaceOperation);
866 
867         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
868         String addMethodName = getJavaBeanMethodName("add", attrName);
869         setOperationBody(implOperation, ""
870 /*{
871         if (<%=attrName%> == null) {
872             return;
873         }
874         for (<%=attrType%> item : <%=attrName%>) {
875             <%=addMethodName%>(item);
876         }
877     }*/
878         );
879     }
880 
881     protected void addMultipleSetOperation(ObjectModelAttribute attribute,
882                                            String collectionInterface,
883                                            String collectionImpl) {
884 
885         String attrName = getPropertyName(attribute);
886         String referenceType = getPropertyType(attribute);
887         String attrType = collectionInterface + "<" + referenceType + ">";
888         String constantName = getConstantName(attrName);
889         
890         if (log.isDebugEnabled()) {
891             log.debug("Generate multiple 'set' operation for property : " + attrName +
892                     " [" + attrType + "]");
893         }
894 
895         // Interface operation
896         ObjectModelOperation interfaceOperation =
897                 createPropertySetterSignature(outputInterface, attrType, attrName,
898                         "");
899 
900         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
901 
902         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
903         referenceType = TopiaGeneratorUtil.getSimpleName(referenceType);
904 
905         // Force fire for collection
906         setOperationBody(implOperation, ""
907 /*{
908         // Copy elements to keep data for fire with new reference
909         <%=attrType%> oldValue = this.<%=attrName%> != null ? new <%=collectionImpl%><<%=referenceType%>>(this.<%=attrName%>) : null;
910         fireOnPreWrite(<%=constantName%>, oldValue, <%=attrName%>);
911         this.<%=attrName%> = <%=attrName%>;
912         fireOnPostWrite(<%=constantName%>, oldValue, <%=attrName%>);
913     }*/
914         );
915     }
916 
917     protected void addMultipleRemoveOperation(ObjectModelAttribute attribute) {
918 
919         String attrName = getPropertyName(attribute);
920         String attrType = getPropertyType(attribute);
921         ObjectModelAttribute reverse = attribute.getReverseAttribute();
922         String constantName = getConstantName(attrName);
923         
924         if (log.isDebugEnabled()) {
925             log.debug("Generate 'remove' operation for property : " + attrName +
926                     " [" + attrType + "]");
927         }
928 
929         // Interface operation
930         ObjectModelOperation interfaceOperation =
931                 addOperation(outputInterface, getJavaBeanMethodName("remove" , attrName),
932                         void.class, ObjectModelJavaModifier.PACKAGE);
933         ObjectModelParameter param =
934                 addParameter(interfaceOperation, attrType, attrName);
935 
936         // Implementation
937         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
938 
939         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
940 
941         StringBuilder body = new StringBuilder();
942 
943         body.append(""
944 /*{
945         fireOnPreWrite(<%=constantName%>, <%=attrName%>, null);
946         if (this.<%=attrName%> == null || !this.<%=attrName%>.remove(<%=attrName%>)) {
947             throw new IllegalArgumentException("List does not contain given element");
948         }
949 }*/
950         );
951 
952         if (reverse != null && (reverse.isNavigable() ||
953                 hasUnidirectionalRelationOnAbstractType(attribute, model))) {
954             String getterName = getJavaBeanMethodName("get", reverse.getName());
955             String setterName = getJavaBeanMethodName("set", reverse.getName());
956             if (!TopiaGeneratorUtil.isNMultiplicity(reverse)) {
957                 body.append(""
958 /*{
959         <%=attrName%>.<%=setterName%>(null);
960 }*/
961             );
962         // Don't manage reverse attribute remove if attribute has associationClass
963         } else if (!attribute.hasAssociationClass()) {
964             body.append(""
965 /*{
966         <%=attrName%>.<%=getterName%>().remove(this);
967 }*/
968                 );
969             }
970         }
971         body.append(""
972 /*{
973         fireOnPostWrite(<%=constantName%>, this.<%=attrName%>.size() + 1, <%=attrName%>, null);
974     }*/
975         );
976         setOperationBody(implOperation, body.toString());
977     }
978 
979     protected void addMultipleClearOperation(ObjectModelAttribute attribute,
980                                              String collectionInterface,
981                                              String collectionImpl) {
982 
983         String attrName = getPropertyName(attribute);
984         String attrType = getPropertyType(attribute);
985         ObjectModelAttribute reverse = attribute.getReverseAttribute();
986         String constantName = getConstantName(attrName);
987         
988         if (log.isDebugEnabled()) {
989             log.debug("Generate multiple 'clear' operation for property : " + attrName +
990                     " [" + attrType + "]");
991         }
992 
993         // Interface operation
994         ObjectModelOperation interfaceOperation =
995                 addOperation(outputInterface, getJavaBeanMethodName("clear" , attrName),
996                         void.class, ObjectModelJavaModifier.PACKAGE);
997 
998         // Implementation
999         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
1000 
1001         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
1002 
1003         StringBuilder body = new StringBuilder(""
1004 /*{
1005         if (this.<%=attrName%> == null) {
1006             return;
1007         }
1008 }*/
1009         );
1010 
1011         if (reverse != null && (reverse.isNavigable() ||
1012                 hasUnidirectionalRelationOnAbstractType(attribute, model))) {
1013             String getterName = getJavaBeanMethodName("get", reverse.getName());
1014             String setterName = getJavaBeanMethodName("set", reverse.getName());
1015             body.append(""
1016 /*{        for (<%=attrType%> item : this.<%=attrName%>) {
1017 }*/
1018             );
1019             if (!TopiaGeneratorUtil.isNMultiplicity(reverse)) {
1020                 body.append(""
1021 /*{            item.<%=setterName%>(null);
1022 }*/
1023                 );
1024             // Don't manage reverse attribute remove if attribute has associationClass
1025             }  else if (!attribute.hasAssociationClass())  {
1026                 body.append(""
1027 /*{            item.<%=getterName%>().remove(this);
1028 }*/
1029                 );
1030             }
1031             body.append(""
1032 /*{        }
1033 }*/
1034             );
1035         }
1036         body.append(""
1037 /*{        <%=collectionInterface%><<%=attrType%>> oldValue = new <%=collectionImpl%><<%=attrType%>>(this.<%=attrName%>);
1038         fireOnPreWrite(<%=constantName%>, oldValue, this.<%=attrName%>);
1039         this.<%=attrName%>.clear();
1040         fireOnPostWrite(<%=constantName%>, oldValue, this.<%=attrName%>);
1041     }*/
1042         );
1043         setOperationBody(implOperation, body.toString());
1044     }
1045 
1046     protected void addMultipleGetOperation(ObjectModelAttribute attribute,
1047                                            String collectionInterface) {
1048 
1049         String attrName = getPropertyName(attribute);
1050         String attrType = collectionInterface + "<" + getPropertyType(attribute) + ">";
1051 
1052         if (log.isDebugEnabled()) {
1053             log.debug("Generate multiple 'get' operation for property : " + attrName +
1054                     " [" + attrType + "]");
1055         }
1056 
1057         // Interface operation
1058         ObjectModelOperation interfaceOperation =
1059                 addOperation(outputInterface, getJavaBeanMethodName("get" , attrName),
1060                         attrType, ObjectModelJavaModifier.PACKAGE);
1061 
1062         // Implementation
1063         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
1064 
1065         setOperationBody(implOperation, ""
1066 /*{
1067         return <%=attrName%>;
1068     }*/
1069         );
1070     }
1071 
1072     protected void addMultipleGetTopiaIdOperation(ObjectModelAttribute attribute) {
1073 
1074         String attrName = getPropertyName(attribute);
1075         String attrType = getPropertyType(attribute);
1076 
1077         if (log.isDebugEnabled()) {
1078             log.debug("Generate multiple 'getByTopiaId' operation for property : " + attrName +
1079                     " [" + attrType + "]");
1080         }
1081 
1082         // Interface operation
1083         ObjectModelOperation interfaceOperation =
1084                 addOperation(outputInterface, getJavaBeanMethodName("get", attrName) + "ByTopiaId",
1085                             attrType, ObjectModelJavaModifier.PACKAGE);
1086         ObjectModelParameter param =
1087                 addParameter(interfaceOperation, String.class, "topiaId");
1088 
1089         // Implementation
1090         ObjectModelOperation implOperation =
1091                 createImplOperation(interfaceOperation);
1092 
1093         addImport(outputAbstract, TopiaEntityHelper.class);
1094 
1095         setOperationBody(implOperation, ""
1096 /*{
1097         return TopiaEntityHelper.getEntityByTopiaId(<%=attrName%>, topiaId);
1098     }*/
1099         );
1100     }
1101 
1102     protected void addMultipleGetOperationFromEntity(ObjectModelAttribute attribute) {
1103 
1104         // reference to the real attribute name
1105         String referenceName = attribute.getName();
1106         String referenceType = attribute.getType();
1107 
1108         String referenceGetterName = getJavaBeanMethodName("get", referenceName);
1109         // association attribute name
1110         String attrName = getPropertyName(attribute);
1111         String attrType = getPropertyType(attribute);
1112 
1113         if (log.isDebugEnabled()) {
1114             log.debug("Generate multiple 'getFromEntity' operation for property : " + attrName +
1115                     " [" + attrType + "]");
1116         }
1117 
1118         // Interface operation
1119         ObjectModelOperation interfaceOperation =
1120                 addOperation(outputInterface,
1121                         getJavaBeanMethodName("get", attrName), attrType);
1122 
1123         addParameter(interfaceOperation, referenceType, referenceName);
1124 
1125         // Implementation
1126         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
1127 
1128         attrType = TopiaGeneratorUtil.getSimpleName(attrType);
1129 
1130         setOperationBody(implOperation, ""
1131 /*{
1132         if (<%=referenceName%> == null || this.<%=attrName%> == null) {
1133             return null;
1134         }
1135         for (<%=attrType%> item : this.<%=attrName%>) {
1136             if (<%=referenceName%>.equals(item.<%=referenceGetterName%>())) {
1137                 return item;
1138             }
1139         }
1140         return null;
1141     }*/
1142         );
1143     }
1144 
1145     protected void addMultipleSizeOperation(ObjectModelAttribute attribute) {
1146 
1147         String attrName = getPropertyName(attribute);
1148 
1149         if (log.isDebugEnabled()) {
1150             log.debug("Generate multiple 'size' operation for property : " + attrName);
1151         }
1152 
1153         // Interface operation
1154         ObjectModelOperation interfaceOperation =
1155                 addOperation(outputInterface, getJavaBeanMethodName("size", attrName),
1156                         int.class, ObjectModelJavaModifier.PACKAGE);
1157 
1158         // Implementation
1159         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
1160 
1161         setOperationBody(implOperation, ""
1162 /*{
1163         if (<%=attrName%> == null) {
1164             return 0;
1165         }
1166         return <%=attrName%>.size();
1167     }*/
1168         );
1169     }
1170 
1171     protected void addMultipleIsEmptyOperation(ObjectModelAttribute attribute) {
1172 
1173         String attrName = getPropertyName(attribute);
1174 
1175         if (log.isDebugEnabled()) {
1176             log.debug("Generate multiple 'isEmpty' operation for property : " + attrName);
1177         }
1178 
1179         String sizeMethodName = getJavaBeanMethodName("size", attrName);
1180         // Interface operation
1181         ObjectModelOperation interfaceOperation =
1182                 addOperation(outputInterface, getJavaBeanMethodName("is", attrName)+ "Empty",
1183                         boolean.class, ObjectModelJavaModifier.PACKAGE);
1184 
1185         // Implementation
1186         ObjectModelOperation implOperation = createImplOperation(interfaceOperation);
1187 
1188         setOperationBody(implOperation, ""
1189 /*{
1190         int size = <%=sizeMethodName%>();
1191         return size == 0;
1192     }*/
1193         );
1194     }
1195 
1196     // -------------------------------------------------------------------------
1197     // Generate util operations
1198     // -------------------------------------------------------------------------
1199 
1200     private ObjectModelOperation internalAcceptOperation;
1201 
1202     private StringBuilder internalAcceptOperationBody;
1203 
1204     protected void createAcceptOperation() {
1205 
1206         ObjectModelOperation acceptOperation = addOperation(outputAbstract, "accept", void.class);
1207         addAnnotation(outputAbstract, acceptOperation , Override.class);
1208         addParameter(acceptOperation, EntityVisitor.class, "visitor");
1209 
1210         addException(acceptOperation, TopiaException.class);
1211 
1212         setOperationBody(acceptOperation,""
1213 /*{
1214         visitor.start(this);
1215         accept0(visitor);
1216         visitor.end(this);
1217     }*/
1218         );
1219     }
1220 
1221     protected void createAcceptInternalOperation(ObjectModelClass input) {
1222 
1223         boolean withSuperEntity = false;
1224         for (ObjectModelClassifier parent : input.getSuperclasses()) {
1225             if (TopiaGeneratorUtil.isEntity(parent)) {
1226                 withSuperEntity= true;
1227                 break;
1228             }
1229         }
1230 
1231         internalAcceptOperation = addOperation(outputAbstract, "accept0", void.class, ObjectModelJavaModifier.PROTECTED);
1232         addParameter(internalAcceptOperation, EntityVisitor.class, "visitor");
1233         addException(internalAcceptOperation, TopiaException.class);
1234 
1235         if (withSuperEntity) {
1236             addAnnotation(outputAbstract, internalAcceptOperation, Override.class);
1237             internalAcceptOperationBody = new StringBuilder(""
1238 /*{
1239         super.accept0(visitor);
1240 }*/
1241             );
1242         } else {
1243             internalAcceptOperationBody= new StringBuilder(""
1244 /*{
1245 }*/
1246             );
1247         }
1248     }
1249 
1250     protected void updateAcceptOperation(ObjectModelAttribute attribute) {
1251         String attrName =
1252                 TopiaGeneratorUtil.getSimpleName(getPropertyName(attribute));
1253         String attrType =
1254                 TopiaGeneratorUtil.getSimpleName(getPropertyType(attribute));
1255         String collectionType = getCollectionType(attribute);
1256         String constantName = getConstantName(attrName);
1257         if (collectionType != null) {
1258             collectionType = TopiaGeneratorUtil.getSimpleName(collectionType);
1259             internalAcceptOperationBody.append(""
1260 /*{        visitor.visit(this, <%=constantName%>, <%=collectionType%>.class, <%=attrType%>.class, <%=attrName%>);
1261 }*/
1262             );
1263         } else {
1264             internalAcceptOperationBody.append(""
1265 /*{        visitor.visit(this, <%=constantName%>, <%=attrType%>.class, <%=attrName%>);
1266 }*/
1267             );
1268         }
1269     }
1270 
1271     protected void closeAcceptInternalOperation() {
1272 
1273         setOperationBody(internalAcceptOperation, internalAcceptOperationBody.toString() + ""
1274 /*{    }*/
1275         );
1276     }
1277 
1278     protected void generateToStringOperation(ObjectModelClass input) {
1279 
1280         if (log.isDebugEnabled()) {
1281             log.debug("generate toString method for entity " +
1282                     outputInterface.getQualifiedName());
1283         }
1284         ObjectModelOperation operation =
1285                 addOperation(outputAbstract, "toString", String.class);
1286 
1287         addAnnotation(outputAbstract, operation, Override.class.getSimpleName());
1288 
1289         addImport(outputAbstract, ToStringBuilder.class);
1290 
1291         StringBuilder body = new StringBuilder(""
1292 /*{
1293         String result = new ToStringBuilder(this).
1294 }*/
1295         );
1296         for (ObjectModelAttribute attr : input.getAttributes()) {
1297 
1298             //FIXME possibilité de boucles (non directes)
1299 
1300             ObjectModelClass attrEntity = null;
1301 
1302             if (model.hasClass(attr.getType())) {
1303                 attrEntity = model.getClass(attr.getType());
1304             }
1305 
1306             boolean isEntity = attrEntity != null &&
1307                     TopiaGeneratorUtil.isEntity(attrEntity);
1308 
1309             ObjectModelAttribute reverse = attr.getReverseAttribute();
1310             if (isEntity && (reverse == null || !reverse.isNavigable())
1311                     && !attr.hasAssociationClass() || !isEntity) {
1312                 String attrName = attr.getName();
1313                 String constantName = getConstantName(attrName);
1314                 body.append(""
1315 /*{            append(<%=constantName%>, this.<%=attrName%>).
1316 }*/
1317                 );
1318             }
1319         }
1320         body.append(""
1321 /*{         toString();
1322         return result;
1323     }*/
1324         );
1325         setOperationBody(operation, body.length() == 0 ? " " : body.toString());
1326 
1327     }
1328 
1329     protected void generateCompositeOperation(ObjectModelClass input) {
1330 
1331         ObjectModelOperation operation =
1332                 addOperation(outputAbstract, "getComposite",
1333                 List.class.getName() + '<' + TopiaEntity.class.getName() + '>');
1334 
1335         addException(operation, TopiaException.class);
1336         addAnnotation(outputAbstract, operation, Override.class.getSimpleName());
1337 
1338         addImport(outputAbstract, ArrayList.class);
1339         addImport(outputAbstract, List.class);
1340 
1341         StringBuilder body = new StringBuilder(""
1342 /*{
1343         List<TopiaEntity> tmp = new ArrayList<TopiaEntity>();
1344 
1345         // pour tous les attributs rechecher les composites et les class d'asso
1346         // on les ajoute dans tmp
1347 }*/
1348         );
1349         for (ObjectModelAttribute attr : input.getAttributes()) {
1350 
1351             if (attr.referenceClassifier() &&
1352                     TopiaGeneratorUtil.isEntity(attr.getClassifier())) {
1353 
1354                 if (attr.isComposite()) {
1355                     String attrName = attr.getName();
1356                     String getterName = getJavaBeanMethodName("get", attrName);
1357                     if (TopiaGeneratorUtil.isNMultiplicity(attr)) {
1358                         body.append(""
1359 /*{        if (<%=getterName%>() != null) {
1360               tmp.addAll(<%=getterName%>());
1361            }
1362 }*/
1363                         );
1364                     } else {
1365                         body.append(""
1366 /*{        tmp.add(<%=getterName%>());
1367 }*/
1368                         );
1369                     }
1370                 } else if (attr.hasAssociationClass()) {
1371                     String assocAttrName = TopiaGeneratorUtil.getAssocAttrName(
1372                             attr);
1373                     String assocClassFQN = TopiaGeneratorUtil.getSimpleName(
1374                             attr.getAssociationClass().getQualifiedName());
1375                     String ref = "this." + TopiaGeneratorUtil.toLowerCaseFirstLetter(
1376                             assocAttrName);
1377                     if (!TopiaGeneratorUtil.isNMultiplicity(attr)) {
1378                         body.append(""
1379 /*{
1380         if (<%=ref%> != null) {
1381             tmp.add(<%=ref%>);
1382         }
1383 }*/
1384                         );
1385                     } else {
1386                         ObjectModelAttribute reverse = attr.getReverseAttribute();
1387                         String reverseAttrName = reverse.getName();
1388                         // On utilise pas l'attribut car il est potentiellement
1389                         // pas a jour, car  pour les asso avec cardinalité
1390                         // personne ne fait de add. Ce qui est normal, mais
1391                         // pour pouvoir faire tout de meme des delete en cascade
1392                         // sur les asso, le champs est dans le mapping
1393                         // hibernate et donc il le faut aussi dans la classe
1394                         // sinon hibernate rale lorsqu'il charge l'objet
1395 //                        if (<%=ref%> != null) {
1396 //                            tmp.addAll(<%=ref%>);
1397 //                        }
1398 
1399                         addImport(outputAbstract, TopiaContextImplementor.class);
1400                         body.append(""
1401 /*{
1402         {
1403             org.nuiton.topia.persistence.TopiaDAO<<%=assocClassFQN%>> dao = ((TopiaContextImplementor) getTopiaContext()).getDAO(<%=assocClassFQN%>.class);
1404             List<<%=assocClassFQN%>> findAllByProperties = dao.findAllByProperties("<%=reverseAttrName%>", this);
1405             if (findAllByProperties != null) {
1406                 tmp.addAll(findAllByProperties);
1407             }
1408         }
1409 }*/
1410                         );
1411                     }
1412                 }
1413             }
1414         }
1415         body.append(""
1416 /*{
1417         // on refait un tour sur chaque entity de tmp pour recuperer leur
1418         // composite
1419         List<TopiaEntity> result = new ArrayList<TopiaEntity>();
1420         for (TopiaEntity entity : tmp) {
1421             if (entity != null) {
1422                 result.add(entity);
1423                 result.addAll(entity.getComposite());
1424             }
1425         }
1426         return result;
1427     }*/
1428         );
1429 
1430         setOperationBody(operation, body.length() == 0 ? " " : body.toString());
1431     }
1432 
1433     protected void generateAggregateOperation(ObjectModelClass input) {
1434 
1435         ObjectModelOperation operation =
1436                 addOperation(outputAbstract, "getAggregate",
1437                 List.class.getName() + '<' + TopiaEntity.class.getName() + '>');
1438 
1439         addException(operation, TopiaException.class);
1440         addAnnotation(outputAbstract, operation, Override.class.getSimpleName());
1441 
1442         addImport(outputAbstract, ArrayList.class);
1443         addImport(outputAbstract, List.class);
1444 
1445         StringBuilder body = new StringBuilder(""
1446 /*{
1447         List<TopiaEntity> tmp = new ArrayList<TopiaEntity>();
1448 
1449         // pour tous les attributs rechecher les composites et les class d'asso
1450         // on les ajoute dans tmp
1451 }*/
1452         );
1453         for (ObjectModelAttribute attr : input.getAttributes()) {
1454 
1455             if (attr.referenceClassifier() &&
1456                     TopiaGeneratorUtil.isEntity(attr.getClassifier()) &&
1457                     attr.isAggregate()) {
1458 
1459                 String attrName = attr.getName();
1460                 String getterName = getJavaBeanMethodName("get", attrName);
1461                 if (TopiaGeneratorUtil.isNMultiplicity(attr)) {
1462                     body.append(""
1463 /*{        tmp.addAll(<%=getterName%>());
1464 }*/
1465                     );
1466                 } else {
1467                     body.append(""
1468 /*{        tmp.add(<%=getterName%>());
1469 }*/
1470                     );
1471                 }
1472             }
1473         }
1474         body.append(""
1475 /*{
1476         // on refait un tour sur chaque entity de tmp pour recuperer leur
1477         // composite
1478         List<TopiaEntity> result = new ArrayList<TopiaEntity>();
1479         for (TopiaEntity entity : tmp) {
1480             result.add(entity);
1481             result.addAll(entity.getAggregate());
1482         }
1483         return result;
1484     }*/
1485         );
1486 
1487         setOperationBody(operation, body.length() == 0 ? " " : body.toString());
1488     }
1489 
1490     // -------------------------------------------------------------------------
1491     // Helpers
1492     // -------------------------------------------------------------------------
1493 
1494     protected boolean isAbstract(ObjectModelClass clazz) {
1495         if (clazz.isAbstract()) {
1496             return true;
1497         }
1498 
1499         //Une classe peut être abstraite si elle a des méthodes définies dans
1500         // ses superinterface et non implantées dans ses superclasses
1501         Collection<ObjectModelOperation> allInterfaceOperations =
1502                 clazz.getAllInterfaceOperations(true);
1503         allInterfaceOperations.removeAll(clazz.getAllOtherOperations(true));
1504         for (ObjectModelOperation op : allInterfaceOperations) {
1505             boolean implementationFound = false;
1506             for (ObjectModelClass superClazz : clazz.getSuperclasses()) {
1507                 for (ObjectModelOperation matchingOp :
1508                         superClazz.getOperations(op.getName())) {
1509                     implementationFound = op.equals(matchingOp) &&
1510                                           !matchingOp.isAbstract();
1511                     if (implementationFound) {
1512                         break;
1513                     }
1514                 }
1515                 if (implementationFound) {
1516                     break;
1517                 }
1518             }
1519             if (!implementationFound) {
1520                 if (log.isDebugEnabled()) {
1521                     log.debug(clazz.getName() + " : abstract operation " + op);
1522                 }
1523                 return true;
1524             }
1525         }
1526         return false;
1527     }
1528 
1529     protected String getCollectionType(ObjectModelAttribute attribute) {
1530         String result = null;
1531         if (!associationClass && TopiaGeneratorUtil.isNMultiplicity(attribute)) {
1532             result = TopiaGeneratorUtil.getNMultiplicityInterfaceType(attribute);
1533         }
1534         return result;
1535     }
1536 
1537     protected String getPropertyName(ObjectModelAttribute attribute) {
1538         String propertyName = attribute.getName();
1539         if (!associationClass && attribute.hasAssociationClass()) {
1540             propertyName = TopiaGeneratorUtil.getAssocAttrName(attribute);
1541         }
1542         return propertyName;
1543     }
1544 
1545     protected String getPropertyType(ObjectModelAttribute attribute) {
1546         String propertyType = attribute.getType();
1547         if (!associationClass && attribute.hasAssociationClass()) {
1548             propertyType = attribute.getAssociationClass().getQualifiedName();
1549         }
1550         return propertyType;
1551     }
1552 
1553     protected ObjectModelOperation createImplOperation(ObjectModelOperation interfaceOperation) {
1554         ObjectModelOperation implOperation =
1555                 cloneOperationSignature(interfaceOperation, outputAbstract, false);
1556         addAnnotation(outputAbstract, implOperation, Override.class.getSimpleName());
1557         return implOperation;
1558     }
1559 
1560     /**
1561      * TODO-fdesbois-2010-06-25 : This method can be put in JavaBuilder or ObjectModelTransformerToJava
1562      *
1563      * This method create an set operation in {@code classifier} with
1564      * {@code propertyType} as return type and {@code propertyName} used for
1565      * operation name ('set[propertyName]'). {@code operationDocument} can
1566      * also be added to the operation created. Only signature with default
1567      * visibility will be added.
1568      *
1569      * @param classifier             Classifier where the operation will be added
1570      * @param propertyType           Type of the property (better if qualified name)
1571      * @param propertyName           Name of the property to set
1572      * @param operationDocumentation Documentation for the operation
1573      * @return the created operation
1574      */
1575     protected ObjectModelOperation createPropertySetterSignature(ObjectModelClassifier classifier,
1576                                                                 String propertyType,
1577                                                                 String propertyName,
1578                                                                 String operationDocumentation) {
1579         // Operation
1580         ObjectModelOperation operation =
1581                 addOperation(classifier,
1582                         getJavaBeanMethodName("set", propertyName), void.class);
1583 
1584         ObjectModelParameter param =
1585                 addParameter(operation, propertyType, propertyName);
1586 
1587         // Documentation
1588         if (StringUtils.isNotEmpty(operationDocumentation)) {
1589             setDocumentation(operation, operationDocumentation);
1590             setDocumentation(param, "La valeur de l'attribut à positionner.");
1591         }
1592 
1593         return operation;
1594     }
1595 
1596     protected void addInterface(List<String> interfaceAlreadyDone,
1597                                 ObjectModelClassifier output,
1598                                 ObjectModelClassifier interfaze) {
1599         String qualifiedName = interfaze.getQualifiedName();
1600         if (!interfaceAlreadyDone.contains(qualifiedName)) {
1601 
1602             interfaceAlreadyDone.add(qualifiedName);
1603 
1604             if (output != null) {
1605 
1606                 // add it to output
1607                 addInterface(output, qualifiedName);
1608 
1609                 if (log.isTraceEnabled()) {
1610                     log.trace("Add interface " + qualifiedName + " on " +
1611                               output.getQualifiedName());
1612                 }
1613             } else {
1614                 if (log.isTraceEnabled()) {
1615                     log.trace("Skip included interface " + qualifiedName);
1616                 }
1617             }
1618 
1619             // scan also all interfaces or super-classes of it
1620             for (ObjectModelClassifier parent : interfaze.getInterfaces()) {
1621                 addInterface(interfaceAlreadyDone, null, parent);
1622             }
1623         }
1624     }
1625 
1626     protected void addInterface(List<String> interfaceAlreadyDone,
1627                                 ObjectModelClassifier output,
1628                                 Class<?> clazz) {
1629         String qualifiedName = clazz.getName();
1630         if (!interfaceAlreadyDone.contains(qualifiedName)) {
1631 
1632             // add it to output
1633             addInterface(output, qualifiedName);
1634 
1635         }
1636     }
1637 }