org.seasar.dbflute.task.bs.DfAbstractTexenTask.java Source code

Java tutorial

Introduction

Here is the source code for org.seasar.dbflute.task.bs.DfAbstractTexenTask.java

Source

/*
 * Copyright 2004-2007 the Seasar Foundation and the Others.
 *
 * Licensed 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.seasar.dbflute.task.bs;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.BuildException;
import org.apache.torque.engine.database.model.UnifiedSchema;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.texen.ant.TexenTask;
import org.seasar.dbflute.DBDef;
import org.seasar.dbflute.DfBuildProperties;
import org.seasar.dbflute.config.DfEnvironmentType;
import org.seasar.dbflute.friends.velocity.DfFlutistLog4JLogSystem;
import org.seasar.dbflute.friends.velocity.DfGenerator;
import org.seasar.dbflute.helper.jdbc.connection.DfConnectionMetaInfo;
import org.seasar.dbflute.helper.jdbc.connection.DfDataSourceHandler;
import org.seasar.dbflute.helper.jdbc.context.DfDataSourceContext;
import org.seasar.dbflute.logic.DfDBFluteTaskUtil;
import org.seasar.dbflute.logic.generate.refresh.DfRefreshResourceProcess;
import org.seasar.dbflute.logic.jdbc.connection.DfCurrentSchemaConnector;
import org.seasar.dbflute.logic.sql2entity.analyzer.DfOutsideSqlCollector;
import org.seasar.dbflute.logic.sql2entity.analyzer.DfOutsideSqlFile;
import org.seasar.dbflute.logic.sql2entity.analyzer.DfOutsideSqlPack;
import org.seasar.dbflute.properties.DfBasicProperties;
import org.seasar.dbflute.properties.DfDatabaseProperties;
import org.seasar.dbflute.properties.DfLittleAdjustmentProperties;
import org.seasar.dbflute.properties.DfRefreshProperties;
import org.seasar.dbflute.properties.DfReplaceSchemaProperties;
import org.seasar.dbflute.properties.facade.DfDatabaseTypeFacadeProp;
import org.seasar.dbflute.properties.facade.DfLanguageTypeFacadeProp;
import org.seasar.dbflute.resource.ResourceContext;
import org.seasar.dbflute.s2dao.valuetype.TnValueTypes;

/**
 * The abstract class of texen task.
 * @author jflute
 */
public abstract class DfAbstractTexenTask extends TexenTask {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    /** Log instance. */
    private static final Log _log = LogFactory.getLog(DfAbstractTexenTask.class);

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    /** DB driver. */
    protected String _driver;

    /** DB URL. */
    protected String _url;

    /** Main schema. */
    protected UnifiedSchema _mainSchema;

    /** User name. */
    protected String _userId;

    /** Password */
    protected String _password;

    /** Connection properties. */
    protected Properties _connectionProperties;

    /** The handler of data source. (NotNull) */
    protected final DfDataSourceHandler _dataSourceHandler = new DfDataSourceHandler();

    // ===================================================================================
    //                                                                                Main
    //                                                                                ====
    // -----------------------------------------------------
    //                                               Execute
    //                                               -------
    @Override
    public final void execute() { // completely override
        Throwable cause = null;
        long before = getTaskBeforeTimeMillis();
        try {
            begin();
            initializeDatabaseInfo();
            if (isUseDataSource()) {
                setupDataSource();
            }
            initializeVariousEnvironment();
            doExecute();
        } catch (Exception e) {
            cause = e;
            try {
                logException(e);
            } catch (Throwable ignored) {
                _log.warn("*Ignored exception occured!", ignored);
                _log.error("*Failed to execute DBFlute Task!", e);
            }
        } catch (Error e) {
            cause = e;
            try {
                logError(e);
            } catch (Throwable ignored) {
                _log.warn("*Ignored exception occured!", ignored);
                _log.error("*Failed to execute DBFlute Task!", e);
            }
        } finally {
            if (isUseDataSource()) {
                try {
                    commitDataSource();
                } catch (Exception ignored) {
                } finally {
                    try {
                        destroyDataSource();
                    } catch (Exception ignored) {
                        _log.warn("*Failed to destroy data source: " + ignored.getMessage());
                    }
                }
            }
            if (isValidTaskEndInformation() || cause != null) {
                try {
                    long after = getTaskAfterTimeMillis();
                    showFinalMessage(before, after, cause != null);
                } catch (RuntimeException e) {
                    _log.info("*Failed to show final message!", e);
                }
            }
            if (cause != null) {
                throwTaskFailure();
            }
        }
    }

    protected abstract void begin();

    protected long getTaskBeforeTimeMillis() {
        return System.currentTimeMillis();
    }

    protected long getTaskAfterTimeMillis() {
        return System.currentTimeMillis();
    }

    protected void logException(Exception e) {
        DfDBFluteTaskUtil.logException(e, getDisplayTaskName(), getConnectionMetaInfo());
    }

    protected void logError(Error e) {
        DfDBFluteTaskUtil.logError(e, getDisplayTaskName(), getConnectionMetaInfo());
    }

    protected boolean isValidTaskEndInformation() {
        return true;
    }

    // -----------------------------------------------------
    //                                         Final Message
    //                                         -------------
    protected void showFinalMessage(long before, long after, boolean abort) {
        final String environmentType = DfEnvironmentType.getInstance().getEnvironmentType();
        final StringBuilder sb = new StringBuilder();
        final String ln = ln();
        sb.append(ln).append("_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/");
        sb.append(ln).append("[Final Message]: ").append(getPerformanceView(after - before));
        if (abort) {
            sb.append(" *Abort");
        }
        sb.append(ln);

        final DfConnectionMetaInfo metaInfo = getConnectionMetaInfo();
        final String productDisp = metaInfo != null ? " (" + metaInfo.getProductDisp() + ")" : "";
        final String databaseType = getDatabaseTypeFacadeProp().getTargetDatabase() + productDisp;
        sb.append(ln).append("  DBFLUTE_CLIENT: {" + getBasicProperties().getProjectName() + "}");
        sb.append(ln).append("    database  = " + databaseType);
        sb.append(ln).append("    language  = " + getBasicProperties().getTargetLanguage());
        sb.append(ln).append("    container = " + getBasicProperties().getTargetContainerName());
        sb.append(ln).append("    package   = " + getBasicProperties().getPackageBase());
        sb.append(ln);
        sb.append(ln).append("  DBFLUTE_ENVIRONMENT_TYPE: {" + environmentType + "}");
        sb.append(ln).append("    driver = " + _driver);
        sb.append(ln).append("    url    = " + _url);
        sb.append(ln).append("    schema = " + _mainSchema);
        sb.append(ln).append("    user   = " + _userId);
        sb.append(ln).append("    props  = " + _connectionProperties);

        final String additionalSchemaDisp = buildAdditionalSchemaDisp();
        sb.append(ln).append("    additionalSchema = " + additionalSchemaDisp);
        final DfReplaceSchemaProperties replaceSchemaProp = getProperties().getReplaceSchemaProperties();
        sb.append(ln).append("    repsEnvType      = " + replaceSchemaProp.getRepsEnvType());
        final String refreshProjectDisp = buildRefreshProjectDisp();
        sb.append(ln).append("    refreshProject   = " + refreshProjectDisp);

        final String finalInformation = getFinalInformation();
        if (finalInformation != null) {
            sb.append(ln).append(ln);
            sb.append(finalInformation);
        }
        sb.append(ln).append("_/_/_/_/_/_/_/_/_/_/" + " {" + getDisplayTaskName() + "}");
        DfDBFluteTaskUtil.logFinalMessage(sb.toString());
    }

    protected String buildAdditionalSchemaDisp() {
        final DfDatabaseProperties databaseProp = getDatabaseProperties();
        final List<UnifiedSchema> additionalSchemaList = databaseProp.getAdditionalSchemaList();
        String disp;
        if (additionalSchemaList.size() == 1) {
            final UnifiedSchema unifiedSchema = additionalSchemaList.get(0);
            final String identifiedSchema = unifiedSchema.getIdentifiedSchema();
            disp = identifiedSchema;
            if (unifiedSchema.isCatalogAdditionalSchema()) {
                disp = disp + "(catalog)";
            } else if (unifiedSchema.isMainSchema()) { // should NOT be true
                disp = disp + "(main)";
            } else if (unifiedSchema.isUnknownSchema()) { // should NOT be true
                disp = disp + "(unknown)";
            }
        } else {
            final StringBuilder sb = new StringBuilder();
            for (UnifiedSchema unifiedSchema : additionalSchemaList) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                final String identifiedSchema = unifiedSchema.getIdentifiedSchema();
                sb.append(identifiedSchema);
                if (unifiedSchema.isCatalogAdditionalSchema()) {
                    sb.append("(catalog)");
                } else if (unifiedSchema.isMainSchema()) { // should NOT be true
                    sb.append("(main)");
                } else if (unifiedSchema.isUnknownSchema()) { // should NOT be true
                    sb.append("(unknown)");
                }
            }
            disp = sb.toString();
        }
        return disp;
    }

    protected String buildRefreshProjectDisp() {
        final DfRefreshProperties refreshProp = getProperties().getRefreshProperties();
        if (!refreshProp.hasRefreshDefinition()) {
            return "";
        }
        final List<String> refreshProjectList = refreshProp.getProjectNameList();
        final String disp;
        if (refreshProjectList.size() == 1) {
            disp = refreshProjectList.get(0);
        } else {
            final StringBuilder sb = new StringBuilder();
            for (String refreshProject : refreshProjectList) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(refreshProject);
            }
            disp = sb.toString();
        }
        return disp;
    }

    protected String getDisplayTaskName() {
        final String taskName = getTaskName();
        return DfDBFluteTaskUtil.getDisplayTaskName(taskName);
    }

    protected String getFinalInformation() {
        return null; // as default
    }

    protected void throwTaskFailure() {
        DfDBFluteTaskUtil.throwTaskFailure(getDisplayTaskName());
    }

    protected void initializeDatabaseInfo() {
        _driver = getDatabaseProperties().getDatabaseDriver();
        _url = getDatabaseProperties().getDatabaseUrl();
        _userId = getDatabaseProperties().getDatabaseUser();
        _mainSchema = getDatabaseProperties().getDatabaseSchema();
        _password = getDatabaseProperties().getDatabasePassword();
        _connectionProperties = getDatabaseProperties().getConnectionProperties();

        final ResourceContext context = new ResourceContext();
        context.setCurrentDBDef(getBasicProperties().getCurrentDBDef());
        ResourceContext.setResourceContextOnThread(context); // no need to clear because of one thread
    }

    protected void initializeVariousEnvironment() {
        if (getDatabaseTypeFacadeProp().isDatabaseOracle()) {
            // basically for data loading of ReplaceSchema
            final DBDef currentDBDef = ResourceContext.currentDBDef();
            TnValueTypes.registerBasicValueType(currentDBDef, java.util.Date.class,
                    TnValueTypes.UTILDATE_AS_TIMESTAMP);
        }
    }

    protected abstract void doExecute();

    /**
     * Get performance view.
     * @param mil The value of millisecond.
     * @return Performance view. (ex. 1m23s456ms) (NotNull)
     */
    protected String getPerformanceView(long mil) {
        if (mil < 0) {
            return String.valueOf(mil);
        }

        long sec = mil / 1000;
        long min = sec / 60;
        sec = sec % 60;
        mil = mil % 1000;

        StringBuffer sb = new StringBuffer();
        if (min >= 10) { // Minute
            sb.append(min).append("m");
        } else if (min < 10 && min >= 0) {
            sb.append("0").append(min).append("m");
        }
        if (sec >= 10) { // Second
            sb.append(sec).append("s");
        } else if (sec < 10 && sec >= 0) {
            sb.append("0").append(sec).append("s");
        }
        if (mil >= 100) { // Millisecond
            sb.append(mil).append("ms");
        } else if (mil < 100 && mil >= 10) {
            sb.append("0").append(mil).append("ms");
        } else if (mil < 10 && mil >= 0) {
            sb.append("00").append(mil).append("ms");
        }

        return sb.toString();
    }

    // -----------------------------------------------------
    //                                        Custom Execute
    //                                        --------------
    protected void fireVelocityProcess() {
        assertBasicAntParameter();

        // set up the encoding of templates from DBFlute property
        setInputEncoding(getBasicProperties().getTemplateFileEncoding());
        setOutputEncoding(getBasicProperties().getSourceFileEncoding());

        try {
            initializeVelocityInstance();
            final DfGenerator generator = setupGenerator();
            final Context ctx = setupControlContext();

            _log.info("generator.parse(\"" + controlTemplate + "\", c);");
            generator.parse(controlTemplate, ctx);
            generator.shutdown();
            cleanup();
        } catch (BuildException e) {
            throw e;
        } catch (MethodInvocationException e) {
            final String method = e.getReferenceName() + "." + e.getMethodName() + "()";
            String msg = "Exception thrown by " + method + ": control=" + controlTemplate;
            throw new IllegalStateException(msg, e.getWrappedThrowable());
        } catch (ParseErrorException e) {
            throw new IllegalStateException("Velocity syntax error: control=" + controlTemplate, e);
        } catch (ResourceNotFoundException e) {
            throw new IllegalStateException("Resource not found: control=" + controlTemplate, e);
        } catch (Exception e) {
            throw new IllegalStateException("Generation failed: control=" + controlTemplate, e);
        }
    }

    protected void assertBasicAntParameter() {
        if (templatePath == null && !useClasspath) {
            String msg = "The template path needs to be defined if you are not using the classpath for locating templates!";
            throw new IllegalStateException(msg);
        }
        if (controlTemplate == null) {
            throw new IllegalStateException("The control template needs to be defined!");
        }
        // *because of unused
        //if (outputDirectory == null) {
        //    throw new IllegalStateException("The output directory needs to be defined!");
        //}
        // *because of unused
        //if (outputFile == null) {
        //    throw new IllegalStateException("The output file needs to be defined!");
        //}
    }

    protected void initializeVelocityInstance() {
        // /---------------------------
        // Initialize Velocity instance 
        // ----------/
        if (templatePath != null) {
            log("Using templatePath: " + templatePath, 3);
            setupVelocityTemplateProperty();
        }
        if (useClasspath) {
            log("Using classpath");
            setupVelocityClasspathProperty();
        }
        setupVelocityLogProperty();
        try {
            Velocity.init();
        } catch (Exception e) {
            String msg = "Failed to initialize Velocity:";
            msg = msg + " templatePath=" + templatePath + " useClasspath=" + useClasspath;
            throw new IllegalStateException(msg, e);
        }
    }

    private void setupVelocityTemplateProperty() {
        Velocity.setProperty("file.resource.loader.path", templatePath);
    }

    private void setupVelocityClasspathProperty() {
        final String resourceLoaderName = "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
        Velocity.addProperty("resource.loader", "classpath");
        Velocity.setProperty("classpath.resource.loader.class", resourceLoaderName);
        Velocity.setProperty("classpath.resource.loader.cache", "false");
        Velocity.setProperty("classpath.resource.loader.modificationCheckInterval", "2");
    }

    private void setupVelocityLogProperty() {
        Velocity.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, DfFlutistLog4JLogSystem.class.getName());
    }

    private DfGenerator setupGenerator() {
        final DfGenerator generator = getGeneratorHandler();

        // *set up later using DBFlute property (dfprop)
        //generator.setOutputPath(outputDirectory);

        // actually from DBFlute property (dfprop)
        // because these variables could be set up before here
        generator.setInputEncoding(inputEncoding);
        generator.setOutputEncoding(outputEncoding);

        if (templatePath != null) {
            generator.setTemplatePath(templatePath);
        }
        return generator;
    }

    private Context setupControlContext() {
        final Context ctx;
        try {
            ctx = initControlContext();
        } catch (Exception e) {
            String msg = "Failed to initialize control context:";
            msg = msg + " templatePath=" + templatePath + " useClasspath=" + useClasspath;
            throw new IllegalStateException(msg, e);
        }
        try {
            populateInitialContext(ctx);
        } catch (Exception e) {
            String msg = "Failed to populate initial context:";
            msg = msg + " templatePath=" + templatePath + " useClasspath=" + useClasspath;
            throw new IllegalStateException(msg, e);
        }
        if (contextProperties != null) {
            for (Iterator<?> i = contextProperties.getKeys(); i.hasNext();) {
                String property = (String) i.next();
                String value = contextProperties.getString(property);
                try {
                    ctx.put(property, new Integer(value));
                } catch (NumberFormatException nfe) {
                    String booleanString = contextProperties.testBoolean(value);
                    if (booleanString != null) {
                        ctx.put(property, Boolean.valueOf(booleanString));
                    } else {
                        if (property.endsWith("file.contents")) {
                            final String canonicalPath;
                            try {
                                canonicalPath = getProject().resolveFile(value).getCanonicalPath();
                            } catch (IOException e) {
                                String msg = "Failed to get the canonical path:";
                                msg = msg + " property=" + property + " value=" + value;
                                throw new IllegalStateException(msg, e);
                            }
                            value = fileContentsToString(canonicalPath);
                            property = property.substring(0, property.indexOf("file.contents") - 1);
                        }
                        ctx.put(property, value);
                    }
                }
            }
        }
        return ctx;
    }

    // Copy from velocity.
    private static String fileContentsToString(String file) {
        String contents = "";
        File f = new File(file);
        if (f.exists()) {
            FileReader fr = null;
            try {
                fr = new FileReader(f);
                char template[] = new char[(int) f.length()];
                fr.read(template);
                contents = new String(template);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fr != null) {
                    try {
                        fr.close();
                    } catch (IOException ignored) {
                    }
                }
            }
        }
        return contents;
    }

    // -----------------------------------------------------
    //                                           Data Source
    //                                           -----------
    protected abstract boolean isUseDataSource();

    protected void setupDataSource() throws SQLException {
        _dataSourceHandler.setUser(_userId);
        _dataSourceHandler.setPassword(_password);
        _dataSourceHandler.setDriver(_driver);
        _dataSourceHandler.setUrl(_url);
        _dataSourceHandler.setConnectionProperties(_connectionProperties);
        _dataSourceHandler.setAutoCommit(true);
        _dataSourceHandler.create();
        connectSchema();
    }

    protected void commitDataSource() throws SQLException {
        _dataSourceHandler.commit();
    }

    protected void destroyDataSource() throws SQLException {
        _dataSourceHandler.destroy();

        if (getDatabaseTypeFacadeProp().isDatabaseDerby()) {
            // Derby(Embedded) needs an original shutdown for destroying a connection
            DfDBFluteTaskUtil.shutdownIfDerbyEmbedded(_driver);
        }
    }

    protected DataSource getDataSource() {
        return DfDataSourceContext.getDataSource();
    }

    protected void connectSchema() throws SQLException {
        final DfCurrentSchemaConnector connector = new DfCurrentSchemaConnector(_mainSchema,
                getDatabaseTypeFacadeProp());
        connector.connectSchema(getDataSource());
    }

    protected DfConnectionMetaInfo getConnectionMetaInfo() {
        return _dataSourceHandler.getConnectionMetaInfo();
    }

    // -----------------------------------------------------
    //                                    Context Properties
    //                                    ------------------
    @Override
    public void setContextProperties(String file) { // called by ANT (and completely override)
        try {
            // /- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            // Initialize torque properties as Properties and set up singleton class
            // that saves 'build.properties'.
            // - - - - - - - - - -/
            final Properties prop = DfDBFluteTaskUtil.getBuildProperties(file, getProject());
            DfBuildProperties.getInstance().setProperties(prop);

            // /- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            // Initialize context properties for Velocity.
            // - - - - - - - - - -/
            contextProperties = new ExtendedProperties();
            final Set<Entry<Object, Object>> entrySet = prop.entrySet();
            for (Entry<Object, Object> entry : entrySet) {
                contextProperties.setProperty((String) entry.getKey(), entry.getValue());
            }
        } catch (RuntimeException e) {
            String msg = "Failed to set context properties:";
            msg = msg + " file=" + file + " contextProperties=" + contextProperties;
            _log.warn(msg, e); // logging because it throws to ANT world
            throw e;
        }
    }

    // ===================================================================================
    //                                                                 SQL File Collecting
    //                                                                 ===================
    /**
     * Collect outside-SQL containing its file info as pack.
     * @return The pack object for outside-SQL files. (NotNull)
     */
    protected DfOutsideSqlPack collectOutsideSql() {
        final DfOutsideSqlCollector sqlFileCollector = new DfOutsideSqlCollector();
        return sqlFileCollector.collectOutsideSql();
    }

    // ===================================================================================
    //                                                                    Refresh Resource
    //                                                                    ================
    protected void refreshResources() {
        final List<String> projectNameList = getRefreshProperties().getProjectNameList();
        new DfRefreshResourceProcess(projectNameList).refreshResources();
    }

    // ===================================================================================
    //                                                                SQL File Information
    //                                                                ====================
    protected void showTargetSqlFileInformation(DfOutsideSqlPack outsideSqlPack) {
        final StringBuilder sb = new StringBuilder();
        sb.append(ln()).append("/- - - - - - - - - - - - - - - - - - - - - - - -");
        sb.append(ln()).append("Target SQL files: ").append(outsideSqlPack.size());
        sb.append(ln());
        for (DfOutsideSqlFile sqlFile : outsideSqlPack.getOutsideSqlFileList()) {
            sb.append(ln()).append("  ").append(sqlFile.getPhysicalFile().getName());
        }
        sb.append(ln()).append("- - - - - - - - - -/");
        _log.info(sb);
    }

    // ===================================================================================
    //                                                                    Skip Information
    //                                                                    ================
    protected void showSkippedFileInformation() {
        final StringBuilder sb = new StringBuilder();
        sb.append(ln()).append("/- - - - - - - - - - - - - - - - - - - - - - - -");
        final boolean skipGenerateIfSameFile = getLittleAdjustmentProperties().isSkipGenerateIfSameFile();
        if (!skipGenerateIfSameFile) {
            sb.append(ln()).append("All class files have been generated. (overrided)");
            sb.append(ln()).append("- - - - - - - - - -/");
            _log.info(sb);
            return;
        }
        final List<String> parseFileNameList = DfGenerator.getInstance().getParseFileNameList();
        final int parseSize = parseFileNameList.size();
        if (parseSize == 0) {
            sb.append(ln()).append("No class file has been parsed.");
            sb.append(ln()).append("- - - - - - - - - -/");
            return;
        }
        final List<String> skipFileNameList = DfGenerator.getInstance().getSkipFileNameList();
        final int skipSize = skipFileNameList.size();
        if (skipSize == 0) {
            sb.append(ln()).append("All class files have been generated. (overrided)");
            sb.append(ln()).append("- - - - - - - - - -/");
            return;
        }
        if (skipSize == parseSize) {
            sb.append(ln()).append("All class files have been skipped generating");
            sb.append(ln()).append("                because they have no change.");
        } else {
            sb.append(ln()).append("Several class files have been skipped generating");
            sb.append(ln()).append("                    because they have no change.");
        }
        sb.append(ln());
        sb.append(ln()).append("    -> ").append(skipSize).append(" skipped (in ").append(parseSize)
                .append(" files)");
        sb.append(ln()).append("- - - - - - - - - -/");
    }

    // ===================================================================================
    //                                                                          Properties
    //                                                                          ==========
    protected DfBuildProperties getProperties() {
        return DfBuildProperties.getInstance();
    }

    protected DfBasicProperties getBasicProperties() {
        return getProperties().getBasicProperties();
    }

    protected DfDatabaseTypeFacadeProp getDatabaseTypeFacadeProp() {
        return getBasicProperties().getDatabaseTypeFacadeProp();
    }

    protected DfLanguageTypeFacadeProp getLanguageTypeFacadeProp() {
        return getBasicProperties().getLanguageTypeFacadeProp();
    }

    protected DfDatabaseProperties getDatabaseProperties() {
        return getProperties().getDatabaseProperties();
    }

    protected DfLittleAdjustmentProperties getLittleAdjustmentProperties() {
        return getProperties().getLittleAdjustmentProperties();
    }

    protected DfRefreshProperties getRefreshProperties() {
        return getProperties().getRefreshProperties();
    }

    // ===================================================================================
    //                                                                       Assist Helper
    //                                                                       =============
    public DfGenerator getGeneratorHandler() {
        return DfGenerator.getInstance();
    }

    // ===================================================================================
    //                                                                      General Helper
    //                                                                      ==============
    protected String ln() {
        return "\n";
    }

    // ===================================================================================
    //                                                                            Accessor
    //                                                                            ========
    public void setEnvironmentType(String environmentType) {
        DfEnvironmentType.getInstance().setEnvironmentType(environmentType);
    }
}