1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.melati.poem.prepro;
47
48 import java.util.ArrayList;
49 import java.util.Enumeration;
50 import java.util.Vector;
51 import java.util.Hashtable;
52 import java.util.Arrays;
53 import java.io.StreamTokenizer;
54 import java.io.Writer;
55 import java.io.IOException;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class TableDef {
82
83 DSD dsd;
84
85 final String nameFromDsd;
86 final String capitalisedName;
87
88 final String name;
89 String displayName;
90 String description;
91 String category;
92 String superclass;
93 int displayOrder;
94 boolean seqCached;
95 int cacheSize = CacheSizeTableQualifier.DEFAULT;
96 private Vector<FieldDef> fields = new Vector<FieldDef>();
97 boolean isAbstract;
98 boolean definesColumns;
99 TableNamingInfo tableNamingInfo = null;
100
101 int nextFieldDisplayOrder = 0;
102
103
104
105 private final Hashtable<String, String> imports = new Hashtable<String, String>();
106 private final Vector<String> tableBaseImports = new Vector<String>();
107 private final Vector<String> persistentBaseImports = new Vector<String>();
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public TableDef(DSD dsd, StreamTokenizer tokens, int displayOrder,
130 boolean isAbstract, TableNamingStore nameStore)
131 throws ParsingDSDException,
132 IOException,
133 IllegalityException {
134 this.dsd = dsd;
135 this.displayOrder = displayOrder;
136 this.isAbstract = isAbstract;
137 if (tokens.ttype != StreamTokenizer.TT_WORD)
138 throw new ParsingDSDException("<table name>", tokens);
139 nameFromDsd = tokens.sval;
140 name = nameFromDsd.toLowerCase();
141 capitalisedName = nameFromDsd.substring(0,1).toUpperCase() + nameFromDsd.substring(1);
142
143 if (tokens.nextToken() == StreamTokenizer.TT_WORD) {
144 if (!tokens.sval.equals("extends"))
145 throw new ParsingDSDException("{", tokens);
146 tokens.wordChars('.', '.');
147 try {
148 if (tokens.nextToken() != StreamTokenizer.TT_WORD)
149 throw new ParsingDSDException("<class name>", tokens);
150 } finally {
151 tokens.ordinaryChar('.');
152 }
153 superclass = tokens.sval;
154 } else
155 tokens.pushBack();
156
157 tableNamingInfo = nameStore.add(dsd, dsd.packageName, nameFromDsd, superclass);
158
159 while (tokens.nextToken() == '(') {
160 tokens.nextToken();
161 TableQualifier.from(tokens).apply(this);
162 DSD.expect(tokens, ')');
163 }
164
165 DSD.expect(tokens, '{');
166 while (tokens.nextToken() != '}')
167 fields.addElement(FieldDef.from(this, tokens, nextFieldDisplayOrder++));
168
169 tokens.nextToken();
170
171 }
172
173
174
175
176
177 void addImport(String importName, String destination) {
178 if (!destination.equals("table") && !destination.equals("persistent")
179 && !destination.equals("both"))
180 throw new RuntimeException(
181 "Destination other than 'table', 'persistent' or 'both' used:"
182 + destination);
183
184 String existing = null;
185 existing = imports.put(importName, destination);
186 if (existing != null && existing != destination)
187 imports.put(importName, "both");
188 }
189
190 private final TableDef this_ = this;
191
192
193
194
195
196
197
198 public void generateTableDeclarationJava(Writer w)
199 throws IOException {
200 if (!isAbstract) {
201 w.write(" private " + tableNamingInfo.tableMainClassShortName() +
202 "<" + tableNamingInfo.mainClassShortName() + ">" +
203 " tab_" + name + " = null;\n");
204
205
206
207
208
209 }
210 }
211
212
213
214
215
216
217
218 public void generateTableDefinitionJava(Writer w)
219 throws IOException {
220 if (!isAbstract)
221 w.write(" redefineTable(tab_" + name + " = " + "new "
222 + tableNamingInfo.tableMainClassUnambiguous()
223 + (
224 (tableNamingInfo.tableMainClassRootReturnClass().equals(tableNamingInfo.tableMainClassUnambiguous())
225 ?
226 "<"+ tableNamingInfo.mainClassUnambiguous() +">"
227 : "")
228 )
229 + "(this, \"" + nameFromDsd + "\", "
230 + "DefinitionSource.dsd));\n");
231 }
232
233
234
235
236
237
238
239 public void generateTableAccessorJava(Writer w)
240 throws IOException {
241 if (isAbstract)
242 return;
243
244 generateTableAccessorDeclaration(w, false);
245 w.write(" {\n" + " return ");
246
247
248 if (!tableNamingInfo.tableMainClassRootReturnClass().equals(tableNamingInfo.tableMainClassUnambiguous()))
249 w.write("(" + tableNamingInfo.tableMainClassRootReturnClass() + ")");
250 w.write("tab_" + name + ";\n }\n");
251
252 if (tableNamingInfo.hidesOther) {
253 generateSubclassedTableAccessorDeclaration(w, false);
254 w.write(" {\n" + " return ");
255 w.write("tab_" + name + ";\n }\n");
256 }
257
258 }
259
260
261
262
263
264
265
266
267 public void generateTableAccessorDefnJava(Writer w)
268 throws IOException {
269 if (isAbstract)
270 return;
271
272 generateTableAccessorDeclaration(w, true);
273 w.write(";\n");
274
275 if (tableNamingInfo.hidesOther) {
276 generateSubclassedTableAccessorDeclaration(w, true);
277 w.write(";\n");
278 }
279
280 }
281
282 private void generateTableAccessorDeclaration(Writer w, boolean inInterface) throws IOException {
283 w.write("\n /**\n"
284 + " * Retrieves the " + tableNamingInfo.tableMainClassShortName() + " table.\n"
285 + " *\n");
286 if (!tableNamingInfo.tableMainClassRootReturnClass().equals(tableNamingInfo.tableMainClassUnambiguous()))
287 w.write(" * Deprecated: use get" + tableNamingInfo.projectName + tableNamingInfo.tableMainClassShortName() + "\n");
288 w.write(" * See org.melati.poem.prepro.TableDef#generateTableAccessorJava \n"
289 + " * @return the " + tableNamingInfo.tableMainClassRootReturnClass() + " from this database\n" + " */\n");
290 if (!inInterface)
291 if (!tableNamingInfo.tableMainClassRootReturnClass().equals(tableNamingInfo.tableMainClassUnambiguous()))
292 w.write(" @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n");
293 w.write(" public " + tableNamingInfo.tableMainClassRootReturnClass() +
294 "<" + tableNamingInfo.mainClassRootReturnClass() + "> get" + tableNamingInfo.tableMainClassShortName() + "()");
295 }
296
297 private void generateSubclassedTableAccessorDeclaration(Writer w, boolean inInterface) throws IOException {
298 w.write("\n /**\n"
299 + " * Retrieves our (" + tableNamingInfo.projectName + ") " + tableNamingInfo.tableMainClassShortName() + " table.\n"
300 + " *\n"
301 + " * See org.melati.poem.prepro.TableDef#generateSubclassedTableAccessorDeclaration \n"
302 + " * @return the " + tableNamingInfo.tableMainClassRootReturnClass() + " from this database\n" + " */\n");
303 w.write(" public " + tableNamingInfo.tableMainClassShortName()
304 + "<" + tableNamingInfo.mainClassShortName() + "> "
305 + tableNamingInfo.leafTableAccessorName() + "()");
306 }
307
308
309
310
311
312
313
314 public void generatePersistentBaseJava(Writer w)
315 throws IOException {
316 for (Enumeration<String> e = persistentBaseImports.elements();
317 e.hasMoreElements();) {
318 String importedClassName = e.nextElement();
319 TableNamingInfo tni = dsd.tableNamingStore.tableInfoByTableOrPersistentFQName.get(importedClassName);
320 if (tableNamingInfo.extended != null) {
321 if (tni != null)
322 if (tni.equals(tableNamingInfo))
323 w.write("// ours\n//import " + importedClassName + ";\n");
324 else
325 if (tni.equals(tableNamingInfo.extended))
326 if (tableNamingInfo.extended.extended != null)
327 w.write("// extends extended\n//import " + importedClassName + ";\n");
328 else
329 w.write("// base extension\nimport " + importedClassName + ";\n");
330 else
331 w.write("import " + importedClassName + ";\n");
332 else
333 w.write("import " + importedClassName + ";\n");
334 } else
335 w.write("import " + importedClassName + ";\n");
336 }
337 w.write("\n");
338
339
340
341 String rootReturnClass = tableNamingInfo.tableMainClassRootReturnClass();
342
343 w.write("\n" + "/**\n"
344 + " * Melati POEM generated abstract base class for a "
345 + "<code>Persistent</code> \n" +
346 " * <code>" + nameFromDsd + "</code> Object.\n" + " *\n" +
347 " * See org.melati.poem.prepro.TableDef#generatePersistentBaseJava \n" +
348 " */\n");
349 w.write("public abstract class " + tableNamingInfo.baseClassUnambiguous()
350 + " extends " + tableNamingInfo.superclassMainUnambiguous() + " {\n" + "\n");
351
352 w.write("\n /**\n" +
353 " * Retrieves the Database object.\n" + " * \n" +
354 " * See org.melati.poem.prepro.TableDef#generatePersistentBaseJava \n" +
355 " * @return the database\n" + " */\n");
356 w.write(" public " + dsd.databaseTablesClassName + " get" + dsd.databaseTablesClassName + "() {\n"
357 + " return (" + dsd.databaseTablesClassName + ")getDatabase();\n"
358 + " }\n" + "\n");
359
360 w.write("\n /**\n"
361 + " * Retrieves the <code>" + tableNamingInfo.tableMainClassShortName() + "</code> table \n"
362 + " * which this <code>Persistent</code> is from.\n" + " * \n"
363 + " * See org.melati.poem.prepro.TableDef#generatePersistentBaseJava \n"
364 + " * @return the " + rootReturnClass + "\n"
365 + " */\n");
366 w.write(" @SuppressWarnings(\"unchecked\")\n");
367 w.write(" public " + rootReturnClass + "<"+tableNamingInfo.mainClassRootReturnClass()+"> "
368 + tableNamingInfo.rootTableAccessorName() + "() {\n"
369 + " return ("
370 + rootReturnClass + "<"+tableNamingInfo.mainClassRootReturnClass()+">)getTable();\n"
371 + " }\n\n");
372
373 if (!fields.elements().hasMoreElements()) {
374 w.write(" // There are no Fields in this table, only in its ancestors \n");
375 } else {
376 w.write(" @SuppressWarnings(\"unchecked\")\n");
377 w.write(" private " + tableNamingInfo.tableMainClassUnambiguous() +"<"+tableNamingInfo.mainClassUnambiguous() + "> _" + tableNamingInfo.rootTableAccessorName() + "() {\n"
378 + " return ("
379 + tableNamingInfo.tableMainClassUnambiguous() + "<"+tableNamingInfo.mainClassUnambiguous()+">)getTable();\n"
380 + " }\n\n");
381
382 w.write(" // Fields in this table \n");
383 for (Enumeration<FieldDef> f = fields.elements(); f.hasMoreElements();) {
384 FieldDef fd = f.nextElement();
385 w.write(" /**\n");
386 w.write(DSD.javadocFormat(2, 1,
387 ((fd.displayName != null) ? fd.displayName : fd.name)
388 + ((fd.description != null) ? " - " + fd.description : "")));
389 w.write(" */\n");
390 w.write(" protected ");
391 fd.generateJavaDeclaration(w);
392
393 w.write(";\n");
394 }
395
396 for (Enumeration<FieldDef> f = fields.elements(); f.hasMoreElements();) {
397 FieldDef field = f.nextElement();
398 w.write('\n');
399 field.generateBaseMethods(w);
400 w.write('\n');
401 field.generateFieldCreator(w);
402 }
403 }
404
405
406
407 for (TableDef t : dsd.tablesInDatabase) {
408 if (!t.isAbstract && t.superclass == null) {
409 for (FieldDef f : t.fields) {
410 if (f instanceof ReferenceFieldDef) {
411 ReferenceFieldDef rfd = (ReferenceFieldDef) f;
412 if (rfd.getTargetTableNamingInfo() != null && rfd.getTargetTableNamingInfo().mainClassFQName().equals(tableNamingInfo.mainClassFQName())) {
413 w.write('\n');
414 w.write(" private CachedSelection<" + rfd.shortestUnambiguousClassname +"> "+rfd.name+rfd.shortestUnambiguousClassname + "s = null;\n");
415 w.write(" /** References to this "+tableNamingInfo.mainClassShortName()+" in the " + rfd.shortestUnambiguousClassname+" table via its "+ rfd.name+" field.*/\n");
416 w.write(" @SuppressWarnings(\"unchecked\")\n");
417 w.write(" public Enumeration<" + rfd.shortestUnambiguousClassname +"> get" + StringUtils.capitalised(rfd.name)+rfd.shortestUnambiguousClassname + "s() {\n");
418 w.write(" if (getTroid() == null)\n");
419 w.write(" return new EmptyEnumeration<" + rfd.shortestUnambiguousClassname +">();\n");
420 w.write(" else {\n");
421 w.write(" if (" + rfd.name+rfd.shortestUnambiguousClassname + "s == null)\n");
422 w.write(" " + rfd.name+rfd.shortestUnambiguousClassname + "s =\n");
423 w.write(" get" + dsd.databaseTablesClassName + "().get"+rfd.shortestUnambiguousClassname+"Table().get"+StringUtils.capitalised(rfd.name)+"Column().cachedSelectionWhereEq(getTroid());\n");
424 w.write(" return " + rfd.name+rfd.shortestUnambiguousClassname + "s.objects();\n");
425 w.write(" }\n");
426 w.write(" }\n");
427 w.write("\n");
428 w.write("\n");
429 w.write(" /** References to this "+tableNamingInfo.mainClassShortName()+" in the " + rfd.shortestUnambiguousClassname+" table via its "+ rfd.name+" field, as a List.*/\n");
430 w.write(" public List<" + StringUtils.capitalised(rfd.shortestUnambiguousClassname) +"> get" + StringUtils.capitalised(rfd.name)+rfd.shortestUnambiguousClassname + "List() {\n");
431 w.write(" return Collections.list(get" + StringUtils.capitalised(rfd.name)+rfd.shortestUnambiguousClassname + "s());\n");
432 w.write(" }\n");
433 w.write("\n");
434 w.write("\n");
435 }
436 }
437 }
438 }
439 }
440 w.write('\n');
441
442 w.write("}\n");
443 }
444
445
446
447
448
449
450
451 public void generatePersistentJava(Writer w)
452 throws IOException {
453
454 w.write("import " + dsd.packageName + ".generated."
455 + tableNamingInfo.baseClassShortName() + ";\n");
456 w.write("\n/**\n"
457 + " * Melati POEM generated, programmer modifiable stub \n"
458 + " * for a <code>Persistent</code> <code>"
459 + tableNamingInfo.mainClassShortName() + "</code> object.\n");
460 w.write(" * \n"
461 + (description != null ? " * <p> \n"
462 + " * Description: \n"
463 + DSD.javadocFormat(1, 3, (description + ((description
464 .lastIndexOf(".") != description.length() - 1) ? "." : "")))
465 + " * </p>\n" : ""));
466 w.write(fieldSummaryTable());
467 w.write(" * \n" + " * See org.melati.poem.prepro.TableDef"
468 + "#generatePersistentJava \n" + " */\n");
469 w.write("public class " + tableNamingInfo.mainClassShortName() + " extends "
470 + tableNamingInfo.baseClassShortName() + " {\n");
471
472 w.write("\n /**\n"
473 + " * Constructor \n"
474 + " * for a <code>Persistent</code> <code>"
475 + tableNamingInfo.mainClassShortName()
476 + "</code> object.\n"
477 + (description != null ? (" * <p>\n"
478 + " * Description: \n"
479 + DSD
480 .javadocFormat(2, 3, (description + ((description
481 .lastIndexOf(".") != description.length() - 1) ? "."
482 : ""))) + " * </p>\n") : "") + " * \n"
483 + " * See org.melati.poem.prepro.TableDef"
484 + "#generatePersistentJava \n" + " */\n");
485
486 w.write(" public " + tableNamingInfo.mainClassShortName() + "() { \n"
487 + " super();\n"
488 + "}\n" + "\n"
489 + " // programmer's domain-specific code here\n" + "}\n");
490 }
491
492
493
494
495
496
497
498 public void generateTableBaseJava(Writer w)
499 throws IOException {
500
501 for (Enumeration<String> e = tableBaseImports.elements(); e.hasMoreElements();) {
502 String packageName = e.nextElement();
503 if (ambiguous(packageName))
504 w.write("// Extended table \nimport " + packageName + ";\n");
505 else
506 w.write("import " + packageName + ";\n");
507 }
508
509 w.write("\n");
510 w.write("\n"
511 + "/**\n"
512 + " * Melati POEM generated base class for " + "<code>Table</code> <code>" + nameFromDsd + "</code>.\n");
513 w.write(" *\n"
514 + " * See org.melati.poem.prepro.TableDef"
515 + "#generateTableBaseJava \n" + " */\n\n");
516 w.write("public class " + tableNamingInfo.tableBaseClassShortName() + "<T extends "+tableNamingInfo.mainClassShortName()+"> extends "
517 + tableNamingInfo.superclassTableShortName() + "<T> {\n"
518 + "\n");
519
520 for (Enumeration<FieldDef> f = fields.elements(); f.hasMoreElements();) {
521 w.write(" private ");
522 (f.nextElement()).generateColDecl(w);
523 w.write(" = null;\n");
524 }
525
526 w.write("\n /**\n" + " * Constructor. \n"
527 + " * \n"
528 + " * See org.melati.poem.prepro.TableDef" + "#generateTableBaseJava \n"
529 + " * @param database the POEM database we are using\n"
530 + " * @param name the name of this <code>Table</code>\n"
531 + " * @param definitionSource which definition is being used\n"
532 + " * @throws PoemException if anything goes wrong\n" + " */\n");
533 w.write("\n" + " public " + tableNamingInfo.tableBaseClassShortName() + "(\n"
534 + " Database database, String name,\n"
535 + " DefinitionSource definitionSource)"
536 + " throws PoemException {\n"
537 + " super(database, name, definitionSource);\n" + " }\n" + "\n");
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553 w.write("\n /**\n"
554 + " * Get the database tables.\n" + " *\n"
555 + " * See org.melati.poem.prepro.TableDef#generateTableBaseJava \n"
556 + " * @return the database tables\n"
557 + " */\n");
558 w.write(" public " + dsd.databaseTablesClassName + " get"+ dsd.databaseTablesClassName + "() {\n" +
559 " return (" + dsd.databaseTablesClassName + ")getDatabase();\n" +
560 " }\n" +
561 "\n");
562
563 w.write("\n /**\n"
564 + " * Initialise this table by defining its columns.\n"
565 + " *\n"
566 + " * See org.melati.poem.prepro.TableDef#generateTableBaseJava \n"
567 + " */\n");
568 w.write(
569 " public void init() throws PoemException {\n" +
570 " super.init();\n");
571
572 for (Enumeration<FieldDef> fs = fields.elements(); fs.hasMoreElements();) {
573 (fs.nextElement()).generateColDefinition(w);
574 if (fs.hasMoreElements())
575 w.write('\n');
576 }
577
578 w.write(" }\n" + "\n");
579
580 for (Enumeration<FieldDef> fs = fields.elements(); fs.hasMoreElements();) {
581 (fs.nextElement()).generateColAccessor(w);
582 w.write('\n');
583 }
584
585
586
587 String requiredReturnClass = tableNamingInfo.mainClassRootReturnClass();
588
589 w.write("\n /**\n" + " * Retrieve the <code>"
590 + tableNamingInfo.mainClassShortName() + "</code> as a <code>"
591 + requiredReturnClass + "</code>.\n"
592 + " *\n"
593 + " * See org.melati.poem.prepro.TableDef" + "#generateTableBaseJava \n"
594 + " * @param troid a Table Row Object ID\n"
595 + " * @return the <code>Persistent</code> identified "
596 + "by the <code>troid</code>\n" + " */\n");
597 w.write(" public " + requiredReturnClass + " get"
598 + tableNamingInfo.mainClassShortName() + "Object(" + "Integer troid) {\n"
599 + " return (" + requiredReturnClass + ")getObject(troid);\n"
600 + " }\n" + "\n");
601
602 w.write("\n /**\n" + " * Retrieve the <code>"
603 + tableNamingInfo.mainClassShortName() + "</code> \n"
604 + " * as a <code>" + requiredReturnClass + "</code>.\n"
605 + " *\n"
606 + " * See org.melati.poem.prepro.TableDef" + "#generateTableBaseJava \n"
607 + " * @param troid a Table Row Object ID\n"
608 + " * @return the <code>Persistent</code> identified " + " */\n");
609 w.write(" public " + requiredReturnClass + " get"
610 + tableNamingInfo.mainClassShortName() + "Object(" + "int troid) {\n"
611 + " return (" + requiredReturnClass + ")getObject(troid);\n"
612 + " }\n");
613
614 if (!isAbstract)
615 w.write("\n" + " protected JdbcPersistent _newPersistent() {\n"
616 + " return new " + tableNamingInfo.mainClassUnambiguous() + "();\n" + " }"
617 + "\n");
618
619 if (displayName != null)
620 w.write(" public String defaultDisplayName() {\n" + " return "
621 + StringUtils.quoted(displayName, '"') + ";\n" + " }\n" + "\n");
622
623 if (description != null)
624 w.write(" public String defaultDescription() {\n" + " return "
625 + StringUtils.quoted(description, '"') + ";\n" + " }\n" + "\n");
626
627 if (seqCached)
628 w.write(" public boolean defaultRememberAllTroids() {\n"
629 + " return true;\n" + " }\n" + "\n");
630
631 if (cacheSize != CacheSizeTableQualifier.DEFAULT)
632 w.write(" public Integer defaultCacheLimit() {\n"
633 + " return new Integer("
634 + (cacheSize == CacheSizeTableQualifier.UNLIMITED ? "999999999" : ""
635 + cacheSize) + ");\n" + " }\n" + "\n");
636
637 if (category != null)
638 w.write(" public String defaultCategory() {\n" + " return "
639 + StringUtils.quoted(category, '"') + ";\n" + " }\n" + "\n");
640
641 w.write(" public int defaultDisplayOrder() {\n" + " return "
642 + displayOrder + ";\n" + " }\n");
643
644 FieldDef uniqueNonNullableField = null;
645 ArrayList<FieldDef> requiredFields = new ArrayList<FieldDef>();
646 for (Enumeration<FieldDef> fs = fields.elements(); fs.hasMoreElements();) {
647 FieldDef f = fs.nextElement();
648 if (!f.isNullable() && f.isUnique() && !f.isTroidColumn()
649 && uniqueNonNullableField == null){
650 uniqueNonNullableField = f;
651 }
652 if (!f.isNullable() && !f.isTroidColumn()){
653 requiredFields.add(f);
654 }
655 }
656 if (uniqueNonNullableField != null) {
657 w.write("\n");
658 w.write(" /**\n");
659 w.write(" * @return a newly created or existing "
660 + tableNamingInfo.mainClassShortName() + "\n");
661 w.write(" **/\n");
662 w.write(" public " + tableNamingInfo.mainClassShortName() + " ensure(");
663 boolean seenOne = false;
664 for (FieldDef f : requiredFields){
665 if (seenOne)
666 w.write(", ");
667 w.write(f.typeShortName);
668 w.write(" ");
669 w.write(f.name);
670 seenOne = true;
671 }
672 w.write(") {\n");
673
674 w.write(" "
675 + tableNamingInfo.mainClassShortName() + " p = ("
676 + tableNamingInfo.mainClassShortName() +")get"
677 + uniqueNonNullableField.capitalisedName + "Column().firstWhereEq("
678 + uniqueNonNullableField.name + ");\n");
679
680
681 w.write(" if (p == null) {\n"
682 + " p = (" + tableNamingInfo.mainClassShortName() + ")newPersistent();\n");
683
684 for (FieldDef f : requiredFields){
685 w.write(" p.set");
686 w.write(f.capitalisedName);
687 w.write("(");
688 w.write(f.name);
689 w.write(");\n");
690 }
691 w.write(" }\n");
692
693 w.write(" return (" + tableNamingInfo.mainClassShortName()
694 + ")get" + uniqueNonNullableField.capitalisedName + "Column().ensure(p);\n");
695
696
697 w.write(" }\n");
698 }
699
700
701 w.write("}\n");
702 }
703
704 private boolean ambiguous(String packageName) {
705 TableNamingInfo tni = dsd.tableNamingStore.tableInfoByTableOrPersistentFQName.get(packageName);
706 if (tni == null)
707 return false;
708 else if(tni.hidden || tni.hidesOther)
709 return true;
710 return false;
711 }
712
713
714
715
716
717
718
719 public void generateTableJava(Writer w)
720 throws IOException {
721
722 w.write("import " + tableNamingInfo.tableBaseClassFQName() + ";\n");
723 w.write("import org.melati.poem.DefinitionSource;\n");
724 w.write("import org.melati.poem.Database;\n");
725 w.write("import org.melati.poem.PoemException;\n");
726
727 w.write("\n/**\n"
728 + " * Melati POEM generated, programmer modifiable stub \n"
729 + " * for a <code>"
730 + tableNamingInfo.tableMainClassShortName()
731 + "</code> object.\n"
732 + (description != null ? " * <p>\n"
733 + " * Description: \n"
734 + DSD.javadocFormat(1, 3, (description + ((description
735 .lastIndexOf(".") != description.length() - 1) ? "." : "")))
736 + " * </p>\n" : "") + " *\n");
737 w.write(fieldSummaryTable());
738 w.write(" * \n"
739 + " * See org.melati.poem.prepro.TableDef" + "#generateTableJava \n" + " */\n");
740 w.write("public class " + tableNamingInfo.tableMainClassShortName() + "<T extends "+tableNamingInfo.mainClassShortName()+"> extends "
741 + tableNamingInfo.tableBaseClassShortName() + "<"+tableNamingInfo.mainClassShortName()+"> {\n");
742
743 Object o = new Object() {
744 public String toString() {
745 return "\n /**\n"
746 + " * Constructor.\n"
747 + " * \n"
748 + " * See org.melati.poem.prepro.TableDef" + "#generateTableJava \n"
749 + " * @param database the POEM database we are using\n"
750 + " * @param name the name of this <code>Table</code>\n"
751 + " * @param definitionSource which definition is being used\n"
752 + " * @throws PoemException if anything goes wrong\n"
753 + " */\n";
754 }
755 };
756 w.write(o.toString());
757 w.write(" public " + tableNamingInfo.tableMainClassShortName() + "(\n"
758 + " Database database, String name,\n"
759 + " DefinitionSource definitionSource)"
760 + " throws PoemException {\n"
761 + " super(database, name, definitionSource);\n" + " }\n" + "\n"
762 + " // programmer's domain-specific code here\n" + "}\n");
763 }
764
765
766
767
768
769
770
771
772
773 public void generateJava()
774 throws IOException, IllegalityException {
775
776 boolean hasDisplayLevel = false;
777 boolean hasSearchability = false;
778
779 boolean needSelectionImports = false;
780 for (TableDef t : dsd.tablesInDatabase) {
781 if (!t.isAbstract && t.superclass == null)
782 for (FieldDef f : t.fields) {
783 if (f instanceof ReferenceFieldDef) {
784 ReferenceFieldDef rfd = (ReferenceFieldDef) f;
785 if (!(rfd.getTargetTableNamingInfo() == null) &&
786 rfd.getTargetTableNamingInfo().mainClassFQName().equals(tableNamingInfo.mainClassFQName())) {
787 needSelectionImports = true;
788 addImport(rfd.table.tableNamingInfo.mainClassFQName(), "persistent");
789 }
790 }
791 }
792 }
793 if (needSelectionImports) {
794 addImport("org.melati.poem.CachedSelection", "persistent");
795 addImport("org.melati.poem.util.EmptyEnumeration","persistent");
796 addImport("java.util.Enumeration","persistent");
797 addImport("java.util.List","persistent");
798 addImport("java.util.Collections","persistent");
799 }
800
801 int fieldCount = 0;
802 for (Enumeration<FieldDef> e = fields.elements(); e.hasMoreElements();) {
803 fieldCount++;
804 FieldDef f = e.nextElement();
805 if (f.displayLevel != null)
806 hasDisplayLevel = true;
807 if (f.searchability != null)
808 hasSearchability = true;
809 }
810 if (fieldCount == 0 && !isAbstract && tableNamingInfo.superclass == null)
811 throw new NonAbstractEmptyTableException(name);
812
813 if (!isAbstract)
814 addImport("org.melati.poem.JdbcPersistent", "table");
815 if (hasDisplayLevel)
816 addImport("org.melati.poem.DisplayLevel", "table");
817 if (hasSearchability)
818 addImport("org.melati.poem.Searchability", "table");
819 addImport(tableNamingInfo.objectFQName, "table");
820 if (definesColumns) {
821 addImport("org.melati.poem.Column", "both");
822 addImport("org.melati.poem.Field", "both");
823 }
824 if (tableNamingInfo.superclassMainUnambiguous().equals("JdbcPersistent")) {
825 addImport("org.melati.poem.JdbcPersistent", "persistent");
826 } else {
827 addImport(tableNamingInfo.superclassMainFQName(), "persistent");
828 }
829
830
831
832 addImport(tableNamingInfo.tableMainClassFQName(), "persistent");
833 addImport(dsd.packageName + "." + dsd.databaseTablesClassName, "persistent");
834
835 addImport("org.melati.poem.Database", "table");
836 addImport("org.melati.poem.DefinitionSource", "table");
837 addImport("org.melati.poem.PoemException", "table");
838
839 if (!isAbstract && definesColumns)
840 addImport("org.melati.poem.Persistent", "table");
841
842 if (tableNamingInfo.superclassTableUnambiguous().equals("Table")) {
843 addImport("org.melati.poem.Table", "table");
844 } else {
845 addImport(tableNamingInfo.superclassTableFQName(), "table");
846 }
847 addImport(dsd.packageName + "." + dsd.databaseTablesClassName, "table");
848 addImport(tableNamingInfo.mainClassFQName(), "persistent");
849
850
851 for (Enumeration<String> i = imports.keys(); i.hasMoreElements();) {
852 String fqKey;
853 String key = i.nextElement();
854 if (key.indexOf(".") == -1) {
855 TableNamingInfo targetTable = (TableNamingInfo) dsd.tableNamingStore.tableInfoByPersistentShortName
856 .get(key);
857 if (targetTable == null)
858 throw new RuntimeException("No TableNamingInfo for " + key +
859 ". This is probably a typo either in the table definition name or in a reference field.");
860 fqKey = targetTable.objectFQName;
861 String destination = imports.get(key);
862 imports.remove(key);
863 addImport(fqKey, destination);
864 }
865 }
866 for (Enumeration<String> i = imports.keys(); i.hasMoreElements();) {
867 String fqKey;
868 String key = i.nextElement();
869
870 if (key.indexOf(".") == -1) {
871 TableNamingInfo targetTable =
872 (TableNamingInfo)dsd.tableNamingStore.tableInfoByPersistentShortName.get(key);
873 fqKey = targetTable.objectFQName;
874 } else {
875 fqKey = key;
876 }
877 String destination = imports.get(key);
878 if (destination == "table") {
879 tableBaseImports.addElement(fqKey);
880 } else if (destination == "persistent") {
881 persistentBaseImports.addElement(fqKey);
882 } else {
883 tableBaseImports.addElement(fqKey);
884 persistentBaseImports.addElement(fqKey);
885 }
886 }
887 Object[] t = tableBaseImports.toArray();
888 Object[] p = persistentBaseImports.toArray();
889 Arrays.sort(t);
890 Arrays.sort(p);
891 tableBaseImports.removeAllElements();
892 persistentBaseImports.removeAllElements();
893 for (int i = 0; i < t.length; i++)
894 tableBaseImports.addElement((String)t[i]);
895 for (int i = 0; i < p.length; i++)
896 persistentBaseImports.addElement((String)p[i]);
897
898 dsd.createJava(tableNamingInfo.baseClassShortName(), new Generator() {
899 public void process(Writer w)
900 throws IOException {
901 this_.generatePersistentBaseJava(w);
902 }
903 }, true);
904
905 dsd.createJava(tableNamingInfo.mainClassShortName(), new Generator() {
906 public void process(Writer w)
907 throws IOException {
908 this_.generatePersistentJava(w);
909 }
910 }, false);
911
912 dsd.createJava(tableNamingInfo.tableBaseClassShortName(), new Generator() {
913 public void process(Writer w)
914 throws IOException {
915 this_.generateTableBaseJava(w);
916 }
917 }, true);
918
919 dsd.createJava(tableNamingInfo.tableMainClassShortName(), new Generator() {
920 public void process(Writer w)
921 throws IOException {
922 this_.generateTableJava(w);
923 }
924 }, false);
925 }
926
927 String fieldSummaryTable() {
928 StringBuffer table = new StringBuffer();
929 table.append(" * \n" + " * <table> \n" + " * <caption>\n"
930 + " * Field summary for SQL table <code>" + nameFromDsd + "</code>\n"
931 + " * </caption>\n"
932 + " * <tr><th>Name</th><th>Type</th><th>Description</th></tr>\n");
933 for (Enumeration<FieldDef> f = fields.elements(); f.hasMoreElements();) {
934 FieldDef fd = f.nextElement();
935 table.append(DSD.javadocFormat(1, 1, "<tr><td> " + fd.name
936 + " </td><td> " + fd.typeShortName + " </td><td> "
937 + ((fd.description != null) ? fd.description : " ")
938 + " </td></tr>"));
939 }
940 table.append(" * </table> \n");
941 return table.toString();
942 }
943 }