1 package pl.aislib.tools.mapping.generators;
2
3 import java.io.File;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.io.Writer;
7 import java.util.ArrayList;
8 import java.util.Iterator;
9 import java.util.List;
10
11 import pl.aislib.tools.mapping.Generator;
12 import pl.aislib.tools.mapping.structure.Aggregate;
13 import pl.aislib.tools.mapping.structure.Call;
14 import pl.aislib.tools.mapping.structure.Count;
15 import pl.aislib.tools.mapping.structure.Delete;
16 import pl.aislib.tools.mapping.structure.Field;
17 import pl.aislib.tools.mapping.structure.Fields;
18 import pl.aislib.tools.mapping.structure.JavaClass;
19 import pl.aislib.tools.mapping.structure.JavaField;
20 import pl.aislib.tools.mapping.structure.JavaMethod;
21 import pl.aislib.tools.mapping.structure.JavaParam;
22 import pl.aislib.tools.mapping.structure.Operations;
23 import pl.aislib.tools.mapping.structure.Select;
24 import pl.aislib.tools.mapping.structure.SqlTable;
25 import pl.aislib.tools.mapping.structure.Structure;
26 import pl.aislib.tools.mapping.structure.Update;
27
28 /***
29 * <code>ApplicationDatabase.java</code> generator.
30 *
31 * @author <a href="mailto:milosz@ais.pl">Milosz Tylenda</a>, AIS.PL
32 * $Revision: 1.23 $
33 */
34 public class DatabaseGenerator extends Generator {
35
36 private String databaseClassName = "ApplicationDatabase";
37
38 private File baseDir;
39 private Writer writer;
40
41 public void setDatabaseClassName(String databaseClassName) {
42 this.databaseClassName = databaseClassName;
43 }
44
45 private File initDirectory(File destinationDir) throws IOException {
46 File dir = new File(destinationDir.getPath());
47 if (!dir.exists()) {
48 dir.mkdirs();
49 }
50 return dir;
51 }
52
53 private void initWriter(String className) throws IOException {
54 writer = new FileWriter(baseDir.getPath() + File.separator + className + ".java");
55 }
56
57 private void closeWriter() throws IOException {
58 writer.close();
59 }
60
61 public void generate() throws IOException {
62 log("Generating " + databaseClassName + ":");
63 baseDir = initDirectory(destinationDir);
64 initWriter(databaseClassName);
65 MiscPutter miscPutter = new MiscPutter(writer);
66 DisuPutter disuPutter = new DisuPutter(writer);
67 OperationsPutter operationsPutter = new OperationsPutter(writer);
68 miscPutter.setProperties(packageName, databaseClassName);
69 List structureList = database.getStructureList();
70 for (int i = 0, size = structureList.size() ; i < size ; i++) {
71 Structure structure = (Structure) structureList.get(i);
72 JavaClass javaClass = structure.getJavaClass();
73 miscPutter.addJavaClass(javaClass);
74 }
75 miscPutter.putHeader();
76 for (int i = 0, size = structureList.size() ; i < size ; i++) {
77 Structure structure = (Structure) structureList.get(i);
78 SqlTable sqlTable = structure.getSqlTable();
79 JavaClass javaClass = structure.getJavaClass();
80 Fields fields = structure.getFields();
81 log(" Parsing structure " + structure.getName());
82 disuPutter.setProperties(sqlTable, javaClass, fields);
83 disuPutter.put();
84
85 Operations operations = structure.getOperations();
86 if (operations != null) {
87
88 List aggregateList = operations.getAggregateList();
89 for (Iterator aggregateIter = aggregateList.listIterator() ; aggregateIter.hasNext() ; ) {
90 Aggregate aggregate = (Aggregate) aggregateIter.next();
91 operationsPutter.putAggregate(aggregate, javaClass);
92 }
93
94 List callList = operations.getCallList();
95 for (Iterator callIter = callList.listIterator() ; callIter.hasNext() ; ) {
96 Call call = (Call) callIter.next();
97 operationsPutter.putCall(call, javaClass, fields);
98 }
99
100 List countList = operations.getCountList();
101 for (Iterator countIter = countList.listIterator() ; countIter.hasNext() ; ) {
102 Count count = (Count) countIter.next();
103 operationsPutter.putCount(count.getJavaMethod(), javaClass);
104 }
105
106 List deleteList = operations.getDeleteList();
107 for (Iterator deleteIter = deleteList.listIterator() ; deleteIter.hasNext() ; ) {
108 Delete deletee = (Delete) deleteIter.next();
109 operationsPutter.putDelete(deletee.getJavaMethod(), javaClass);
110 }
111
112 List selectList = operations.getSelectList();
113 for (Iterator selectIter = selectList.listIterator() ; selectIter.hasNext() ; ) {
114 Select select = (Select) selectIter.next();
115 operationsPutter.putSelect(select, javaClass);
116 }
117
118 List updateList = operations.getUpdateList();
119 for (Iterator updateIter = updateList.listIterator() ; updateIter.hasNext() ; ) {
120 Update update = (Update) updateIter.next();
121 operationsPutter.putUpdate(update.getJavaMethod(), javaClass);
122 }
123 }
124 }
125 miscPutter.putExceptionCaught();
126 miscPutter.putClassEndBrace();
127 closeWriter();
128 log(databaseClassName + " class generated:");
129 log(" " + disuPutter.deleteCount + " delete method(s) generated");
130 log(" " + disuPutter.insertCount + " insert method(s) generated");
131 log(" " + disuPutter.selectCount + " select method(s) generated");
132 log(" " + disuPutter.updateCount + " update method(s) generated");
133 log(" " + operationsPutter.aggregateCount + " operations/aggregate method(s) generated");
134 log(" " + operationsPutter.callCount + " operations/call method(s) generated");
135 log(" " + operationsPutter.countCount + " operations/count method(s) generated");
136 log(" " + operationsPutter.deleteCount + " operations/delete method(s) generated");
137 log(" " + operationsPutter.selectCount + " operations/select method(s) generated");
138 log(" " + operationsPutter.updateCount + " operations/update method(s) generated");
139 }
140
141
142
143 /***
144 * Puts <code>delete/insert/select/update</code> methods.
145 * @author Milosz Tylenda, AIS.PL
146 */
147 class DisuPutter {
148
149 private Writer writer;
150 private SqlTable sqlTable;
151 private JavaClass javaClass;
152 private Fields fields;
153 public int deleteCount = 0;
154 public int insertCount = 0;
155 public int selectCount = 0;
156 public int updateCount = 0;
157
158 public DisuPutter(Writer awriter) {
159 writer = awriter;
160 }
161
162 public void put() throws IOException {
163 String className = javaClass.getName();
164 List fieldList = fields.getFieldList();
165
166
167 if (sqlTable.isDelete() && fields.hasPrimaryKey()) {
168 writer.write(createDIUMethodBody("delete", className));
169 deleteCount++;
170 }
171
172
173 if (sqlTable.isInsert()) {
174 writer.write(createDIUMethodBody("insert", className));
175 insertCount++;
176 }
177
178
179 if (sqlTable.isSelect()) {
180
181
182 List primaryKeys = new ArrayList();
183 for (int i = 0, size = fieldList.size() ; i < size ; i++) {
184 Field field = (Field) fieldList.get(i);
185 if (field.isPrimaryKey()) {
186 primaryKeys.add(field);
187 }
188 }
189
190 if (!primaryKeys.isEmpty()) {
191 String fullMethodName = Utils.createMethodName("select", className, null);
192 writer.write(" public " + className + " " + fullMethodName);
193 writer.write("(\n");
194 writer.write(" ");
195 for (int i = 0, size = primaryKeys.size() ; i < size ; i++) {
196 Field field = (Field) primaryKeys.get(i);
197 JavaField javaField = field.getJavaField();
198 writer.write( " " + javaField.getType() + " " + javaField.getName());
199 if (i < size - 1) {
200 writer.write(",");
201 } else {
202 writer.write("\n");
203 }
204 }
205 writer.write(" ) throws SQLException {\n");
206 writer.write(" Connection con = manager.getConnection();\n");
207 writer.write(" try {\n");
208 writer.write(" return " + className);
209 writer.write("Handler.select(\n");
210 writer.write(" ");
211 for (int i = 0, size = primaryKeys.size() ; i < size ; i++) {
212 Field field = (Field) primaryKeys.get(i);
213 JavaField javaField = field.getJavaField();
214 writer.write( " " + javaField.getName() + ",");
215 }
216 writer.write(" con);\n");
217 writer.write(" } catch (SQLException sqle) {\n");
218 writer.write(createCallToExceptionCaught(fullMethodName, primaryKeys));
219 writer.write(" throw sqle;\n");
220 writer.write(" } finally {\n");
221 writer.write(" manager.releaseConnection(con);\n");
222 writer.write(" }\n");
223 writer.write(" }\n\n");
224 selectCount++;
225 }
226 }
227
228
229 if (sqlTable.isUpdate() && fields.hasPrimaryKey()) {
230 writer.write(createDIUMethodBody("update", className));
231 updateCount++;
232 }
233 }
234
235 public void setProperties(SqlTable sqlTable, JavaClass javaClass, Fields fields) {
236 this.sqlTable = sqlTable;
237 this.javaClass = javaClass;
238 this.fields = fields;
239 }
240
241 /***
242 * Returns a method body for the given operation type (delete, insert, update).
243 */
244 private String createDIUMethodBody(String diu, String className) {
245 StringBuffer sb = new StringBuffer(512);
246 String fullMethodName = Utils.createMethodName(diu, className, null);
247 sb.append(" public void " + fullMethodName + "(" + className + " object) throws SQLException {\n");
248 sb.append(" Connection con = manager.getConnection();\n");
249 sb.append(" try {\n");
250 sb.append(" " + className + "Handler." + diu + "(object, con);\n");
251 sb.append(" } catch (SQLException sqle) {\n");
252 sb.append(createCallToExceptionCaught(fullMethodName));
253 sb.append(" throw sqle;\n");
254 sb.append(" } finally {\n");
255 sb.append(" manager.releaseConnection(con);\n");
256 sb.append(" }\n");
257 sb.append(" }\n\n");
258 return sb.toString();
259 }
260
261 /***
262 * Creates exceptionCaught() invocation from DIU method.
263 */
264 private String createCallToExceptionCaught(String fullMethodName) {
265 StringBuffer sb = new StringBuffer(512);
266 sb.append(" Map args = new HashMap();\n");
267 sb.append(" args.put(\"object\", object);\n");
268 sb.append(" exceptionCaught(sqle, \"" + fullMethodName + "\", args);\n");
269 return sb.toString();
270 }
271
272 /***
273 * Creates exceptionCaught() invocation from select-method body.
274 */
275 private String createCallToExceptionCaught(String fullMethodName, List primaryKeyList) {
276 StringBuffer sb = new StringBuffer(512);
277 sb.append(" Map args = new HashMap();\n");
278 for (int i = 0, size = primaryKeyList.size() ; i < size ; i++) {
279 Field field = (Field) primaryKeyList.get(i);
280 JavaField javaField = field.getJavaField();
281 sb.append(" args.put(\"" + javaField.getName() + "\", " + javaField.getName() + ");\n");
282 }
283 sb.append(" exceptionCaught(sqle, \"" + fullMethodName + "\", args);\n");
284 return sb.toString();
285 }
286
287 }
288
289
290
291 /***
292 * Puts <code><operations></code> methods.
293 * @author Milosz Tylenda, AIS.PL
294 */
295 class OperationsPutter {
296
297 private Writer writer;
298 public int aggregateCount = 0;
299 public int callCount = 0;
300 public int countCount = 0;
301 public int deleteCount = 0;
302 public int selectCount = 0;
303 public int updateCount = 0;
304
305 public OperationsPutter(Writer awriter) {
306 writer = awriter;
307 }
308
309 public void putAggregate(Aggregate aggregate, JavaClass javaClass) throws IOException {
310 String className = javaClass.getName();
311 JavaMethod javaMethod = aggregate.getJavaMethod();
312 String methodName = javaMethod.getName();
313 List javaParamList = javaMethod.getJavaParamList();
314 writer.write(createOperationMethodBody(aggregate.createReturnType(), "aggregate", className,
315 methodName, javaParamList, aggregate.createReturnForJavadoc()));
316 aggregateCount++;
317 }
318
319 public void putCall(Call call, JavaClass javaClass, Fields fields) throws IOException {
320 String className = javaClass.getName();
321 JavaMethod javaMethod = call.getJavaMethod();
322 String methodName = javaMethod.getName();
323 List javaParamList = javaMethod.createExtendedJavaParamList(javaClass);
324 writer.write(createOperationMethodBody(call.createReturnType(fields), "call", className, methodName, javaParamList,
325 call.createReturnForJavadoc()));
326 callCount++;
327 }
328
329 public void putCount(JavaMethod javaMethod, JavaClass javaClass) throws IOException {
330 String className = javaClass.getName();
331 String methodName = javaMethod.getName();
332 List javaParamList = javaMethod.getJavaParamList();
333 writer.write(createOperationMethodBody("int", "count", className, methodName, javaParamList,
334 "number of counted rows"));
335 countCount++;
336 }
337
338 public void putDelete(JavaMethod javaMethod, JavaClass javaClass) throws IOException {
339 String className = javaClass.getName();
340 String methodName = javaMethod.getName();
341 List javaParamList = javaMethod.getJavaParamList();
342 writer.write(createOperationMethodBody("int", "delete", className, methodName, javaParamList,
343 "number of deleted rows"));
344 deleteCount++;
345 }
346
347 public void putSelect(Select select, JavaClass javaClass) throws IOException {
348 String className = javaClass.getName();
349 JavaMethod javaMethod = select.getJavaMethod();
350 String methodName = javaMethod.getName();
351 List javaParamList = javaMethod.getJavaParamList();
352 writer.write(createOperationMethodBody(select.createReturnType(javaClass), "select", className, methodName,
353 javaParamList, select.createReturnForJavadoc(javaClass)));
354 selectCount++;
355 }
356
357 public void putUpdate(JavaMethod javaMethod, JavaClass javaClass) throws IOException {
358 String className = javaClass.getName();
359 String methodName = javaMethod.getName();
360 List javaParamList = javaMethod.getJavaParamList();
361 writer.write(createOperationMethodBody("int", "update", className, methodName, javaParamList,
362 "number of updated rows"));
363 updateCount++;
364 }
365
366 /***
367 * Returns a method body for the given operation type.
368 */
369 private String createOperationMethodBody(String returnType, String operation, String className, String methodName,
370 List javaParamList, String returnString) {
371 StringBuffer sb = new StringBuffer(1024);
372 String fullMethodName = Utils.createMethodName(operation, className, methodName);
373 String shortMethodName = Utils.createMethodName(operation, null, methodName);
374 String returnOrNothing = "return ";
375 if (returnType.equals("void")) {
376 returnOrNothing = "";
377 }
378 sb.append(" /**\n");
379 sb.append(" * <code>" + fullMethodName + "</code>.\n");
380 sb.append(Utils.formatMethodArgsForJavaDoc(javaParamList));
381 if (returnString != null) {
382 sb.append(" * @return " + returnString + "\n");
383 }
384 sb.append(" * @throws SQLException when operation failed\n");
385 sb.append(" * @see " + className + "Handler#" + shortMethodName + "\n");
386 sb.append(" */\n");
387 sb.append(" public " + returnType + " " + fullMethodName + "(\n");
388 sb.append(" ");
389 sb.append(Utils.formatMethodArgsWithoutComma(javaParamList));
390 sb.append(" ) throws SQLException {\n");
391 sb.append(" Connection con = manager.getConnection();\n");
392 sb.append(" try {\n");
393 sb.append(" " + returnOrNothing + className + "Handler." + shortMethodName + "(\n");
394 sb.append(" ");
395 sb.append(Utils.formatMethodParams(javaParamList));
396 sb.append("con);\n");
397 sb.append(" } catch (SQLException sqle) {\n");
398 sb.append(createCallToExceptionCaught(fullMethodName, javaParamList));
399 sb.append(" throw sqle;\n");
400 sb.append(" } finally {\n");
401 sb.append(" manager.releaseConnection(con);\n");
402 sb.append(" }\n");
403 sb.append(" }\n\n");
404 return sb.toString();
405 }
406
407 /***
408 * Creates exceptionCaught() invocation from operations-method body.
409 */
410 private String createCallToExceptionCaught(String fullMethodName, List javaParamList) {
411 StringBuffer sb = new StringBuffer(512);
412 sb.append(" Map args = new HashMap();\n");
413 for (int i = 0, size = javaParamList.size() ; i < size ; i++) {
414 JavaParam javaParam = (JavaParam) javaParamList.get(i);
415 sb.append(" args.put(\"" + javaParam.getName() + "\", " + javaParam.getName() + ");\n");
416 }
417 sb.append(" exceptionCaught(sqle, \"" + fullMethodName + "\", args);\n");
418 return sb.toString();
419 }
420
421 }
422
423
424
425 /***
426 * Puts some little things like a <code>package</code> string and a class ending brace.
427 * @author Milosz Tylenda, AIS.PL
428 */
429 class MiscPutter {
430
431 private Writer writer;
432 private List javaClassList = new ArrayList();
433 private String packagePrefix/package-summary.html">ong> String packagePrefix;
434 private String className;
435
436 public MiscPutter(Writer awriter) {
437 writer = awriter;
438 }
439
440 public void putHeader() throws IOException {
441 writer.write("package " + packagePrefix + ";\n\n");
442 writer.write("// THIS FILE HAS BEEN GENERATED AUTOMAGICALLY. DO NOT EDIT!\n\n");
443 writer.write("import java.math.BigDecimal;\n\n");
444 writer.write("import java.sql.Connection;\n");
445 writer.write("import java.sql.SQLException;\n");
446 writer.write("import java.sql.Timestamp;\n\n");
447 writer.write("import java.util.HashMap;\n");
448 writer.write("import java.util.Iterator;\n");
449 writer.write("import java.util.List;\n");
450 writer.write("import java.util.Map;\n\n");
451 writer.write("import pl.aislib.fm.Database;\n\n");
452 writer.write("import pl.aislib.fm.jdbc.Manager;\n\n");
453 for (int i = 0, size = javaClassList.size() ; i < size ; i++) {
454 JavaClass javaClass = (JavaClass) javaClassList.get(i);
455 String name = javaClass.getName();
456 writer.write("import " + packagePrefix + "." + objectsSubpackage + "." + name + ";\n");
457 }
458 writer.write("\n");
459 for (int i = 0, size = javaClassList.size() ; i < size ; i++) {
460 JavaClass javaClass = (JavaClass) javaClassList.get(i);
461 String name = javaClass.getName();
462 writer.write("import " + packagePrefix + "." + dbHandlersSubpackage + "." + name + "Handler;\n");
463 }
464 writer.write("\n");
465 writer.write("/**\n");
466 writer.write(" * Application Database.\n");
467 writer.write(" * @author DatabaseGenerator\n");
468 writer.write(" */\n");
469 writer.write("public class " + className + " extends Database {\n\n");
470 writer.write(" public " + className + "(Manager manager) {\n");
471 writer.write(" super(manager);\n");
472 writer.write(" }\n\n");
473 }
474
475 public void putClassEndBrace() throws IOException {
476 writer.write("}\n");
477 }
478
479 public void addJavaClass(JavaClass javaClass) {
480 javaClassList.add(javaClass);
481 }
482
483 public void setProperties(String packagePrefix, String className) {/package-summary.html">ong> void setProperties(String packagePrefix, String className) {
484 this.packagePrefix = packagePrefix;
485 this.className = className;
486 }
487
488 /***
489 * Generates exceptionCaught() method which is invoked from other methods if
490 * an SQLException is caught.
491 */
492 public void putExceptionCaught() throws IOException {
493 writer.write(" /**\n");
494 writer.write(" * Logs the given arguments on <code>FATAL</code> level.\n");
495 writer.write(" * Invoked from other methods when an <code>SQLException</code> is thrown.\n");
496 writer.write(" * @param sqle the caught <code>SQLException</code>\n");
497 writer.write(" * @param methodName the name of method where the exception has been thrown\n");
498 writer.write(" * @param methodArgs the names and values of method arguments where the exception has been thrown\n");
499 writer.write(" * - (argument name, argument value) pairs\n");
500 writer.write(" */\n");
501 writer.write(" protected void exceptionCaught(SQLException sqle, String methodName, Map methodArgs) {\n");
502 writer.write(" String id = \"[\" + (System.currentTimeMillis() / 1000) + \"] \";\n");
503 writer.write(" log.fatal(id + \"SQLException caught in \" + methodName + \" method\");\n");
504 writer.write(" log.fatal(id + \"Method arguments:\");\n");
505 writer.write(" for (Iterator iter = methodArgs.entrySet().iterator() ; iter.hasNext(); ) {\n");
506 writer.write(" Map.Entry entry = (Map.Entry) iter.next();\n");
507 writer.write(" String name = String.valueOf(entry.getKey());\n");
508 writer.write(" String value = stringValue(entry.getValue());\n");
509 writer.write(" log.fatal(id + name + \"=\" + value);\n");
510 writer.write(" }\n");
511 writer.write(" log.fatal(id + \"The caught SQLException:\", sqle);\n");
512 writer.write(" while ((sqle = sqle.getNextException()) != null) {\n");
513 writer.write(" log.fatal(id + \"Next SQLException:\", sqle);\n");
514 writer.write(" }\n");
515 writer.write(" }\n");
516 writer.write("\n");
517 writer.write(" /**\n");
518 writer.write(" * Converts the given <code>Object</code> to its <code>String</code> representation.\n");
519 writer.write(" * @param value the <code>Object</code> to convert\n");
520 writer.write(" * @return the result of conversion\n");
521 writer.write(" */\n");
522 writer.write(" private String stringValue(Object value) {\n");
523 writer.write(" if (value == null) {\n");
524 writer.write(" return \"null\";\n");
525 writer.write(" }\n");
526 writer.write(" if (value instanceof String) {\n");
527 writer.write(" return \"'\" + value + \"'\";\n");
528 writer.write(" }\n");
529 writer.write(" return String.valueOf(value);\n");
530 writer.write(" }\n");
531 writer.write("\n");
532 }
533
534 }
535
536 }
537
538 /***
539 * $Log: DatabaseGenerator.java,v $
540 * Revision 1.23 2004/08/11 12:41:01 wswiatek
541 * Database and map handlers location are now parametrizable.
542 * Maven plugin version changed to 1.0.1
543 *
544 * Revision 1.22 2003/10/29 11:47:02 pikus
545 * use ant logger where possible
546 *
547 * Revision 1.21 2003/09/12 13:22:19 milosz
548 * Refactoring: syntax checking moved from generators to DatabaseChecker and other classes in structure package.
549 *
550 * Revision 1.20 2003/09/10 07:35:43 milosz
551 * Support for operations/call element added.
552 *
553 * Revision 1.19 2003/07/11 13:08:14 milosz
554 * objectsSubpackage property added.
555 *
556 * Revision 1.18 2003/06/04 08:01:32 milosz
557 * 'multipleRows' attribute added to operations/select element; corrected code for operations/aggregate.
558 *
559 * Revision 1.17 2003/05/26 08:36:03 pikus
560 * cleanup imports
561 *
562 * Revision 1.16 2003/05/14 13:39:03 milosz
563 * operations/aggregate element added.
564 *
565 * Revision 1.15 2003/04/08 09:54:24 milosz
566 * Removed unnecessary <code> tag from @throws tag in JavaDoc.
567 *
568 * Revision 1.14 2003/04/04 07:59:15 milosz
569 * exceptionCaught method is generated.
570 *
571 * Revision 1.13 2003/03/28 14:52:33 milosz
572 * Added @see tag generation in operations methods.
573 *
574 * Revision 1.12 2003/03/28 14:39:22 milosz
575 * Refactoring: Four subclasses collapsed to OperationsPutter subclass.
576 *
577 * Revision 1.11 2003/03/28 14:06:33 milosz
578 * Refactoring: createDIUMethodBody and createOperationMethodBody methods extracted.
579 *
580 * Revision 1.10 2003/03/27 16:20:17 milosz
581 * createMethodName method added.
582 *
583 * Revision 1.9 2002/12/03 11:53:12 milosz
584 * Added JavaDoc generation to operations/select.
585 *
586 * Revision 1.8 2002/12/03 11:09:20 milosz
587 * operations/count element added.
588 *
589 * Revision 1.7 2002/12/03 09:10:50 milosz
590 * operations/update element added.
591 *
592 * Revision 1.6 2002/12/02 14:28:13 milosz
593 * operations/delete element added.
594 *
595 * Revision 1.5 2002/10/09 10:03:31 milosz
596 * Better messages and behaviour for structure without primary keys.
597 *
598 * Revision 1.4 2002/10/08 09:28:12 milosz
599 * Added necessary imports;
600 *
601 * Revision 1.3 2002/10/08 08:27:10 milosz
602 * Generators became AntTasks(?). Ufff...
603 *
604 * Revision 1.2 2002/10/04 13:07:22 milosz
605 * Reaching old mapping's functionality.
606 *
607 */
608