View Javadoc
1   /*
2    * #%L
3    * ToPIA :: Persistence
4    * $Id$
5    * $HeadURL$
6    * %%
7    * Copyright (C) 2004 - 2014 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  
25  package org.nuiton.topia.generator;
26  
27  import org.apache.commons.lang3.ArrayUtils;
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.Template;
32  import org.nuiton.eugene.java.ObjectModelTransformerToJava;
33  import org.nuiton.eugene.models.object.ObjectModel;
34  import org.nuiton.eugene.models.object.ObjectModelAttribute;
35  import org.nuiton.eugene.models.object.ObjectModelClass;
36  import org.nuiton.eugene.models.object.ObjectModelEnumeration;
37  import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
38  import org.nuiton.eugene.models.object.ObjectModelOperation;
39  import org.nuiton.eugene.models.object.ObjectModelType;
40  import org.nuiton.eugene.models.object.xml.ObjectModelAttributeImpl;
41  import org.nuiton.eugene.models.object.xml.ObjectModelEnumerationImpl;
42  import org.nuiton.topia.TopiaContext;
43  import org.nuiton.topia.TopiaException;
44  import org.nuiton.topia.TopiaRuntimeException;
45  import org.nuiton.topia.framework.TopiaContextImplementor;
46  import org.nuiton.topia.persistence.TopiaDAO;
47  import org.nuiton.topia.persistence.TopiaEntity;
48  import org.nuiton.topia.persistence.TopiaEntityEnum;
49  import org.nuiton.topia.persistence.util.EntityOperator;
50  import org.nuiton.topia.persistence.util.EntityOperatorStore;
51  import org.nuiton.topia.persistence.util.TopiaEntityHelper;
52  
53  import java.lang.reflect.Array;
54  import java.util.Arrays;
55  import java.util.List;
56  import java.util.Set;
57  
58  
59  /*{generator option: parentheses = false}*/
60  
61  /*{generator option: writeString = +}*/
62  
63  /**
64   * Created: 13 nov. 2009 09:05:17
65   *
66   * @author tchemit &lt;chemit@codelutin.com&gt;
67   * @version $Id$
68   * @since 2.3.0
69   */
70  @Component(role = Template.class, hint = "org.nuiton.topia.generator.DAOHelperTransformer")
71  public class DAOHelperTransformer extends ObjectModelTransformerToJava {
72  
73      private static final Log log =
74              LogFactory.getLog(DAOHelperTransformer.class);
75  
76      @Override
77      public void transformFromModel(ObjectModel model) {
78          String packageName = getDefaultPackageName();
79          String modelName = model.getName();
80          String daoHelperClazzName = modelName + "DAOHelper";
81          String entityEnumName = modelName + "EntityEnum";
82  
83          List<ObjectModelClass> classes =
84                  TopiaGeneratorUtil.getEntityClasses(model, true);
85  
86          boolean generateOperator =
87                  TopiaGeneratorUtil.shouldGenerateOperatorForDAOHelper(model);
88  
89          boolean generateStandaloneEnum =
90                  TopiaGeneratorUtil.shouldGenerateStandaloneEnumForDAOHelper(model);
91  
92          ObjectModelClass daoHelper = createClass(daoHelperClazzName,
93                                                   packageName);
94  
95          ObjectModelEnumeration entityEnum;
96  
97          if (generateStandaloneEnum) {
98              if (log.isDebugEnabled()) {
99                  log.debug("Will generate standalone " + entityEnumName +
100                      " in package " + packageName);
101             }
102             entityEnum = createEnumeration(entityEnumName, packageName);
103             addImport(entityEnum, TopiaEntity.class);
104             addImport(entityEnum, EntityOperatorStore.class);
105             addImport(entityEnum, Arrays.class);
106             addImport(entityEnum, TopiaRuntimeException.class);
107             addImport(entityEnum, ArrayUtils.class);
108             addImport(entityEnum, TopiaEntityHelper.class);
109 
110         } else {
111             entityEnum = (ObjectModelEnumerationImpl)
112                     addInnerClassifier(daoHelper,
113                                        ObjectModelType.OBJECT_MODEL_ENUMERATION,
114                                        entityEnumName
115                     );
116             addImport(daoHelper, TopiaRuntimeException.class);
117             addImport(daoHelper, TopiaEntityEnum.class);
118             addImport(daoHelper, EntityOperatorStore.class);
119             addImport(daoHelper, Arrays.class);
120             addImport(daoHelper, ArrayUtils.class);
121             addImport(daoHelper, TopiaEntityHelper.class);
122         }
123 
124         // generate DAOHelper
125         createDAOHelper(model,
126                         daoHelper,
127                         daoHelperClazzName,
128                         entityEnumName,
129                         generateOperator,
130                         classes
131         );
132 
133         // generate TopiaEntityEnum
134         createEntityEnum(entityEnum,
135                          daoHelperClazzName,
136                          entityEnumName,
137                          generateOperator,
138                          generateStandaloneEnum,
139                          classes
140         );
141     }
142 
143     protected void createDAOHelper(ObjectModel model,
144                                    ObjectModelClass daoHelper,
145                                    String daoHelperClazzName,
146                                    String entityEnumName,
147                                    boolean generateOperator,
148                                    List<ObjectModelClass> classes) {
149 
150         String modelName = model.getName();
151         String modelVersion = model.getVersion();
152 
153         addImport(daoHelper, TopiaContextImplementor.class);
154         addImport(daoHelper, TopiaDAO.class);
155         addImport(daoHelper, TopiaEntity.class);
156         addImport(daoHelper, TopiaContext.class);
157         addImport(daoHelper, Array.class);
158 
159         if (generateOperator) {
160             addImport(daoHelper,EntityOperator.class);
161             addImport(daoHelper, EntityOperatorStore.class);
162         }
163 
164         // add non public constructor
165         ObjectModelOperation constructor =
166                 addConstructor(daoHelper, ObjectModelJavaModifier.PROTECTED);
167         setOperationBody(constructor," ");
168 
169         ObjectModelOperation op;
170 
171         // getModelVersion method
172         op = addOperation(daoHelper, "getModelVersion", "String", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
173         setOperationBody(op, ""
174 /*{
175         return "<%=modelVersion%>";
176     }*/
177         );
178 
179         // getModelName method
180         op = addOperation(daoHelper, "getModelName", "String", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
181         setOperationBody(op, ""
182 /*{
183         return "<%=modelName%>";
184     }*/
185         );
186 
187 
188         for (ObjectModelClass clazz : classes) {
189             String clazzName = clazz.getName();
190             String daoClazzName = clazzName + "DAO";
191 
192             // specialized getXXXDao method
193             op = addOperation(daoHelper, "get" + daoClazzName, clazz.getPackageName() + '.' + daoClazzName, ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
194             addParameter(op, TopiaContext.class, "context");
195             addImport(daoHelper, clazz);
196             addException(op, TopiaException.class);
197             setOperationBody(op, ""
198 /*{
199         TopiaContextImplementor ci = (TopiaContextImplementor) context;
200         <%=daoClazzName%> result = ci.getDAO(<%=clazzName%>.class, <%=daoClazzName%>.class);
201         return result;
202     }*/
203             );
204 
205         }
206 
207         // generic getDao method
208         op = addOperation(daoHelper, "getDAO", "<T extends TopiaEntity, D extends TopiaDAO<? super T>> D", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
209         addParameter(op, TopiaContext.class, "context");
210         addParameter(op, "Class<T>", "klass");
211         addException(op, TopiaException.class);
212         setOperationBody(op, ""
213 /*{
214         TopiaContextImplementor ci = (TopiaContextImplementor) context;
215         <%=entityEnumName%> constant = <%=entityEnumName%>.valueOf(klass);
216         D dao = (D) ci.getDAO(constant.getContract());
217         return dao;
218     }*/
219         );
220 
221         op = addOperation(daoHelper, "getDAO", "<T extends TopiaEntity, D extends TopiaDAO<? super T>> D", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
222         addParameter(op, TopiaContext.class, "context");
223         addParameter(op, "T", "entity");
224         addException(op, TopiaException.class);
225         setOperationBody(op, ""
226 /*{
227         TopiaContextImplementor ci = (TopiaContextImplementor) context;
228         <%=entityEnumName%> constant = <%=entityEnumName%>.valueOf(entity);
229         D dao = (D) ci.getDAO(constant.getContract());
230         return dao;
231     }*/
232         );
233 
234         // getContractClass method
235         op = addOperation(daoHelper, "getContractClass", "<T extends TopiaEntity> Class<T>", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
236         addParameter(op, "Class<T>", "klass");
237         setOperationBody(op, ""
238 /*{
239         <%=entityEnumName%> constant = <%=entityEnumName%>.valueOf(klass);
240         return (Class<T>) constant.getContract();
241     }*/
242         );
243 
244         // getImplementationClass method
245         op = addOperation(daoHelper, "getImplementationClass", "<T extends TopiaEntity> Class<T>", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
246         addParameter(op, "Class<T>", "klass");
247         setOperationBody(op, ""
248 /*{
249         <%=entityEnumName%> constant = <%=entityEnumName%>.valueOf(klass);
250         return (Class<T>) constant.getImplementation();
251     }*/
252         );
253 
254         // getContractClasses method
255         op = addOperation(daoHelper, "getContractClasses", "Class<? extends TopiaEntity>[]", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
256         setOperationBody(op, ""
257 /*{
258         <%=entityEnumName%>[] values = <%=entityEnumName%>.values();
259         Class<? extends TopiaEntity>[] result = (Class<? extends TopiaEntity>[]) Array.newInstance(Class.class, values.length);
260         for (int i = 0; i < values.length; i++) {
261             result[i] = values[i].getContract();
262         }
263         return result;
264     }*/
265         );
266 
267         // getImplementationClasses method
268         op = addOperation(daoHelper, "getImplementationClasses", "Class<? extends TopiaEntity>[]", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
269         setOperationBody(op, ""
270 /*{
271         <%=entityEnumName%>[] values = <%=entityEnumName%>.values();
272         Class<? extends TopiaEntity>[] result = (Class<? extends TopiaEntity>[]) Array.newInstance(Class.class, values.length);
273         for (int i = 0; i < values.length; i++) {
274             result[i] = values[i].getImplementation();
275         }
276         return result;
277     }*/
278         );
279 
280         // getImplementationClassesAsString method
281         op = addOperation(daoHelper, "getImplementationClassesAsString", "String", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
282         setOperationBody(op, ""
283 /*{
284         StringBuilder buffer = new StringBuilder();
285         for (Class<? extends TopiaEntity> aClass : getImplementationClasses()) {
286             buffer.append(',').append(aClass.getName());
287         }
288         return buffer.substring(1);
289     }*/
290         );
291 
292         // getContracts method
293         op = addOperation(daoHelper, "getContracts", entityEnumName+"[]", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
294         setOperationBody(op, ""
295 /*{
296         return <%=entityEnumName%>.values();
297     }*/
298         );
299 
300         if (generateOperator) {
301             // getOperator method
302             op = addOperation(daoHelper, "getOperator", "<T extends TopiaEntity> EntityOperator<T>", ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC);
303             addParameter(op,"Class<T>","klass");
304             setOperationBody(op, ""
305 /*{
306         <%=entityEnumName%> constant = <%=entityEnumName%>.valueOf(klass);
307         return EntityOperatorStore.getOperator(constant);
308     }*/
309             );
310         }
311     }
312 
313     protected void createEntityEnum(ObjectModelEnumeration entityEnum,
314                                     String daoHelperClazzName,
315                                     String entityEnumName,
316                                     boolean generateOperator,
317                                     boolean generateStandaloneEnum,
318                                     List<ObjectModelClass> classes) {
319 
320         ObjectModelAttributeImpl attr;
321         ObjectModelOperation op;
322 
323         addInterface(entityEnum, TopiaEntityEnum.class);
324 
325         for (ObjectModelClass clazz : classes) {
326             String clazzName = clazz.getName();
327 
328             boolean withNatural = false;
329             boolean withNotNull = false;
330             StringBuilder naturalIdsParams = new StringBuilder();
331             StringBuilder notNullParams = new StringBuilder();
332 
333             Set<ObjectModelAttribute> naturalIdsAttributes = TopiaGeneratorUtil.getNaturalIdAttributes(clazz);
334             for (ObjectModelAttribute attribute: naturalIdsAttributes) {
335                 withNatural = true;
336                 // attribut metier
337                 naturalIdsParams.append(", \"").append(attribute.getName()).append("\"");
338             }
339             Set<ObjectModelAttribute> notNullIdsAttributes = TopiaGeneratorUtil.getNotNullAttributes(clazz);
340             for (ObjectModelAttribute attribute : notNullIdsAttributes) {
341                 withNotNull = true;
342                 // attribut not-null
343                 notNullParams.append(", \"").append(attribute.getName()).append("\"");
344             }
345 
346             StringBuilder params = new StringBuilder(clazzName + ".class");
347 
348             String dbSchema = TopiaGeneratorUtil.getDbSchemaNameTagValue(clazz, model);
349             if (dbSchema == null) {
350                 params.append(", null");
351             } else {
352                 params.append(", \"").append(dbSchema.toLowerCase()).append("\"");
353             }
354 
355             String dbTable  = TopiaGeneratorUtil.getDbName(clazz);
356             params.append(", \"").append(dbTable.toLowerCase()).append("\"");
357 
358             if (withNotNull) {
359                 params.append(", new String[]{ ").append(notNullParams.substring(2)).append(" }");
360             } else {
361                 params.append(", ArrayUtils.EMPTY_STRING_ARRAY");
362             }
363             if (withNatural) {
364                 params.append(", ").append(naturalIdsParams.substring(2));
365             }
366             addLiteral(entityEnum, clazzName + '(' + params.toString() + ')');
367 
368             if (generateStandaloneEnum) {
369                 addImport(entityEnum, clazz);
370             }
371         }
372 
373         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "contract", "Class<? extends TopiaEntity>");
374         attr.setDocumentation("The contract of the entity.");
375 
376         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "dbSchemaName", "String");
377         attr.setDocumentation("The optional name of database schema of the entity (if none was filled, will be {@code null}).");
378 
379         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "dbTableName", "String");
380         attr.setDocumentation("The name of the database table for the entity.");
381 
382         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "implementationFQN", "String");
383         attr.setDocumentation("The fully qualified name of the implementation of the entity.");
384 
385         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "implementation", "Class<? extends TopiaEntity>");
386         attr.setDocumentation("The implementation class of the entity (will be lazy computed at runtime).");
387 
388         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "naturalIds", "String[]");
389         attr.setDocumentation("The array of property involved in the natural key of the entity.");
390 
391         attr = (ObjectModelAttributeImpl) addAttribute(entityEnum, "notNulls", "String[]");
392         attr.setDocumentation("The array of not null properties of the entity.");
393 
394         // constructor
395         op = addConstructor(entityEnum, ObjectModelJavaModifier.PACKAGE);
396         addParameter(op,"Class<? extends TopiaEntity >","contract");
397         addParameter(op,"String","dbSchemaName");
398         addParameter(op,"String","dbTableName");
399         addParameter(op,"String[]","notNulls");
400         addParameter(op,"String...","naturalIds");
401         setOperationBody(op, ""
402 /*{
403         this.contract = contract;
404         this.dbSchemaName = dbSchemaName;
405         this.dbTableName = dbTableName;
406         this.notNulls = notNulls;
407         this.naturalIds = naturalIds;
408         implementationFQN = contract.getName() + "Impl";
409     }*/
410         );
411 
412         // getContract method
413         op = addOperation(entityEnum, "getContract", "Class<? extends TopiaEntity>", ObjectModelJavaModifier.PUBLIC);
414         addAnnotation(entityEnum,op,Override.class.getSimpleName());
415         setOperationBody(op, ""
416 /*{
417         return contract;
418     }*/
419         );
420 
421         // dbSchemaName method
422         op = addOperation(entityEnum, "dbSchemaName", String.class, ObjectModelJavaModifier.PUBLIC);
423         addAnnotation(entityEnum,op,Override.class.getSimpleName());
424         setOperationBody(op, ""
425 /*{
426         return dbSchemaName;
427     }*/
428         );
429 
430         // dbTableName method
431         op = addOperation(entityEnum, "dbTableName", String.class, ObjectModelJavaModifier.PUBLIC);
432         addAnnotation(entityEnum,op,Override.class.getSimpleName());
433         setOperationBody(op, ""
434 /*{
435         return dbTableName;
436     }*/
437         );
438 
439         // getNaturalIds method
440         op = addOperation(entityEnum, "getNaturalIds", "String[]", ObjectModelJavaModifier.PUBLIC);
441         addAnnotation(entityEnum,op,Override.class.getSimpleName());
442         setOperationBody(op, ""
443 /*{
444         return naturalIds;
445     }*/
446         );
447 
448         // isUseNaturalIds method
449         op = addOperation(entityEnum, "isUseNaturalIds", "boolean", ObjectModelJavaModifier.PUBLIC);
450         addAnnotation(entityEnum,op,Override.class.getSimpleName());
451         setOperationBody(op, ""
452 /*{
453         return naturalIds.length > 0;
454     }*/
455         );
456 
457         // getNotNulls method
458         op = addOperation(entityEnum, "getNotNulls", "String[]", ObjectModelJavaModifier.PUBLIC);
459         addAnnotation(entityEnum,op,Override.class.getSimpleName());
460         setOperationBody(op, ""
461 /*{
462         return notNulls;
463     }*/
464         );
465 
466         // isUseNotNulls method
467         op = addOperation(entityEnum, "isUseNotNulls", "boolean", ObjectModelJavaModifier.PUBLIC);
468         addAnnotation(entityEnum,op,Override.class.getSimpleName());
469         setOperationBody(op, ""
470 /*{
471         return notNulls.length > 0;
472     }*/
473         );
474 
475         // getImplementationFQN method
476         op = addOperation(entityEnum, "getImplementationFQN","String",ObjectModelJavaModifier.PUBLIC);
477         addAnnotation(entityEnum,op,Override.class.getSimpleName());
478         setOperationBody(op, ""
479 /*{
480         return implementationFQN;
481     }*/
482         );
483 
484         // setImplementationFQN method
485         op = addOperation(entityEnum, "setImplementationFQN","void",ObjectModelJavaModifier.PUBLIC);
486         addAnnotation(entityEnum,op,Override.class.getSimpleName());
487         addParameter(op,"String","implementationFQN");
488         if (generateOperator) {
489                setOperationBody(op, ""
490 /*{
491         this.implementationFQN = implementationFQN;
492         implementation = null;
493         // reinit the operators store
494         EntityOperatorStore.clear();
495     }*/
496             );
497         } else {
498             setOperationBody(op, ""
499 /*{
500         this.implementationFQN = implementationFQN;
501         this.implementation = null;
502     }*/
503             );
504         }
505 
506         // accept method
507         op = addOperation(entityEnum, "accept","boolean",ObjectModelJavaModifier.PUBLIC);
508         addAnnotation(entityEnum,op,Override.class.getSimpleName());
509         addParameter(op,"Class<? extends TopiaEntity>","klass");
510         setOperationBody(op, ""
511 /*{
512         return <%=daoHelperClazzName%>.getContractClass(klass) == contract;
513     }*/
514         );
515 
516         // getImplementation method
517         op = addOperation(entityEnum, "getImplementation","Class<? extends TopiaEntity>",ObjectModelJavaModifier.PUBLIC);
518         addAnnotation(entityEnum,op,Override.class.getSimpleName());
519         setOperationBody(op, ""
520 /*{
521         if (implementation == null) {
522         try {
523                 implementation = (Class<? extends TopiaEntity>) Class.forName(implementationFQN);
524             } catch (ClassNotFoundException e) {
525                 throw new TopiaRuntimeException("could not find class " + implementationFQN, e);
526             }
527         }
528         return implementation;
529     }*/
530         );
531 
532         // valueOf method
533         op = addOperation(entityEnum, "valueOf", entityEnumName, ObjectModelJavaModifier.PUBLIC,ObjectModelJavaModifier.STATIC);
534         addParameter(op,"TopiaEntity","entity");
535         setOperationBody(op, ""
536 /*{
537         return valueOf(entity.getClass());
538     }*/
539         );
540 
541         // valueOf method
542         op = addOperation(entityEnum, "valueOf", entityEnumName, ObjectModelJavaModifier.PUBLIC,ObjectModelJavaModifier.STATIC);
543         addParameter(op,"Class<?>","klass");
544         setOperationBody(op, ""
545 /*{
546         if (klass.isInterface()) {
547            return valueOf(klass.getSimpleName());
548         }
549 
550         Class<?> contractClass = TopiaEntityHelper.getContractClass(<%=entityEnumName%>.values(), (Class) klass);
551 
552         if (contractClass != null) {
553 
554             return valueOf(contractClass.getSimpleName());
555         }
556 
557         throw new IllegalArgumentException("no entity defined for the class " + klass + " in : " + Arrays.toString(<%=entityEnumName%>.values()));
558     }*/
559         );
560     }
561 }