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.impl.PrimitiveLogImpl;
013: import com.completex.objective.components.log.adapter.StdOutputLogAdapter;
014: import com.completex.objective.components.persistency.ColumnType;
015: import com.completex.objective.components.persistency.JavaToMetaTypeImpl;
016: import com.completex.objective.components.persistency.MetaColumn;
017: import com.completex.objective.components.persistency.MetaTable;
018: import com.completex.objective.components.persistency.meta.MetaModel;
019: import com.completex.objective.components.persistency.meta.adapter.ModelLoaderAdapter;
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.BufferedReader;
026: import java.io.File;
027: import java.io.FileInputStream;
028: import java.io.FileReader;
029: import java.io.FileWriter;
030: import java.io.IOException;
031: import java.io.Reader;
032: import java.io.Writer;
033: import java.sql.SQLException;
034: import java.util.ArrayList;
035: import java.util.Arrays;
036: import java.util.Date;
037: import java.util.Iterator;
038: import java.util.LinkedHashMap;
039: import java.util.List;
040: import java.util.Map;
041:
042: /**
043: * Args[0]: lifecycle-ctl-config.properties
044: *
045: * @author Gennady Krizhevsky
046: */
047: public class LifeCycleControllerGenerator {
048:
049: private static final String DEFAULT_CLASS_TEMPLATE = "ftl/life-cycle-ctl.ftl";
050:
051: protected static final String[] toUncommectTrimRight = {};
052:
053: protected static final ArrayList namesToUncommectTrimRight = new ArrayList();
054:
055: protected static final Log logger = StdOutputLogAdapter
056: .newInfoLogInstance();
057:
058: public static final String DEFAULT_SUFFIX = "Ctl";
059:
060: protected com.completex.objective.components.persistency.meta.adapter.ModelLoaderAdapter modelFileLoaderAdapter;
061: protected com.completex.objective.components.persistency.meta.MetaModel model;
062:
063: public static final List imports = new ArrayList();
064:
065: static {
066: imports
067: .add("com.completex.objective.components.persistency.core.impl.AbstractLifeCycleController");
068: imports
069: .add("com.completex.objective.components.persistency.LifeCycleController");
070: imports
071: .add("com.completex.objective.components.persistency.Record");
072: imports
073: .add("com.completex.objective.components.persistency.rule.*");
074: imports
075: .add("com.completex.objective.components.persistency.rule.impl.*");
076: imports.add("java.math.BigDecimal");
077: imports
078: .add("com.completex.objective.components.persistency.PersistentObject");
079: }
080:
081: public static final String INTERNAL_DESC_PATH = "intern_path"; // Internal descriptor file path
082: public static final String EXTERNAL_DESC_PATH = "extern_path"; // External descriptor file path
083: public static final String OUT_DIR = "out_dir"; // Top level directory for generated classes
084: public static final String PACKAGE = "package"; // Package
085: public static final String TEMPLATE_PATH = "template_path"; // Package
086: public static final String FILTER_PATTERN = "filter_pattern";
087: public static final String CLASS_PREFIX = "class_prefix";
088: public static final String CLASS_SUFFIX = "class_suffix";
089: public static final String PERSISTENT_CLASS_PACKAGE = "persistent_class_package";
090: public static final String CTL_PREFIX = "ctl_prefix";
091: public static final String CTL_SUFFIX = "ctl_suffix";
092: public static final String DEBUG = "debug";
093: protected boolean debug;
094:
095: private LineStruct lineStruct = new LineStruct();
096:
097: public LifeCycleControllerGenerator() {
098: }
099:
100: public void process(String propertiesPath) throws Exception {
101: PropertyMap properties = toProperties(propertiesPath);
102: process(properties);
103: }
104:
105: public void process(PropertyMap properties) throws Exception {
106: initialize(properties);
107: setup();
108: process();
109: }
110:
111: private PropertyMap toProperties(String propertiesPath)
112: throws IOException {
113: PropertyMap properties = new PropertyMap();
114: properties.load(new FileInputStream(propertiesPath));
115: return properties;
116: }
117:
118: public void initialize(PropertyMap properties) throws Exception {
119: logger.debug("INPUT: " + properties);
120:
121: lineStruct.inFilePath = properties.getProperty(
122: INTERNAL_DESC_PATH, true);
123: lineStruct.exFilePath = properties.getProperty(
124: EXTERNAL_DESC_PATH, true);
125: lineStruct.outputPath = properties.getProperty(OUT_DIR, true);
126: lineStruct.packageName = properties.getProperty(PACKAGE, true);
127: lineStruct.templatePath = properties.getProperty(TEMPLATE_PATH);
128: lineStruct.filterPattern = properties
129: .getProperty(FILTER_PATTERN);
130: lineStruct.classPrefix = properties.getProperty(CLASS_PREFIX);
131: lineStruct.classSuffix = properties.getProperty(CLASS_SUFFIX);
132: lineStruct.persistentClassPackage = properties
133: .getProperty(PERSISTENT_CLASS_PACKAGE);
134: lineStruct.ctlPrefix = properties.getProperty(CTL_PREFIX);
135: lineStruct.ctlSuffix = properties.getProperty(CTL_SUFFIX,
136: DEFAULT_SUFFIX);
137: debug = properties.getBoolean(DEBUG);
138: if (logger instanceof PrimitiveLogImpl) {
139: ((PrimitiveLogImpl) logger).setDebugEnabled(debug);
140: }
141:
142: }
143:
144: protected void setup() throws Exception, SQLException {
145:
146: String inFilePath = lineStruct.inFilePath;
147: Reader internalFileReader = new BufferedReader(new FileReader(
148: inFilePath));
149: String exFilePath = lineStruct.exFilePath;
150: Reader externalFileReader = new BufferedReader(new FileReader(
151: exFilePath));
152:
153: JavaToMetaTypeImpl javaToMetaType = new JavaToMetaTypeImpl();
154: modelFileLoaderAdapter = new ModelLoaderAdapter(
155: new ModelLoaderAdapter.InternalFileModelLoaderAdapter(
156: internalFileReader, lineStruct.filterPattern),
157: new ModelLoaderAdapter.ExternalFileModelLoaderAdapter(
158: externalFileReader, lineStruct.filterPattern),
159: javaToMetaType, logger);
160: model = modelFileLoaderAdapter.load(null);
161:
162: }
163:
164: protected MetaModel loadModelFromFile() throws Exception {
165: logger.info("loadModelFromFile started");
166:
167: MetaModel model = modelFileLoaderAdapter.load(null);
168: logger.info("loadModelFromFile ended");
169:
170: return model;
171: }
172:
173: private void process() throws IOException, TemplateException {
174: generateTemplate();
175: }
176:
177: private void generateTemplate() throws IOException,
178: TemplateException {
179: Date timestamp = new Date();
180: String outputDir = FileUtil.makePath(lineStruct.packageName,
181: lineStruct.outputPath);
182:
183: Template template = com.completex.objective.tools.generators.TemplateHelper
184: .getTemplate(lineStruct.templatePath,
185: DEFAULT_CLASS_TEMPLATE, this .getClass(), false);
186:
187: printGeneratedIn(outputDir);
188:
189: for (Iterator it = model.tableIterator(); it.hasNext();) {
190: Map.Entry entry = (Map.Entry) it.next();
191: logger.debug("ENTRY " + entry);
192: logger.debug("ENTRY CLASS " + entry.getClass().getName());
193: MetaTable table = (MetaTable) entry.getValue();
194:
195: String className = PersistentObjectGenerator.javaName(table
196: .getTableAlias(), lineStruct.ctlPrefix,
197: lineStruct.ctlSuffix, true);
198: String prefix = lineStruct.classPrefix;
199: String suffix = lineStruct.classSuffix;
200: String persistentObjectName = PersistentObjectGenerator
201: .javaName(table.getTableAlias(), prefix, suffix,
202: true);
203:
204: Map templateModel = new LinkedHashMap();
205: templateModel.put("package", lineStruct.packageName);
206: templateModel.put("timestamp", timestamp);
207: templateModel.put("className", className);
208: templateModel.put("persistentObjectName",
209: persistentObjectName);
210: String persistentClassPackage = "";
211: if (lineStruct.persistentClassPackage != null) {
212: persistentClassPackage = "import "
213: + lineStruct.persistentClassPackage + "."
214: + className;
215: if (!lineStruct.persistentClassPackage
216: .equals(lineStruct.packageName)) {
217: imports.add(lineStruct.persistentClassPackage + "."
218: + persistentObjectName);
219: }
220: }
221: templateModel.put("persistentClassPackage",
222: persistentClassPackage);
223:
224: templateModel.put("imports", imports);
225: templateModel.put("tableNameConst",
226: PersistentObjectGenerator.javaConstName("TABLE_",
227: table.getTableAlias()));
228: templateModel.put("tableName", table.getTableName());
229: templateModel.put("tableAlias", table.getTableAlias());
230: templateModel.put("asize", "" + table.size());
231: templateModel.put("keySize", "" + table.keySize());
232:
233: List columns = new ArrayList(table.size());
234: templateModel.put("columns", columns);
235: for (int i = 0; i < table.size(); i++) {
236: MetaColumn metaColumn = table.getColumn(i);
237: String columnName = metaColumn.getColumnName();
238: logger.debug("Processing column [" + metaColumn + "]");
239: Map column = new LinkedHashMap();
240: column.put("javaName", PersistentObjectGenerator
241: .javaName(metaColumn.getColumnAlias(), null,
242: null, false));
243: column.put("javaType", javaType(metaColumn.getType()));
244: column.put("columnName", metaColumn.getColumnName());
245: column.put("columnNameConst", PersistentObjectGenerator
246: .javaConstName("COL_", metaColumn
247: .getColumnAlias()));
248: column.put("columnAlias", metaColumn.getColumnAlias());
249: column.put("columnIndexConst",
250: PersistentObjectGenerator.javaConstName(
251: "ICOL_", metaColumn.getColumnAlias()));
252: column.put("columnIndex", metaColumn.getColumnIndex()
253: + "");
254: column.put("type", metaColumn.getType().getName()
255: .toUpperCase());
256: column
257: .put("primaryKey", metaColumn.isPrimaryKey()
258: + "");
259: column.put("required", metaColumn.isRequired() + "");
260: column.put("autoGenerated", metaColumn
261: .isAutoGenerated()
262: + "");
263: column.put("isAutoIncrement", metaColumn
264: .isAutoIncrement()
265: + "");
266: column.put("columnSize", metaColumn.getColumnSize()
267: + "");
268: column.put("decimalDigits", metaColumn
269: .getDecimalDigits()
270: + "");
271:
272: ArrayList validators = new ArrayList();
273: ArrayList convertors = new ArrayList();
274:
275: if (!metaColumn.isAutoIncrement()
276: && !metaColumn.isAutoGenerated()
277: && metaColumn.isRequired()) {
278: Map validatorMap = new LinkedHashMap();
279: validatorMap.put("validatorComment", "");
280: getMaxNumber(metaColumn.getColumnSize(), metaColumn
281: .getDecimalDigits());
282: validatorMap.put("validator",
283: "RequiredFieldValidator()");
284: validatorMap.put("updateValidator",
285: "NotNullFieldValidator()");
286: validators.add(validatorMap);
287: }
288:
289: if (ColumnType.isNumeric(metaColumn.getType())) {
290: Map validatorMap = new LinkedHashMap();
291: validatorMap.put("validatorComment", "");
292: String maxNumber = getMaxNumber(metaColumn
293: .getColumnSize(), metaColumn
294: .getDecimalDigits());
295: String value = "NumberSizeFieldValidator(new BigDecimal(\"-"
296: + maxNumber
297: + "\"), new BigDecimal(\""
298: + maxNumber + "\"))";
299: if (StringUtil.isEmpty(maxNumber)) {
300: validatorMap.put("validatorComment", "//");
301: }
302: validatorMap.put("validator", value);
303: validators.add(validatorMap);
304: } else if (ColumnType.isString(metaColumn.getType())) {
305: Map validatorMap = new LinkedHashMap();
306: validatorMap.put("validatorComment", "");
307: validatorMap.put("validator",
308: "StringSizeFieldValidator(0, "
309: + metaColumn.getColumnSize() + ")");
310: validators.add(validatorMap);
311: Map convertorMap = addCommentedConvertor(
312: columnName, convertors,
313: "TrimWhiteSpaceFieldConvertor()");
314:
315: convertorMap = new LinkedHashMap();
316: convertorMap.put("convertor",
317: "UpperCaseFieldConvertor()");
318: convertorMap.put("convertorComment", "// ");
319: convertors.add(convertorMap);
320: }
321: column.put("validators", validators);
322: column.put("convertors", convertors);
323:
324: columns.add(column);
325: }
326:
327: logger.debug("outputDir = " + outputDir + "; table = "
328: + table.getTableAlias());
329:
330: String classFileName = className + ".java";
331: Writer writer = new FileWriter(new File(outputDir,
332: classFileName));
333: template.process(templateModel, writer);
334: writer.flush();
335: writer.close();
336: printGeneratedClassFileInfo(classFileName);
337:
338: }
339: }
340:
341: protected static void printGeneratedClassFileInfo(
342: String classFileName) {
343: CompositePoGenerator.printGeneratedClassFileInfo(classFileName);
344: }
345:
346: protected static void printGeneratedClassFileInfo(
347: String classFileName, String outputDir) {
348: CompositePoGenerator.printGeneratedClassFileInfo(classFileName,
349: outputDir);
350: }
351:
352: protected static void printGeneratedIn(String outputDir) {
353: CompositePoGenerator.printGeneratedIn(outputDir);
354: }
355:
356: private Map addCommentedConvertor(String columnName,
357: ArrayList convertors, String convertor) {
358: Map convertorMap = new LinkedHashMap();
359: convertorMap.put("convertorComment", "");
360: if (!namesToUncommectTrimRight.contains(columnName)) {
361: convertorMap.put("convertorComment", "// ");
362: }
363: convertorMap.put("convertor", convertor);
364: convertors.add(convertorMap);
365: return convertorMap;
366: }
367:
368: public static String javaType(ColumnType type) {
369: return (String) PersistentObjectGenerator.getType2JavaMap()
370: .get(type);
371: }
372:
373: //
374: //
375: // Util classes
376: //
377: //
378: static class LineStruct {
379: String inFilePath;
380: String exFilePath;
381: String outputPath;
382: String packageName;
383: String templatePath;
384: String filterPattern;
385: String classPrefix;
386: String classSuffix;
387: String persistentClassPackage;
388: String ctlPrefix;
389: String ctlSuffix;
390: }
391:
392: String getMaxNumber(int columnSize, int afterDecimalPoint) {
393: int beforeDecimal = columnSize - afterDecimalPoint;
394: char[] charsBefore = new char[beforeDecimal];
395: Arrays.fill(charsBefore, '9');
396: String after = "";
397: if (afterDecimalPoint > 0) {
398: char[] charsAfter = new char[afterDecimalPoint];
399: Arrays.fill(charsAfter, '9');
400: after = "." + new String(charsAfter);
401: }
402: return new String(charsBefore) + after;
403: }
404:
405: String fillString(int length) {
406: char[] chars = new char[length];
407: Arrays.fill(chars, '9');
408: return new String(chars);
409: }
410:
411: /**
412: * @param args
413: * @throws Exception
414: */
415: public static void main(String[] args) throws Exception {
416: if (args.length < 1) {
417: System.out
418: .println("ERROR: Generator must have one command line parameter - <persistent-object-config.properties> ");
419: System.exit(1);
420: }
421: System.out.println("STARTED GENERATION ...");
422:
423: LifeCycleControllerGenerator controllerGenerator = new LifeCycleControllerGenerator();
424: controllerGenerator.process(args[0]);
425:
426: System.out.println("FINISHED GENERATION");
427: }
428:
429: }
|