001: /**
002: * Objective Database Abstraction Layer (ODAL)
003: * Copyright (c) 2004, The ODAL Development Group
004: * All rights reserved.
005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
006: *
007: * Distributable under LGPL license.
008: * See terms of license at gnu.org.
009: */package com.completex.objective.tools.generators;
010:
011: import com.completex.objective.components.log.Log;
012: import com.completex.objective.components.log.adapter.StdOutputLogAdapter;
013: import com.completex.objective.components.persistency.ColumnType;
014: import com.completex.objective.components.persistency.UserDefinedTypeMetaColumn;
015: import com.completex.objective.components.persistency.UserDefinedTypeMetaModel;
016: import com.completex.objective.components.persistency.UserDefinedTypeMetaTable;
017: import com.completex.objective.components.persistency.meta.impl.UdtBaseModelLoaderPlugin;
018: import com.completex.objective.components.sdl.reader.SdlReader;
019: import com.completex.objective.components.sdl.reader.impl.SdlReaderImpl;
020: import com.completex.objective.util.PropertyMap;
021: import com.completex.objective.util.StringUtil;
022: import freemarker.template.Template;
023: import freemarker.template.TemplateException;
024:
025: import java.io.*;
026: import java.sql.SQLException;
027: import java.util.*;
028:
029: /**
030: * Under construction
031: *
032: * @author Gennady Krizhevsky
033: */
034: public class UDTObjectGenerator {
035:
036: // private static final String CLASS_BEAN_TEMPLATE = "ftl/sprint-udt-object-oracle-bean.ftl";
037:
038: protected static final Log logger = StdOutputLogAdapter
039: .newLogInstance();
040: protected UdtBaseModelLoaderPlugin modelBaseLoaderAdapter;
041: protected UserDefinedTypeMetaModel model;
042: protected SdlReader sdlReader = new SdlReaderImpl();
043:
044: private static Map TYPE_2_JAVA = new LinkedHashMap();
045:
046: {
047: for (int i = 0; i < ColumnType.getColumnTypes().length; i++) {
048: registerType(ColumnType.getColumnTypes()[i]);
049: }
050: }
051:
052: private static Map TYPE_2_JDBC_RW = new LinkedHashMap();
053:
054: {
055: for (int i = 0; i < ColumnType.getColumnTypes().length; i++) {
056: registerJdbcRwType(ColumnType.getColumnTypes()[i]);
057: }
058: }
059:
060: private void registerJdbcRwType(ColumnType type) {
061: String clazz = type.getValueClassSimpleName();
062:
063: if (ColumnType.isNumeric(type)) {
064: clazz = "BigDecimal";
065: }
066:
067: if (ColumnType.isDate(type)) {
068: clazz = "Timestamp";
069: }
070:
071: UDTObjectGenerator.TYPE_2_JDBC_RW.put(type, clazz);
072: }
073:
074: public static String getJdbcRwType(ColumnType type) {
075: return (String) UDTObjectGenerator.TYPE_2_JDBC_RW.get(type);
076: }
077:
078: private static final String INTERNAL_DESC_PATH = "intern_path"; // Internal descriptor file path
079: private static final String EXTERNAL_DESC_PATH = "extern_path"; // External descriptor file path
080: private static final String OUT_DIR = "out_dir"; // Top level directory for generated classes
081: private static final String PACKAGE = "package"; // Package
082: private static final String TEMPLATE_PATH = "template_path"; // Full template path
083: private static final String TEMPLATE = "template"; // Path when loading as resource
084: private static final String FILTER_PATTERN = "filter_pattern";
085: private static final String CLASS_PREFIX = "class_prefix";
086: private static final String CLASS_SUFFIX = "class_suffix";
087: private static final String GENERATE_INTERFACES = "generate_interfaces";
088: private static final String GENERATE_BEAN = "generate_bean";
089: private static final String GENERATE_HIERARCHY = "generate_hierarchy";
090:
091: private static final String EXTENDS = "extends";
092: private static final String IMPLEMENTS = "implements";
093:
094: private UDTObjectGenerator.LineStruct classStruct = new UDTObjectGenerator.LineStruct();
095: private UDTObjectGenerator.LineStruct arrayStruct = new UDTObjectGenerator.LineStruct();
096: private boolean debug = false;
097: private static final String GENERIC = "generic";
098: private static final String CLASSES = "classes";
099: private static final String ARRAYS = "arrays";
100:
101: public UDTObjectGenerator(String propertiesPath) throws Exception {
102: registerExtraTypes();
103: initializeFromSdl(propertiesPath);
104: setUp();
105: }
106:
107: protected void registerType(ColumnType type) {
108: String className = type.getValueClassName();
109:
110: if (ColumnType.contains(type)) {
111: className = type.getValueClassSimpleName();
112: }
113:
114: UDTObjectGenerator.TYPE_2_JAVA.put(type, className);
115: }
116:
117: protected void unregisterType(ColumnType type) {
118: UDTObjectGenerator.TYPE_2_JAVA.remove(type);
119: }
120:
121: private void initializeFromSdl(String propertiesPath)
122: throws Exception {
123: Map properties = (Map) sdlReader.read(new FileReader(
124: propertiesPath));
125: PropertyMap propertyMap = PropertyMap.toPropertyMap(properties);
126: PropertyMap generic = PropertyMap
127: .toPropertyMap((Map) propertyMap.get(
128: UDTObjectGenerator.GENERIC, true));
129: PropertyMap classes = PropertyMap
130: .toPropertyMap((Map) propertyMap.get(
131: UDTObjectGenerator.CLASSES, true));
132: PropertyMap arrays = PropertyMap
133: .toPropertyMap((Map) propertyMap
134: .get(UDTObjectGenerator.ARRAYS));
135:
136: classStruct = toLineStruct(generic, classes);
137: arrayStruct = toLineStruct(generic, arrays);
138: }
139:
140: private UDTObjectGenerator.LineStruct toLineStruct(
141: PropertyMap generic, PropertyMap classes) {
142: UDTObjectGenerator.LineStruct lineStruct = new UDTObjectGenerator.LineStruct();
143: lineStruct.inFilePath = generic.getProperty(
144: UDTObjectGenerator.INTERNAL_DESC_PATH, true);
145: lineStruct.exFilePath = generic.getProperty(
146: UDTObjectGenerator.EXTERNAL_DESC_PATH, true);
147: lineStruct.template = generic
148: .getProperty(UDTObjectGenerator.TEMPLATE);
149: lineStruct.generateBean = generic.getBoolean(
150: UDTObjectGenerator.GENERATE_BEAN, Boolean.FALSE, false);
151: lineStruct.generateInterfaces = generic
152: .getBoolean(UDTObjectGenerator.GENERATE_INTERFACES);
153: lineStruct.generateHierarchy = generic
154: .getBoolean(UDTObjectGenerator.GENERATE_HIERARCHY);
155:
156: lineStruct.outDir = classes.getProperty(
157: UDTObjectGenerator.OUT_DIR, true);
158: lineStruct.packageName = classes.getProperty(
159: UDTObjectGenerator.PACKAGE, true);
160: lineStruct.templatePath = classes
161: .getProperty(UDTObjectGenerator.TEMPLATE_PATH);
162: lineStruct.template = classes
163: .getProperty(UDTObjectGenerator.TEMPLATE);
164: lineStruct.filterPattern = classes
165: .getProperty(UDTObjectGenerator.FILTER_PATTERN);
166: lineStruct.classPrefix = classes.getProperty(
167: UDTObjectGenerator.CLASS_PREFIX, "");
168: lineStruct.classSuffix = classes.getProperty(
169: UDTObjectGenerator.CLASS_SUFFIX, null);
170: lineStruct.extendsString = classes
171: .getProperty(UDTObjectGenerator.EXTENDS);
172: lineStruct.implements String = classes
173: .getProperty(UDTObjectGenerator.IMPLEMENTS);
174: return lineStruct;
175: }
176:
177: protected void setUp() throws Exception, SQLException {
178: modelBaseLoaderAdapter = new UdtBaseModelLoaderPlugin(
179: classStruct.exFilePath, classStruct.inFilePath);
180: model = modelBaseLoaderAdapter.load(null);
181: }
182:
183: protected UserDefinedTypeMetaModel loadModelFromFile()
184: throws Exception {
185: UDTObjectGenerator.logger.info("loadModelFromFile started");
186:
187: UserDefinedTypeMetaModel model = modelBaseLoaderAdapter
188: .load(null);
189: UDTObjectGenerator.logger.info("loadModelFromFile ended");
190:
191: return model;
192: }
193:
194: protected void process() throws IOException, TemplateException {
195: generateClasses(classStruct, false);
196: generateClasses(arrayStruct, true);
197: }
198:
199: protected void generateClasses(
200: UDTObjectGenerator.LineStruct lineStruct, boolean collection)
201: throws IOException, TemplateException {
202: Date timestamp = new Date();
203: String outputDir = FileUtil.makePath(lineStruct.packageName,
204: lineStruct.outDir);
205:
206: Template template = null;
207: template = getTemplate(lineStruct.templatePath,
208: lineStruct.template);
209:
210: for (Iterator it = model.typeTableNameIterator(); it.hasNext();) {
211: String tableName = (String) it.next();
212: if ("OE_COMP_ORDER_OBJ".equals(tableName)) {
213: int k = 0;
214: }
215: UserDefinedTypeMetaTable table = model
216: .getTypeTable(tableName);
217:
218: if ((table.isCollection() && !collection)
219: || (!table.isCollection() && collection)) {
220: continue;
221: }
222:
223: boolean mainPattern = true;
224: String className = className(table, lineStruct, mainPattern);
225: Map templateModel = new LinkedHashMap();
226: templateModel.put("package", lineStruct.packageName);
227: templateModel.put("timestamp", timestamp);
228: templateModel.put("className", className);
229: templateModel.put("generateHierarchy",
230: lineStruct.generateHierarchy + "");
231: templateModel.put("superType", table.getSuperTypeName());
232: String extendsString = lineStruct.extendsString;
233: if (lineStruct.generateHierarchy) {
234: if (table.getSuperTypeName() != null) {
235: UserDefinedTypeMetaTable super Table = model
236: .getTypeTable(table.getSuperTypeName());
237: String super ClassName = className(super Table
238: .getAlias(), lineStruct, mainPattern);
239: extendsString = addToExtends(
240: lineStruct.extendsString, super ClassName);
241: }
242: }
243: templateModel.put("extends", extendsString);
244: templateModel
245: .put("implements", lineStruct.implements String);
246:
247: ArrayList imports = new ArrayList();
248: if (classStruct.generateInterfaces) {
249: String interfaceName = interfaceName(table,
250: mainPattern, arrayStruct);
251: imports.add(arrayStruct.packageName + "."
252: + interfaceName);
253: }
254:
255: templateModel.put("imports", imports);
256: String tableConst = UDTObjectGenerator.javaConstName(
257: "TABLE_", table.getAlias());
258: templateModel.put("tableNameConst", tableConst);
259: templateModel.put("tableName", table.getName());
260: templateModel.put("tableAlias", table.getAlias());
261: templateModel.put("asize", "" + table.size());
262: templateModel.put("keySize", new Integer(table.size()));
263: String interfaceName = interfaceName(table, true,
264: arrayStruct);
265: templateModel.put("interfaces",
266: lineStruct.generateInterfaces ? "implements "
267: + interfaceName : "");
268: templateModel.put("generateInterfaces",
269: lineStruct.generateInterfaces + "");
270: if (table.isCollection()) {
271: UserDefinedTypeMetaTable subTable = model
272: .getTypeTable(table.getCollectionOfName());
273: templateModel.put("baseTypeName", table
274: .getCollectionOfName());
275: templateModel.put("baseTypeClass", className(subTable,
276: lineStruct, mainPattern));
277: }
278:
279: List columns = new ArrayList(table.size());
280: templateModel.put("columns", columns);
281: for (int i = 0; i < table.size(); i++) {
282: UserDefinedTypeMetaColumn metaColumn = table
283: .getColumn(i);
284: UDTObjectGenerator.logger.debug("Processing column ["
285: + metaColumn + "]");
286: Map column = new LinkedHashMap();
287: String colAlias = metaColumn.getColumnAlias();
288: String colAliasNameResolved = UDTObjectGenerator
289: .javaName(metaColumn.getColumnAlias(), null,
290: null, false);
291:
292: column
293: .put("javaName", UDTObjectGenerator.javaName(
294: metaColumn.getColumnAlias(), null,
295: null, false));
296: column.put("javaType", javaType(metaColumn.getType(),
297: metaColumn, model));
298: column.put("jdbcRead", jdbcRead(metaColumn.getType(),
299: metaColumn, model));
300: column.put("jdbcWrite", jdbcWrite(metaColumn, model));
301: column.put("jdbcType", metaColumn.getJdbcType() + "");
302: column.put("javaClass", metaColumn.getType()
303: .getValueClassName());
304: if (lineStruct.generateHierarchy) {
305: column.put("existInSuperType", metaColumn
306: .isExistInSuperType()
307: + "");
308: } else {
309: column.put("existInSuperType", "false");
310: }
311:
312: boolean primitive = ColumnType.isPrimitive(metaColumn
313: .getType());
314: column.put("primitive", primitive + "");
315: String object2primitive = null;
316: String primitive2object = null;
317: String primitiveCast = null;
318: if (primitive) {
319: if (ColumnType.isNumeric(metaColumn.getType())) {
320: object2primitive = "Number2"
321: + javaType(metaColumn.getType(),
322: metaColumn, model);
323: primitive2object = javaType(metaColumn
324: .getType(), metaColumn, model)
325: + "2Number";
326: primitiveCast = "Number";
327: } else if (ColumnType.BOOLEAN_PRIMITIVE
328: .equals(metaColumn.getType())) {
329: object2primitive = "Boolean2boolean";
330: primitive2object = "boolean2Boolean";
331: primitiveCast = "Boolean";
332: } else {
333: throw new UnsupportedOperationException(
334: "Unsupported type for primitive: "
335: + metaColumn.getType());
336: }
337: }
338:
339: column.put("getOrIs", UDTObjectGenerator
340: .getOrIs(metaColumn));
341: column.put("primitiveCast", primitiveCast);
342: if (metaColumn.getType() == ColumnType.OBJECT
343: && model.getTypeTable(metaColumn.getTypeName()) != null) {
344: column.put("udt", "true");
345: } else {
346: column.put("udt", "false");
347: }
348: column.put("object2primitive", object2primitive);
349: column.put("primitive2object", primitive2object);
350: column.put("columnName", metaColumn.getColumnName());
351: column.put("columnNameConst", UDTObjectGenerator
352: .javaConstName("COL_", metaColumn
353: .getColumnAlias()));
354: column.put("tColumnName", table.getName() + "."
355: + metaColumn.getColumnName());
356: column.put("tColumnNameConst", UDTObjectGenerator
357: .javaConstName("TCOL_", metaColumn
358: .getColumnAlias()));
359: column.put("columnAlias", metaColumn.getColumnAlias());
360: column.put("columnIndexConst", UDTObjectGenerator
361: .javaConstName("ICOL_", metaColumn
362: .getColumnAlias()));
363: column.put("columnIndex", metaColumn.getColumnIndex()
364: + "");
365: String typeString = null;
366: if (ColumnType.contains(metaColumn.getType())) {
367: typeString = "ColumnType."
368: + metaColumn.getType().getName()
369: .toUpperCase();
370: } else {
371: typeString = "new "
372: + metaColumn.getType().getClass().getName()
373: + "()";
374: }
375: column.put("type", typeString);
376: column.put("decimalDigits", metaColumn
377: .getDecimalDigits()
378: + "");
379: columns.add(column);
380: }
381: // FK
382:
383: UDTObjectGenerator.logger.debug("outputDir = " + outputDir
384: + "; table = " + table.getAlias());
385:
386: String classFileName = className + ".java";
387: Writer writer = new FileWriter(new File(outputDir,
388: classFileName));
389: template.process(templateModel, writer);
390: writer.flush();
391: writer.close();
392: printGeneratedClassFileInfo(classFileName, outputDir);
393: }
394: }
395:
396: private String addToExtends(String extendsString, String value) {
397: return extendsString == null ? value : extendsString + ", "
398: + value;
399: }
400:
401: private String className(String tableAlias,
402: UDTObjectGenerator.LineStruct lineStruct,
403: boolean mainPattern) {
404: return UDTObjectGenerator.javaName(tableAlias,
405: lineStruct.classPrefix, lineStruct.classSuffix, true,
406: mainPattern);
407: }
408:
409: private String className(UserDefinedTypeMetaTable table,
410: UDTObjectGenerator.LineStruct lineStruct,
411: boolean mainPattern) {
412: return className(table.getAlias(), lineStruct, mainPattern);
413: }
414:
415: private Template getTemplate(String templatePath,
416: String defaultTemplateFileName) throws IOException {
417: return TemplateHelper.getTemplate(templatePath,
418: defaultTemplateFileName, this .getClass(), debug);
419: }
420:
421: private String interfaceName(UserDefinedTypeMetaTable table,
422: boolean mainPattern,
423: UDTObjectGenerator.LineStruct intfStruct) {
424: String className = className(table, intfStruct, mainPattern);
425: return className;
426: }
427:
428: public String jdbcRead(ColumnType type,
429: UserDefinedTypeMetaColumn metaColumn,
430: UserDefinedTypeMetaModel model) {
431: String convertMethod = null;
432: if (ColumnType.isNumeric(type)) {
433: convertMethod = "Number2" + type.getValueClassSimpleName();
434: }
435:
436: String rc = null;
437: if (convertMethod != null) {
438: rc = convertMethod + "(stream.readBigDecimal())";
439: } else {
440: rc = "stream.read"
441: + StringUtil.capitalizeFirst(type
442: .getValueClassSimpleName()) + "()";
443: }
444:
445: if (type == ColumnType.OBJECT) {
446: String javaType = javaType(type, metaColumn, model);
447: if (javaType != null) {
448: // Add cast:
449: UserDefinedTypeMetaTable subType = findUdt(metaColumn,
450: model);
451: if (subType == null) {
452: rc = "(" + javaType + ") " + rc;
453: } else {
454: if (subType.isCollection()) {
455: rc = "(arr = readArray(stream)) == null ? null : new "
456: + javaType + "(arr).toObjects()";
457: } else {
458: rc = "(" + javaType + ") readObject(stream, "
459: + javaType + ".class)";
460:
461: }
462: }
463: }
464: }
465: return rc;
466: }
467:
468: public String jdbcWrite(UserDefinedTypeMetaColumn metaColumn,
469: UserDefinedTypeMetaModel model) {
470: ColumnType type = metaColumn.getType();
471: String fieldName = UDTObjectGenerator.javaName(metaColumn
472: .getColumnAlias(), null, null, false);
473: boolean collection = false;
474: if (ColumnType.OBJECT == type) {
475: //
476: // If this is object - try to find real type for the class by COLUMN name
477: // - in this case it coincides with table key for the dependency type:
478: //
479: UserDefinedTypeMetaTable table = findUdt(metaColumn, model);
480: collection = table.isCollection();
481: }
482: String convertMethod = null;
483: if (collection) {
484: convertMethod = "stream.writeArray(" + fieldName + ")";
485: } else {
486: if (ColumnType.isNumeric(type)) {
487: convertMethod = "Number2BigDecimal";
488: if (ColumnType.isPrimitive(type)) {
489: convertMethod = StringUtil
490: .uncapitalizeFirst(convertMethod);
491: }
492: convertMethod = "stream.writeBigDecimal("
493: + convertMethod + "(" + fieldName + "))";
494: } else if (ColumnType.isDate(type)) {
495: convertMethod = "date2Timestamp";
496: convertMethod = "stream.writeTimestamp" + "("
497: + convertMethod + "(" + fieldName + "))";
498: }
499: }
500:
501: String rc = null;
502: if (convertMethod != null) {
503: rc = convertMethod;
504: } else {
505: rc = "stream.write"
506: + StringUtil.capitalizeFirst(type
507: .getValueClassSimpleName()) + "("
508: + fieldName + ")";
509: }
510: return rc;
511: }
512:
513: public String javaType(ColumnType type,
514: UserDefinedTypeMetaColumn metaColumn,
515: UserDefinedTypeMetaModel model) {
516: String javaType = (String) UDTObjectGenerator.TYPE_2_JAVA
517: .get(type);
518: if (javaType == null) {
519: javaType = type.getValueClassName();
520: }
521: if (ColumnType.OBJECT == type) {
522: //
523: // If this is object - try to find real type for the class by COLUMN name
524: // - in this case it coincides with table key for the dependency type:
525: //
526: UserDefinedTypeMetaTable table = findUdt(metaColumn, model);
527: javaType = UDTObjectGenerator.javaName(table.getName()
528: .toLowerCase(), null, null, true);
529: }
530: return javaType;
531: }
532:
533: private UserDefinedTypeMetaTable findUdt(
534: UserDefinedTypeMetaColumn metaColumn,
535: UserDefinedTypeMetaModel model) {
536: String typeName = metaColumn.getTypeName();
537: UserDefinedTypeMetaTable table = model.getTypeTable(typeName);
538: return table;
539: }
540:
541: public static String javaName(String name, String prefix,
542: String suffix, boolean calitalizeFirstChar) {
543: return NameHelper.javaName(name, prefix, suffix,
544: calitalizeFirstChar, true);
545: }
546:
547: public static String getOrIs(UserDefinedTypeMetaColumn column) {
548: return ColumnType.isBooleanPrimitive(column.getType()) ? "is"
549: : "get";
550: }
551:
552: public static String javaName(String name, String prefix,
553: String suffix, boolean calitalizeFirstChar,
554: boolean mainPattern) {
555: return NameHelper.javaName(name, prefix, suffix,
556: calitalizeFirstChar, mainPattern);
557: }
558:
559: public static String lowerFirstChar(String name) {
560: // return NameHelper.lowerFirstChar(name);
561: return NameHelper.decapitalizeField(name);
562: }
563:
564: public static String javaConstName(String prefix, String name) {
565: return NameHelper.javaConstName(prefix, name);
566: }
567:
568: static boolean isMixedCase(String name) {
569: return NameHelper.isMixedCase(name);
570: }
571:
572: public UserDefinedTypeMetaModel getModel() {
573: return model;
574: }
575:
576: //
577: //
578: // Util classes
579: //
580: //
581: static class LineStruct {
582: String inFilePath;
583: String exFilePath;
584: String outDir;
585: String packageName;
586: String templatePath;
587: String filterPattern;
588: String classPrefix;
589: String classSuffix;
590: String parentClass;
591: boolean generateInterfaces;
592: boolean generateBean = true;
593: boolean generateHierarchy;
594: String extendsString;
595: String implements String;
596: String template;
597:
598: }
599:
600: public static Map getType2JavaMap() {
601: Map map = UDTObjectGenerator.TYPE_2_JAVA;
602: return map;
603: }
604:
605: protected void registerExtraTypes() {
606: }
607:
608: protected static void printGeneratedClassFileInfo(
609: String classFileName, String outputDir) {
610: System.out.println("GENERATED CLASS [" + classFileName
611: + "] IN " + outputDir);
612: }
613:
614: /**
615: * @param args
616: * @throws Exception
617: */
618: public static void main(String[] args) throws Exception {
619: if (args.length < 1) {
620: System.out
621: .println("ERROR: UDT Object Generator has to have one command line parameter - <persistent-object.properties> ");
622: System.exit(1);
623: }
624: System.out.println("STARTED GENERATION ...");
625:
626: UDTObjectGenerator generator = new UDTObjectGenerator(args[0]);
627:
628: generator.process();
629:
630: System.out.println("FINISHED GENERATION");
631: }
632:
633: }
|