All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.empire.db.codegen.CodeGenWriter Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.empire.db.codegen;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import org.apache.empire.db.DBDatabase;
import org.apache.empire.db.DBTable;
import org.apache.empire.db.DBView;
import org.apache.empire.db.codegen.util.FileUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.CommonsLogLogChute;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is the entry class for generating the java persistence model based on a
 * database schema. It uses the Empire DB open-source framework to build a java
 * persistence layer for an application. The Apache Velocity template engine is
 * used to create the output interfaces and classes.
 * 

* The Empire DB framework doesn't try to hide the underlying database and data * model but instead embraces its power by modeling it within java. The result * is a persistence layer that uses a more "object-oriented, type safe" SQL to * access persistent data. *

* NOTE: THIS VERSION HAS SEVERE RESTRICTIONS: *

    *
  1. Only tables are currently modeled (we'll add views to a later version).
  2. *
  3. Table indexes are not yet modeled (exception is primary key). Again, this * will be added to later editions.
  4. *
  5. It is assumed that each table has a single INTEGER auto-generated primary * key column that has the same name for all tables.
  6. *
  7. It is assumed that each table has a single TIMESTAMP optimistic locking * column that has the same name for all tables.
  8. *
*/ public class CodeGenWriter { private static final Logger log = LoggerFactory.getLogger(CodeGenWriter.class); // Templates public static final String DATABASE_TEMPLATE = "Database.vm"; public static final String BASE_TABLE_TEMPLATE = "BaseTable.vm"; public static final String TABLE_TEMPLATE = "Table.vm"; public static final String BASE_VIEW_TEMPLATE = "BaseView.vm"; public static final String VIEW_TEMPLATE = "View.vm"; public static final String BASE_RECORD_TEMPLATE = "BaseRecord.vm"; public static final String RECORD_TEMPLATE = "Record.vm"; // Services private final WriterService writerService; private final VelocityEngine engine; // Properties private final CodeGenConfig config; private File baseDir; private File tableDir; private File recordDir; private File viewDir; /** * Constructor * @param config the config object * @param writerService the writer service */ public CodeGenWriter(CodeGenConfig config, WriterService writerService) { this.writerService = writerService; this.config = config; this.engine = new VelocityEngine(); // we have to keep this in sync with our logging system // http://velocity.apache.org/engine/releases/velocity-1.5/developer-guide.html#simpleexampleofacustomlogger engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLogLogChute()); if(config.getTemplateFolder() == null){ engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); engine.setProperty("classpath." + RuntimeConstants.RESOURCE_LOADER + ".class", ClasspathResourceLoader.class.getName()); } else { File templateFolder = new File(config.getTemplateFolder()); if(!templateFolder.canRead()){ throw new RuntimeException("Provided template folder missing or not readable: " + config.getTemplateFolder()); } } // init engine try { engine.init(); } catch (Exception e) { log.error("A Exception occured on initializing the velocity-engine:", e); throw new RuntimeException(e); } } /** * Overload using standard WriterService * @param config the config object */ public CodeGenWriter(CodeGenConfig config) { this(config, new WriterService(config)); } /** * Generates the java code files for the database * * @param db the DBDatabase to generate files for * @return the generates files */ public List generateCodeFiles(DBDatabase db) { List generatedFiles = new ArrayList(); // Prepare directories for generated source files this.initDirectories(config); // Create the DB class generatedFiles.add(this.createDatabaseClass(db)); // Create base table class if (config.getTableBaseName().equals("DBTable")==false) { generatedFiles.add(this.createBaseTableClass(db)); } // Create base record class if (config.isGenerateRecords()) { generatedFiles.add(this.createBaseRecordClass(db)); } // Create base view class if (config.isGenerateViews() && config.getViewBaseName().equals("DBView")==false) { generatedFiles.add(this.createBaseViewClass(db)); } // Create table classes, record interfaces and record classes for (DBTable table : db.getTables()) { if (!config.isNestTables()) { // if table nesting is disabled, create separate table classes generatedFiles.add(this.createTableClass(db, table)); } if (config.isGenerateRecords()) { // generate record generatedFiles.add(this.createRecordClass(db, table)); } } // Create view classes for (DBView view : db.getViews()) { if (config.isGenerateViews() && !config.isNestViews()) { // if table nesting is disabled, create separate table classes generatedFiles.add(this.createViewClass(db, view)); } } return generatedFiles; } private void initDirectories(CodeGenConfig config) { // Create the directory structure for the generated source code. File targetDir = new File(config.getTargetFolder()); if (!targetDir.exists()) { targetDir.mkdirs(); } // Create the base package directory this.baseDir = FileUtils.getFileFromPackage(targetDir, config.getPackageName()); // Clean out the directory so old code is wiped out. FileUtils.cleanDirectory(this.baseDir); boolean createTables = (!config.isNestTables() || !config.getTableBaseName().equals("DBTable")); boolean createViews = config.isGenerateViews() && (!config.isNestViews() || !config.getViewBaseName().equals("DBView")); boolean craeteRecords = config.isGenerateRecords(); // createViews if (!createViews) config.setViewPackageName(config.getPackageName()); // Create the table package directory this.tableDir = (createTables ? FileUtils.getFileFromPackage(targetDir, config.getTablePackageName()) : null); // Create the record package directory this.recordDir = (craeteRecords ? FileUtils.getFileFromPackage(targetDir, config.getRecordPackageName()) : null); // Create the record package directory this.viewDir = (createViews ? FileUtils.getFileFromPackage(targetDir, config.getViewPackageName()) : null); } private File createDatabaseClass(DBDatabase db) { File file = new File(baseDir, config.getDbClassName() + ".java"); VelocityContext context = new VelocityContext(); // TODO fall back to getPackageName() is the other names are not set context.put("parser", writerService); context.put("tableClassSuffix", config.getTableClassSuffix()); context.put("basePackageName", config.getPackageName()); context.put("dbClassName", config.getDbClassName()); context.put("tablePackageName", config.getTablePackageName()); context.put("viewPackageName", config.getViewPackageName()); context.put("database", db); context.put("nestTables", config.isNestTables()); context.put("baseTableClassName", config.getTableBaseName()); context.put("nestViews", config.isNestViews()); context.put("templateFolder", config.getTemplateFolder()); context.put("baseViewClassName", config.getViewBaseName()); context.put("preserveRelationNames", config.isPreserveRelationNames()); writeFile(file, DATABASE_TEMPLATE, context); return file; } private File createBaseTableClass(DBDatabase db) { File file = new File(config.isNestTables() ? baseDir : tableDir, config.getTableBaseName() + ".java"); VelocityContext context = new VelocityContext(); context.put("basePackageName", config.getPackageName()); context.put("tablePackageName", config.getTablePackageName()); context.put("baseTableClassName", config.getTableBaseName()); context.put("dbClassName", config.getDbClassName()); writeFile(file, BASE_TABLE_TEMPLATE, context); return file; } private File createTableClass(DBDatabase db, DBTable table) { File file = new File(tableDir, writerService.getTableClassName(table.getName()) + ".java"); VelocityContext context = new VelocityContext(); context.put("parser", writerService); context.put("basePackageName", config.getPackageName()); context.put("tablePackageName", config.getTablePackageName()); context.put("baseTableClassName", config.getTableBaseName()); context.put("dbClassName", config.getDbClassName()); context.put("nestTables", config.isNestTables()); context.put("table", table); writeFile(file, TABLE_TEMPLATE, context); return file; } private File createBaseViewClass(DBDatabase db) { File file = new File(viewDir, config.getViewBaseName() + ".java"); VelocityContext context = new VelocityContext(); context.put("basePackageName", config.getPackageName()); context.put("viewPackageName", config.getViewPackageName()); context.put("baseViewClassName", config.getViewBaseName()); context.put("dbClassName", config.getDbClassName()); writeFile(file, BASE_VIEW_TEMPLATE, context); return file; } private File createViewClass(DBDatabase db, DBView view) { File file = new File(viewDir, writerService.getViewClassName(view.getName()) + ".java"); VelocityContext context = new VelocityContext(); context.put("parser", writerService); context.put("basePackageName", config.getPackageName()); context.put("viewPackageName", config.getViewPackageName()); context.put("baseViewClassName", config.getViewBaseName()); context.put("dbClassName", config.getDbClassName()); context.put("nestViews", config.isNestViews()); context.put("view", view); writeFile(file, VIEW_TEMPLATE, context); return file; } private File createBaseRecordClass(DBDatabase db) { File file = new File(recordDir, config.getRecordBaseName() + ".java"); VelocityContext context = new VelocityContext(); context.put("baseRecordClassName", config.getRecordBaseName()); context.put("basePackageName", config.getPackageName()); context.put("tablePackageName", config.getTablePackageName()); context.put("recordPackageName", config.getRecordPackageName()); context.put("contextClassName", config.getContextClassName()); context.put("baseTableClassName", config.getTableBaseName()); writeFile(file, BASE_RECORD_TEMPLATE, context); return file; } private File createRecordClass(DBDatabase db, DBTable table) { File file = new File(recordDir, writerService.getRecordClassName(table.getName()) + ".java"); VelocityContext context = new VelocityContext(); context.put("parser", writerService); context.put("basePackageName", config.getPackageName()); // If the tables shall be nested within the database classe, their include path for the records needs to be changed if (config.isNestTables()) context.put("tablePackageName", config.getPackageName() + "." + config.getDbClassName()); else context.put("tablePackageName", config.getTablePackageName()); context.put("recordPackageName", config.getRecordPackageName()); context.put("baseRecordClassName", config.getRecordBaseName()); context.put("contextClassName", config.getContextClassName()); context.put("dbClassName", config.getDbClassName()); context .put("createRecordProperties", config .isCreateRecordProperties()); context.put("table", table); writeFile(file, RECORD_TEMPLATE, context); return file; } private void writeFile(File file, String template, VelocityContext context) { String templatePath; if(config.getTemplateFolder() == null) { templatePath = template; } else { templatePath = config.getTemplateFolder()+ System.getProperty("file.separator") + template; } Writer writer = null; try { log.info("Writing " + file); Template velocityTemplate = engine.getTemplate(templatePath); writer = new FileWriter(file); velocityTemplate.merge(context, writer); } catch (IOException e) { log.error(e.getMessage(), e); } catch (ResourceNotFoundException e) { log.error(e.getMessage(), e); } catch (ParseErrorException e) { log.error(e.getMessage(), e); } catch (Exception e) { log.error(e.getMessage(), e); } finally { FileUtils.close(writer); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy