net.ymate.platform.persistence.jdbc.scaffold.JdbcScaffold.java Source code

Java tutorial

Introduction

Here is the source code for net.ymate.platform.persistence.jdbc.scaffold.JdbcScaffold.java

Source

/*
 * Copyright 2007-2107 the original author or authors.
 *
 * 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 net.ymate.platform.persistence.jdbc.scaffold;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.*;

import net.ymate.platform.base.YMP;
import net.ymate.platform.commons.lang.BlurObject;
import net.ymate.platform.commons.util.FileUtils;
import net.ymate.platform.commons.util.ResourceUtils;
import net.ymate.platform.commons.util.RuntimeUtils;
import net.ymate.platform.persistence.jdbc.IConnectionHolder;
import net.ymate.platform.persistence.jdbc.ISession;
import net.ymate.platform.persistence.jdbc.JDBC;
import net.ymate.platform.persistence.jdbc.operator.impl.ArrayResultSetHandler;
import net.ymate.platform.persistence.jdbc.support.JdbcEntityMeta;
import net.ymate.platform.persistence.jdbc.support.ResultSetHelper;

import org.apache.commons.lang.StringUtils;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
 * <p>
 * JdbcScaffold
 * </p>
 * <p>
 * ???????Java?
 * </p>
 * 
 * @author (suninformation@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">?</th><th width="100px"></th><th
 *          width="100px"></th><th width="100px"></th>
 *          </tr>
 *          <!--  Table ?? -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td></td>
 *          <td></td>
 *          <td>2013922?9:44:09</td>
 *          </tr>
 *          </table>
 */
public class JdbcScaffold {

    //   private static final Log _LOG = LogFactory.getLog(JdbcScaffold.class);

    private String TEMPLATE_ROOT_PATH = JdbcScaffold.class.getPackage().getName().replace(".", "/");
    private File TARGET_ROOT_PATH;
    private Configuration FREEMARKER_CONF;
    private Properties JDBC_SCAFFOLD_CONF = new Properties();
    private boolean __isUseClassSuffix;

    /**
     * 
     * 
     * @param outputPath 
     * @throws IOException
     */
    public JdbcScaffold(String outputPath) throws IOException {
        FREEMARKER_CONF = new Configuration();
        FREEMARKER_CONF.setClassForTemplateLoading(JdbcScaffold.class, "/");
        FREEMARKER_CONF.setObjectWrapper(new DefaultObjectWrapper());
        FREEMARKER_CONF.setDefaultEncoding("UTF-8");
        //
        JDBC_SCAFFOLD_CONF
                .load(ResourceUtils.getResourceAsStream("ymp-scaffold-conf.properties", JdbcScaffold.class));
        if (StringUtils.isNotBlank(outputPath)) {
            TARGET_ROOT_PATH = new File(outputPath);
        } else {
            TARGET_ROOT_PATH = new File(JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.output_path"));
        }
        if (TARGET_ROOT_PATH == null || !TARGET_ROOT_PATH.exists() || TARGET_ROOT_PATH.isFile()) {
            throw new Error("The target output path \"" + TARGET_ROOT_PATH.getPath()
                    + "\" is empty or is not a directory.");
        }
        //
        __isUseClassSuffix = new BlurObject(
                JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.use_class_suffix", "true")).toBooleanValue();
    }

    /**
     * ?
     * 
     * @param args
     */
    public static void main(String[] args) throws Exception {
        YMP.initialize();
        JdbcScaffold _scaffold = new JdbcScaffold((args == null || args.length == 0) ? null : args[0]);
        _scaffold.createEntityClassFiles();
        _scaffold.createRepositoryClassFiles();
    }

    /**
     * ??
     */
    public void createEntityClassFiles() {
        Map<String, Object> _propMap = buildPropMap();
        //
        boolean _isUseBaseModel = new BlurObject(
                JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.use_base_model", "false")).toBooleanValue();
        _propMap.put("isUseBaseModel", _isUseBaseModel);
        _propMap.put("isUseClassSuffix", __isUseClassSuffix);
        if (_isUseBaseModel) {
            buildTargetFile("/model/BaseModel.java", "/tmpl/base-model.ftl", _propMap);
        }
        //
        List<String> _tableList = Arrays
                .asList(StringUtils.split(JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.table_gen_list"), "|"));
        if (_tableList == null || _tableList.isEmpty()) {
            _tableList = getTableNames();
        }
        //
        String _dbName = JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.db_name");
        String _dbUser = JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.db_username");
        String[] _prefixs = StringUtils.split(JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.table_prefix"),
                '|');
        boolean _isRemovePrefix = new BlurObject(
                JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.remove_table_prefix")).toBooleanValue();
        List<String> _tableExcludeList = Arrays.asList(StringUtils.split(
                JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.table_exclude_list", "").toLowerCase(), "|"));
        for (String _tableName : _tableList) {
            // ???
            if (!_tableExcludeList.isEmpty() && _tableExcludeList.contains(_tableName.toLowerCase())) {
                continue;
            }
            TableMeta _tableMeta = getTableMeta(_dbName, _dbUser, _tableName);
            if (_tableMeta != null) {
                String _modelName = null;
                for (String _prefix : _prefixs) {
                    if (_tableName.startsWith(_prefix)) {
                        if (_isRemovePrefix) {
                            _tableName = _tableName.substring(_prefix.length());
                        }
                        _modelName = JdbcEntityMeta.buildFieldNameToClassAttribute(_tableName);
                        break;
                    }
                }
                if (StringUtils.isBlank(_modelName)) {
                    _modelName = JdbcEntityMeta.buildFieldNameToClassAttribute(_tableName);
                }
                //
                _propMap.put("tableName", _tableName);
                _propMap.put("modelName", _modelName);
                List<Attr> _fieldList = new ArrayList<Attr>(); // 
                List<Attr> _fieldListForNotNullable = new ArrayList<Attr>(); // ?
                List<Attr> _allFieldList = new ArrayList<Attr>(); // ????
                if (_tableMeta.getPkSet().size() > 1) {
                    _propMap.put("primaryKeyType", _modelName + "PK");
                    _propMap.put("primaryKeyName",
                            StringUtils.uncapitalize((String) _propMap.get("primaryKeyType")));
                    List<Attr> _primaryKeyList = new ArrayList<Attr>();
                    _propMap.put("primaryKeyList", _primaryKeyList);
                    Attr _pkAttr = new Attr((String) _propMap.get("primaryKeyType"),
                            (String) _propMap.get("primaryKeyName"), null, false, 0, null);
                    _fieldList.add(_pkAttr);
                    _fieldListForNotNullable.add(_pkAttr);
                    //
                    for (String pkey : _tableMeta.getPkSet()) {
                        ColumnInfo _ci = _tableMeta.getFieldMap().get(pkey);
                        _primaryKeyList.add(new Attr(_ci.getColumnType(),
                                StringUtils.uncapitalize(
                                        JdbcEntityMeta.buildFieldNameToClassAttribute(pkey.toLowerCase())),
                                pkey, _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue()));
                        _allFieldList.add(new Attr("String", _ci.getColumnName().toUpperCase(), _ci.getColumnName(),
                                false, 0, _ci.getDefaultValue()));
                    }
                    for (String key : _tableMeta.getFieldMap().keySet()) {
                        if (_tableMeta.getPkSet().contains(key)) {
                            continue;
                        }
                        ColumnInfo _ci = _tableMeta.getFieldMap().get(key);
                        Attr _attr = new Attr(_ci.getColumnType(),
                                StringUtils.uncapitalize(
                                        JdbcEntityMeta.buildFieldNameToClassAttribute(key.toLowerCase())),
                                key, _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue());
                        _fieldList.add(_attr);
                        _fieldListForNotNullable.add(_attr);
                        _allFieldList.add(new Attr("String", _ci.getColumnName().toUpperCase(), _ci.getColumnName(),
                                _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue()));
                    }
                } else {
                    _propMap.put("primaryKeyType",
                            _tableMeta.getFieldMap().get(_tableMeta.getPkSet().get(0)).getColumnType());
                    _propMap.put("primaryKeyName", StringUtils.uncapitalize(
                            JdbcEntityMeta.buildFieldNameToClassAttribute(_tableMeta.getPkSet().get(0))));
                    for (String key : _tableMeta.getFieldMap().keySet()) {
                        ColumnInfo _ci = _tableMeta.getFieldMap().get(key);
                        Attr _attr = new Attr(_ci.getColumnType(),
                                StringUtils.uncapitalize(
                                        JdbcEntityMeta.buildFieldNameToClassAttribute(key.toLowerCase())),
                                key, _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue());
                        _fieldList.add(_attr);
                        if (_attr.getNullable() == 0) {
                            _fieldListForNotNullable.add(_attr);
                        }
                        _allFieldList.add(new Attr("String", _ci.getColumnName().toUpperCase(), _ci.getColumnName(),
                                _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue()));
                    }
                }
                _propMap.put("fieldList", _fieldList);
                // ??????
                _propMap.put("notNullableFieldList",
                        _fieldList.size() == _fieldListForNotNullable.size() ? Collections.emptyList()
                                : _fieldListForNotNullable);
                _propMap.put("allFieldList", _allFieldList);
                //
                buildTargetFile("/model/" + _modelName + (__isUseClassSuffix ? "Model.java" : ".java"),
                        "/tmpl/model-entity.ftl", _propMap);
                //
                if (_tableMeta.getPkSet().size() > 1) {
                    _propMap.put("modelName", _modelName);
                    if (_tableMeta.getPkSet().size() > 1) {
                        List<Attr> _primaryKeyList = new ArrayList<Attr>();
                        _propMap.put("primaryKeyList", _primaryKeyList);
                        //
                        for (String pkey : _tableMeta.getPkSet()) {
                            ColumnInfo _ci = _tableMeta.getFieldMap().get(pkey);
                            _primaryKeyList.add(new Attr(_ci.getColumnType(),
                                    StringUtils.uncapitalize(
                                            JdbcEntityMeta.buildFieldNameToClassAttribute(pkey.toLowerCase())),
                                    pkey, _ci.isAutoIncrement(), _ci.getNullable(), _ci.getDefaultValue()));
                        }
                    }
                    buildTargetFile("/model/" + _modelName + "PK.java", "/tmpl/model-pk.ftl", _propMap);
                }
            }
        }
    }

    /**
     * ??????
     */
    public void createRepositoryClassFiles() {
        Map<String, Object> _propMap = buildPropMap();
        _propMap.put("isUseClassSuffix", __isUseClassSuffix);
        String[] _repositoryList = StringUtils
                .split(JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.repository_name_list"), "|");
        String _repositoryName = null;
        for (String _name : _repositoryList) {
            _repositoryName = JdbcEntityMeta.buildFieldNameToClassAttribute(_name);
            _propMap.put("repositoryName", _repositoryName);
            buildTargetFile("/repository/I" + _repositoryName + (__isUseClassSuffix ? "Repository.java" : ".java"),
                    "/tmpl/repository-interface.ftl", _propMap);
            //
            buildTargetFile(
                    "/repository/impl/" + _repositoryName + (__isUseClassSuffix ? "Repository.java" : ".java"),
                    "/tmpl/repository-impl.ftl", _propMap);
        }
    }

    private void buildTargetFile(String targetFileName, String tmplFile, Map<String, Object> propMap) {
        Writer _outWriter = null;
        try {
            File _outputFile = new File(TARGET_ROOT_PATH,
                    new File(((String) propMap.get("packageName")).replace('.', '/'), targetFileName).getPath());
            FileUtils.mkdirs(_outputFile.getParent(), true);
            Template _template = FREEMARKER_CONF.getTemplate(TEMPLATE_ROOT_PATH + tmplFile);
            _outWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_outputFile), StringUtils
                    .defaultIfEmpty(FREEMARKER_CONF.getOutputEncoding(), FREEMARKER_CONF.getDefaultEncoding())));
            _template.process(propMap, _outWriter);
            System.out.println("Output file \"" + _outputFile + "\".");
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {
            if (_outWriter != null) {
                try {
                    _outWriter.flush();
                    _outWriter.close();
                } catch (IOException e) {
                }
            }
        }
    }

    private Map<String, Object> buildPropMap() {
        Map<String, Object> _propMap = new HashMap<String, Object>();
        _propMap.put("packageName", JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jdbc.package", ""));
        _propMap.put("lastUpdateTime", new Date());
        return _propMap;
    }

    /**
     * @return ?????
     */
    private List<String> getTableNames() {
        List<String> _tableNames = new ArrayList<String>();
        ISession _session = null;
        try {
            _session = JDBC.openSession();
            String _dbType = JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jbdc.db_type", "unknow");
            String _sql = null;
            if ("mysql".equalsIgnoreCase(_dbType)) {
                _sql = "show tables";
            } else if ("oracle".equalsIgnoreCase(_dbType)) {
                _sql = "select t.table_name from user_tables t";
            } else if ("sqlserver".equalsIgnoreCase(_dbType)) {
                _sql = "select name from sysobjects where xtype='U'";
            } else {
                throw new Error("The current database \"" + _dbType + "\" type not supported");
            }
            ResultSetHelper _helper = ResultSetHelper
                    .bind(_session.findAll(_sql, new ArrayResultSetHandler(), null));
            for (int _idx = 0; _idx < _helper.getRowCount(); _idx++) {
                _helper.move(_idx);
                _tableNames.add(_helper.getAsString(0));
            }
        } catch (Throwable e) {
            if (e instanceof Error) {
                throw (Error) e;
            }
            throw new Error(RuntimeUtils.unwrapThrow(e));
        } finally {
            if (_session != null)
                _session.close();
        }
        return _tableNames;
    }

    /**
     * @param dbName ???
     * @param dbUserName ??
     * @param tableName ??
     * @return ?????
     */
    private TableMeta getTableMeta(String dbName, String dbUserName, String tableName) {
        IConnectionHolder _connHolder = null;
        Statement _statement = null;
        ResultSet _resultSet = null;
        Map<String, ColumnInfo> _tableFields = new LinkedHashMap<String, ColumnInfo>();
        List<String> _pkFields = new LinkedList<String>();
        TableMeta _meta = new TableMeta(_pkFields, _tableFields);
        try {
            _connHolder = JDBC.getConnectionHolder();
            String _dbType = JDBC_SCAFFOLD_CONF.getProperty("ymp.scaffold.jbdc.db_type", "unknow");
            DatabaseMetaData _dbMetaData = _connHolder.getConnection().getMetaData();
            _resultSet = _dbMetaData.getPrimaryKeys(dbName,
                    _dbType.equalsIgnoreCase("oracle") ? dbUserName.toUpperCase() : dbUserName, tableName);
            if (_resultSet == null) {
                _meta = null;
                System.err.println("Database table \"" + tableName + "\" primaryKey resultSet is null, ignored");
            } else {
                while (_resultSet.next()) {
                    _pkFields.add(_resultSet.getString(4).toLowerCase());
                }
                if (_pkFields.isEmpty()) {
                    _meta = null;
                    System.err
                            .println("Database table \"" + tableName + "\" does not set the primary key, ignored");
                } else {
                    _statement = _connHolder.getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                            ResultSet.CONCUR_UPDATABLE);
                    _resultSet = _statement
                            .executeQuery("select * from " + _connHolder.getDialect().wapperQuotedIdent(tableName));
                    ResultSetMetaData _rsMetaData = _resultSet.getMetaData();
                    //
                    for (int _idx = 1; _idx <= _rsMetaData.getColumnCount(); _idx++) {
                        // ??
                        ResultSet _column = _dbMetaData.getColumns(dbName,
                                _dbType.equalsIgnoreCase("oracle") ? dbUserName.toUpperCase() : dbUserName,
                                tableName, _rsMetaData.getColumnName(_idx));
                        if (_column.next()) {
                            // ????
                            _tableFields.put(_rsMetaData.getColumnName(_idx).toLowerCase(),
                                    new ColumnInfo(_rsMetaData.getColumnName(_idx).toLowerCase(),
                                            compressType(_rsMetaData.getColumnClassName(_idx)),
                                            _rsMetaData.isAutoIncrement(_idx), _rsMetaData.isNullable(_idx),
                                            _column.getString("COLUMN_DEF")));
                        }
                    }
                    //
                    System.err.println("TABLE_NAME: " + tableName + " ---------------->>");
                    System.err.println("COLUMN_NAME\tPK\tCOLUMN_TYPE\tIS_AUTOINCREMENT\tIS_NULLABLE\tCOLUMN_DEF");
                    for (ColumnInfo _cInfo : _tableFields.values()) {
                        System.err
                                .println(_cInfo.getColumnName() + "\t" + _pkFields.contains(_cInfo.getColumnName())
                                        + "\t" + _cInfo.getColumnType() + "\t" + _cInfo.isAutoIncrement() + "\t"
                                        + _cInfo.getNullable() + "\t" + _cInfo.getDefaultValue());
                    }
                }
            }
        } catch (Throwable e) {
            if (e instanceof Error) {
                throw (Error) e;
            }
            throw new Error(RuntimeUtils.unwrapThrow(e));
        } finally {
            _connHolder.release();
            _statement = null;
            _resultSet = null;
        }
        return _meta;
    }

    private String compressType(String javaType) {
        return javaType.substring(javaType.lastIndexOf(".") + 1);
    }

    /**
     * <p>
     * TableMeta
     * </p>
     * <p>
     * ????
     * </p>
     * 
     * @author (suninformation@163.com)
     * @version 0.0.0
     *          <table style="border:1px solid gray;">
     *          <tr>
     *          <th width="100px">?</th><th width="100px"></th><th
     *          width="100px"></th><th width="100px"></th>
     *          </tr>
     *          <!--  Table ?? -->
     *          <tr>
     *          <td>0.0.0</td>
     *          <td></td>
     *          <td></td>
     *          <td>2011-10-26?01:33:57</td>
     *          </tr>
     *          </table>
     */
    private class TableMeta {
        //      private String tableName;
        private List<String> pkSet;
        private Map<String, ColumnInfo> fieldMap;

        public TableMeta(/* String tableName, */List<String> pkSet, Map<String, ColumnInfo> fieldMap) {
            //         this.tableName = tableName;
            this.pkSet = pkSet;
            this.fieldMap = fieldMap;
        }

        //      public String getTableName() {
        //         return tableName;
        //      }

        public List<String> getPkSet() {
            return pkSet;
        }

        public Map<String, ColumnInfo> getFieldMap() {
            return fieldMap;
        }
    }

    /**
     * <p>
     * ColumnInfo
     * </p>
     * <p>
     * ?
     * </p>
     * 
     * @author (suninformation@163.com)
     * @version 0.0.0
     *          <table style="border:1px solid gray;">
     *          <tr>
     *          <th width="100px">?</th><th width="100px"></th><th
     *          width="100px"></th><th width="100px"></th>
     *          </tr>
     *          <!--  Table ?? -->
     *          <tr>
     *          <td>0.0.0</td>
     *          <td></td>
     *          <td></td>
     *          <td>2011-10-8?11:19:57</td>
     *          </tr>
     *          </table>
     */
    private class ColumnInfo {

        private String columnName;
        private String columnType;
        private boolean autoIncrement;
        private int nullable;
        private String defaultValue;

        /**
         * 
         * @param columnName
         * @param columnType
         * @param autoIncrement
           * @param nullable
           * @param defaultValue
         */
        public ColumnInfo(String columnName, String columnType, boolean autoIncrement, int nullable,
                String defaultValue) {
            this.columnName = columnName;
            this.autoIncrement = autoIncrement;
            this.columnType = columnType;
            this.nullable = nullable;
            this.defaultValue = defaultValue;
        }

        public String getColumnName() {
            return columnName;
        }

        public boolean isAutoIncrement() {
            return autoIncrement;
        }

        public String getColumnType() {
            return columnType;
        }

        public int getNullable() {
            return nullable;
        }

        public String getDefaultValue() {
            return defaultValue;
        }
    }

    public class Attr {
        String varType;
        String varName;
        String columnName;
        boolean autoIncrement;
        int nullable;
        String defaultValue;

        public Attr(String varType, String varName, String columnName, boolean autoIncrement, int nullable,
                String defaultValue) {
            this.varName = varName;
            this.varType = varType;
            this.columnName = columnName;
            this.autoIncrement = autoIncrement;
            this.nullable = nullable;
            this.defaultValue = defaultValue;
        }

        public String getVarType() {
            return varType;
        }

        public String getVarName() {
            return varName;
        }

        public String getColumnName() {
            return columnName;
        }

        public boolean isAutoIncrement() {
            return autoIncrement;
        }

        public int getNullable() {
            return nullable;
        }

        public String getDefaultValue() {
            return defaultValue;
        }

        @Override
        public String toString() {
            return this.getVarName();
        }

    }

}