Java tutorial
/* * Apache License, Version 2.0??????? * ????????????? * * ??http://www.apache.org/licenses/LICENSE-2.0????? * * ??????????????? * ???????? * ?????????????????????? * * ???????????????????????? */ package jp.co.golorp.emarf.model; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigInteger; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.dbutils.BasicRowProcessor; import org.apache.commons.dbutils.BeanProcessor; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.RowProcessor; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jp.co.golorp.emarf.constants.AppKey; import jp.co.golorp.emarf.constants.MessageKeys; import jp.co.golorp.emarf.constants.model.ModelFieldTypes; import jp.co.golorp.emarf.exception.ApplicationError; import jp.co.golorp.emarf.exception.SystemError; import jp.co.golorp.emarf.generator.BeanGenerator; import jp.co.golorp.emarf.properties.App; import jp.co.golorp.emarf.properties.collection.AppSet; import jp.co.golorp.emarf.sql.Connections; import jp.co.golorp.emarf.sql.MetaData; import jp.co.golorp.emarf.sql.info.ColumnInfo; import jp.co.golorp.emarf.sql.info.TableInfo; import jp.co.golorp.emarf.sql.relation.RelateColumnMap; import jp.co.golorp.emarf.util.DateUtil; import jp.co.golorp.emarf.util.IOUtil; import jp.co.golorp.emarf.util.LogUtil; import jp.co.golorp.emarf.util.ModelUtil; import jp.co.golorp.emarf.util.StringUtil; /** * IO * * @author oukuf@golorp */ public final class Models { /** LOG */ private static final Logger LOG = LoggerFactory.getLogger(Models.class); /** ?? */ private static final String ROW_MAX = App.get(AppKey.MODELS_ROW_MAX); /** ? */ public static final String ID_SUFFIX = App.get(AppKey.MODELS_ID_SUFFIX); /** ??Set */ public static final String SEQ_SUFFIX = App.get(AppKey.MODELS_SEQ_SUFFIX); /** */ private static final String ORACLE_SEQUENCE_PREFIX = App.get(AppKey.MODELS_ORACLE_SEQUENCE_PREFIX); /** */ private static final String ORACLE_SEQUENCE_SUFFIX = App.get(AppKey.MODELS_ORACLE_SEQUENCE_SUFFIX); /** ??? */ public static final AppSet<String> AINT_INSERT_SET = App.getSet(AppKey.MODELS_AINT_INSERTS); /** ??? */ public static final AppSet<String> AINT_UPDATE_SET = App.getSet(AppKey.MODELS_AINT_UPDATES); /** */ public static final Map<String, String> AUTO_INSERT_MAP = App.getMap(AppKey.MODELS_AUTO_INSERT_VALUES); /** */ public static final Map<String, String> AUTO_UPDATE_MAP = App.getMap(AppKey.MODELS_AUTO_UPDATE_VALUES); /** */ private static PagingBy pagingBy = null; /** * ?? * * @author oukuf@golorp */ public enum PagingBy { /** limit?mysql?? */ limit, /** rownum?oracle?? */ rownum } /** * */ private Models() { } /** * insert * * @param model * ? * @return ?? */ public static Model create(final Model model) { // ?? String modelName = model.getClass().getSimpleName(); // TableInfo tableInfo = MetaData.getTableInfo(modelName); if (tableInfo == null) { throw new SystemError(MessageKeys.ABEND_DATA_INSERT, modelName); } // ?? String tableName = tableInfo.getTableName(); // Set<String> primaryKeys = tableInfo.getPrimaryKeys(); // OracleSequence????? if (primaryKeys.size() == 1) { fillByOracleSequence(model, tableName, primaryKeys.iterator().next()); } // ?? Set<String> primaryPropertyNames = ModelUtil.getPrimaryPropertyNames(modelName); if (primaryPropertyNames != null) { // ??? Iterator<String> iPrimaryPropertyNames = primaryPropertyNames.iterator(); String primaryPropertyName = iPrimaryPropertyNames.next(); Object o = model.get(primaryPropertyName); if (o != null) { // ??????? boolean isExistAllKey = true; // criteria??? Criteria c = Criteria.equal(modelName, primaryPropertyName, o); // criteria???? while (iPrimaryPropertyNames.hasNext()) { primaryPropertyName = iPrimaryPropertyNames.next(); o = model.get(primaryPropertyName); if (o == null) { isExistAllKey = false; break; } c.eq(primaryPropertyName, o); } // ?????????????? if (isExistAllKey && Models.getModel(modelName, c) != null) { throw new ApplicationError(MessageKeys.ERRORS_DATA_DUPLICATE); } } } /* * ? */ Statement statement = Models.getStatement(ModelFieldTypes.GET_INSERT_STATEMENT, model); if (Models.regist(statement.getSql(), statement.getParams()) != 1) { throw new SystemError(MessageKeys.ABEND_DATA_INSERT, tableInfo.getTableMei()); } /* * ??? */ // ???? for (String primaryPropertyName : primaryPropertyNames) { // ???? if (model.get(primaryPropertyName) != null) { continue; } // ???? ColumnInfo primaryKeyInfo = tableInfo.getColumnInfo(primaryPropertyName); String primaryKeyName = primaryKeyInfo.getColumnName(); if (primaryPropertyName.endsWith(Models.ID_SUFFIX)) { // AUTO_INCREMENT?ID? String sql = "select last_insert_id() as " + primaryKeyName + " from " + tableName; List<Map<String, Object>> datas = Models.getDatas(sql); if (datas == null) { continue; } Map<String, Object> data = datas.get(0); BigInteger value = (BigInteger) data.get(primaryPropertyName); if (value.intValue() >= 0) { model.set(primaryPropertyName, value.intValue()); } } else if (primaryPropertyName.endsWith(Models.SEQ_SUFFIX)) { // ?? StringBuilder sb = new StringBuilder(); List<Object> params = new ArrayList<Object>(); // ????????????? Set<String> primaryPropertyNames2 = ModelUtil.getPrimaryPropertyNames(modelName); for (String primaryPropertyName2 : primaryPropertyNames2) { // ??? if (primaryPropertyName2.equals(primaryPropertyName)) { break; } // ????where?? if (sb.length() > 0) { sb.append(" and"); } ColumnInfo primaryKeyInfo2 = tableInfo.getColumnInfo(primaryPropertyName2); String columnName2 = primaryKeyInfo2.getColumnName(); Object columnValue2 = model.get(primaryPropertyName2); sb.append(" ").append(columnName2).append(" = ?"); params.add(columnValue2); } // ? String sql = "SELECT MAX(" + primaryKeyName + ") AS " + primaryKeyName + " from " + tableName + " WHERE " + sb.toString(); List<Map<String, Object>> datas = Models.getDatas(sql, params.toArray()); if (datas == null) { continue; } // ??????????????????????0? Map<String, Object> data = datas.get(0); Object value = data.get(primaryPropertyName); if (value != null) { model.set(primaryPropertyName, value); } else { model.set(primaryPropertyName, 0); } } } return Models.refer(model); } /** * * * @param model * ? * @return ?? */ public static Model refer(final Model model) { String modelName = model.getClass().getSimpleName(); Statement statement = Models.getStatement(ModelFieldTypes.GET_SELECT_STATEMENT, model); return Models.getBean(modelName, statement.getSql(), statement.getParams()); } /** * update * * @param model * ? */ public static void update(final Model model) { Statement statement = Models.getStatement(ModelFieldTypes.GET_UPDATE_STATEMENT, model); if (Models.regist(statement.getSql(), statement.getParams()) != 1) { String modelName = model.getClass().getSimpleName(); String tableMei = MetaData.getTableInfo(modelName).getTableMei(); throw new SystemError(MessageKeys.ABEND_DATA_UPDATE, tableMei); } } /** * delete * * @param model * ? */ public static void delete(final Model model) { Statement statement = Models.getStatement(ModelFieldTypes.GET_DELETE_STATEMENT, model); if (Models.regist(statement.getSql(), statement.getParams()) != 1) { String modelName = model.getClass().getSimpleName(); String tableMei = MetaData.getTableInfo(modelName).getTableMei(); throw new SystemError(MessageKeys.ABEND_DATA_DELETE, tableMei); } } /** * @param modelName * truncate??? */ public static void truncate(final String modelName) { TableInfo tableInfo = MetaData.getTableInfo(modelName); if (tableInfo == null) { throw new SystemError(MessageKeys.ABEND_DATA_DELETE, modelName); } String tableName = tableInfo.getTableName(); try { Models.regist("TRUNCATE TABLE " + tableName); } catch (Exception e) { // truncate?????sqlite?? Models.regist("DELETE FROM " + tableName); } } /** * ? * * @param modelName * ?? * @param c * ? * @return */ public static int count(final String modelName, final Criteria c) { // TODO ?????????? // if (c == null) { // return 0; // } Statement where = getWhere(modelName, c); String selectSQL = "SELECT COUNT(*) CNT FROM " + where.getSql(); Object[] params = where.getParams(); List<Map<String, Object>> datas = getDatas(selectSQL, params); Map<String, Object> data = datas.get(0); return Integer.parseInt(data.get("cnt").toString()); } /** * criteria??select * * @param modelName * ?? * @param c * ? * @return */ public static Model getModel(final String modelName, final Criteria c) { List<Model> models = getModels(modelName, c, null, null); if (models == null || models.size() == 0) { return null; } if (models.size() > 1) { throw new SystemError(MessageKeys.ERRORS_DATA_PLURAL); } return (Model) models.get(0); } /** * criteria?select * * @param modelName * ?? * @param c * ? * @return ? */ public static List<Model> getModels(final String modelName, final Criteria c) { return getModels(modelName, c, null, null); } /** * criteria?select * * @param modelName * ?? * @param c * Criteria * @param rows * ? * @param page * ?? * @return ? */ public static List<Model> getModels(final String modelName, final Criteria c, final String rows, final String page) { // ????? String rowsValue = ROW_MAX; if (rows != null) { rowsValue = rows; } // ????? String pageValue = "1"; if (page != null) { pageValue = page; } // where????? Statement where = getWhere(modelName, c); if (where == null) { return null; } String sql = "SELECT * FROM " + where.getSql(); int r = Integer.valueOf(rowsValue); int p = Integer.valueOf(pageValue); int offset = r * (p - 1); if (pagingBy == null || pagingBy == PagingBy.limit) { try { sql += " limit " + offset + ", " + rowsValue; List<Model> beans = getBeans(modelName, sql, where.getParams()); pagingBy = PagingBy.limit; return beans; } catch (Exception e) { } } if (pagingBy == null || pagingBy == PagingBy.rownum) { try { int f = offset + 1; int t = offset + r; sql = "SELECT * FROM (SELECT ROWNUM AS RNO, A.* FROM (" + sql + ") A) WHERE RNO BETWEEN " + f + " AND " + t; List<Model> beans = getBeans(modelName, sql, where.getParams()); pagingBy = PagingBy.rownum; return beans; } catch (Exception e) { } } return null; } /** * ??oracle?? * * @param model * Model * @param tableName * ??? * @param columnName * ????? */ private static void fillByOracleSequence(final Model model, final String tableName, final String columnName) { StringBuilder sb = new StringBuilder("SELECT "); if (ORACLE_SEQUENCE_PREFIX != null) { sb.append(ORACLE_SEQUENCE_PREFIX); } sb.append(tableName).append("_").append(columnName); if (ORACLE_SEQUENCE_SUFFIX != null) { sb.append(ORACLE_SEQUENCE_SUFFIX); } sb.append(".NEXTVAL AS ").append(columnName).append(" FROM DUAL"); try { List<Map<String, Object>> datas = Models.getDatas(sb.toString()); Map<String, Object> data = datas.get(0); String propertyName = StringUtil.toCamelCase(columnName); Object value = data.get(propertyName); if (value != null) { model.set(propertyName, value); } } catch (Exception e) { LOG.trace(tableName + "." + columnName + " is not use Oracle Sequence."); } } /** * ?????????? * * @param <T> * * @param bean * ??bean */ private static <T> void cp2org(final T bean) { Class<?> clazz = bean.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.getName().startsWith(BeanGenerator.ORG_PREFIX)) { try { String orgName = field.getName(); String propertyName = orgName.replaceFirst(BeanGenerator.ORG_PREFIX, ""); Field property = clazz.getDeclaredField(propertyName); field.setAccessible(true); property.setAccessible(true); Object value = property.get(bean); field.set(bean, value); } catch (Exception e) { throw new SystemError(e); } } } } /** * ??? * * @param sql * ?sql * @param params * sql? * @return ? */ private static int regist(final String sql, final Object... params) { Date sysDate = DateUtil.getDate(); for (int i = 0; i < params.length; i++) { Object param = params[i]; if (StringUtil.isNotBlank(param) && param.toString().equals("@{sysDate}")) { params[i] = new Timestamp(sysDate.getTime()); } } statementLog(getRawSql(sql, params)); QueryRunner runner = new QueryRunner(); Connection cn = Connections.get(); try { return runner.update(cn, sql, params); } catch (SQLException e) { throw new SystemError(e); } } /** * crud? * * @param kind * ????? * @param model * ?? * @return sql??set */ private static Statement getStatement(final ModelFieldTypes kind, final Model model) { Class<?> clazz = model.getClass(); Method method = null; try { method = clazz.getMethod(kind.toString(), clazz); } catch (NoSuchMethodException | SecurityException e) { throw new SystemError(e); } Object o = null; try { o = method.invoke(clazz, model); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new SystemError(e); } return (Statement) o; } /** * criteria???join???sql? * * @param modelName * ?? * @param c * ? * @return sql??set */ private static Statement getWhere(final String modelName, final Criteria c) { Criteria criteria = c; if (StringUtil.isNotBlank(BeanGenerator.DELETE_F)) { String deleteF = StringUtil.toCamelCase(BeanGenerator.DELETE_F); if (MetaData.getColumnInfo(modelName, deleteF) != null) { Criteria cDeleteF = Criteria.notEqual(modelName, deleteF, "1").or().eq(deleteF, null); if (criteria == null) { criteria = cDeleteF; } else { criteria.and(cDeleteF); } } if (criteria != null) { for (String modelName2 : criteria.getModels()) { if (!modelName.equals(modelName2)) { if (MetaData.getColumnInfo(modelName2, deleteF) != null) { Criteria cDeleteF = Criteria.notEqual(modelName2, deleteF, "1").or().eq(deleteF, null); if (criteria == null) { criteria = cDeleteF; } else { criteria.and(cDeleteF); } } } } } } StringBuilder sql = new StringBuilder(); TableInfo tableInfo = MetaData.getTableInfo(modelName); if (tableInfo == null) { return null; } String tableName = tableInfo.getTableName(); sql.append(tableName); // ?? if (criteria != null) { for (String modelName2 : criteria.getModels()) { if (modelName.equals(modelName2)) { continue; } TableInfo tableInfo2 = MetaData.getTableInfo(modelName2); String tableName2 = tableInfo2.getTableName(); sql.append(" INNER JOIN ").append(tableName2); List<RelateColumnMap> relateColumnsList = ModelUtil.getRelateProperties(modelName, modelName2); if (relateColumnsList != null) { sql.append(" ON "); StringBuilder sql2 = new StringBuilder(); for (RelateColumnMap relateColumns : relateColumnsList) { for (Entry<String, String> relateColumn : relateColumns.entrySet()) { String propertyName = relateColumn.getKey(); String propertyName2 = relateColumn.getValue(); ColumnInfo columnInfo = tableInfo.getColumnInfo(propertyName); ColumnInfo columnInfo2 = tableInfo2.getColumnInfo(propertyName2); String columnName = columnInfo.getColumnName(); String columnName2 = columnInfo2.getColumnName(); if (sql2.length() > 0) { sql2.append(" AND "); } sql2.append(tableName).append(".").append(columnName).append(" = ").append(tableName2) .append(".").append(columnName2); } } sql.append(sql2); } } } List<Object> params = new ArrayList<Object>(); if (criteria != null) { if (criteria.is()) { sql.append(" WHERE "); params.addAll(criteria.toParameter()); } sql.append(criteria); } return new Statement(sql.toString(), params.toArray(new Object[params.size()])); } /** * Model?????IO * * @param sql * sql * @param params * params * @return List */ private static List<Map<String, Object>> getDatas(final String sql, final Object... params) { // ?SQL? String rawSql = getRawSql(sql, params); // SQL?????? List<Map<String, Object>> datas = ModelsCache.get(rawSql); if (datas != null) { return datas; } // statementLog(rawSql); // ? PreparedStatement ps = null; try { ps = Connections.get().prepareStatement(sql); for (int i = 0; i < params.length; i++) { ps.setString(i + 1, String.valueOf(params[i])); } // ?? datas = new ArrayList<Map<String, Object>>(); ResultSet rs = null; try { // ??? rs = ps.executeQuery(); while (rs.next()) { // ? Map<String, Object> data = new LinkedHashMap<String, Object>(); // ResultSet?META? ResultSetMetaData meta = rs.getMetaData(); // META???? int columnCount = meta.getColumnCount(); for (int i = 1; i <= columnCount; i++) { // ??? String columnName = meta.getColumnName(i); // ??? String propertyName = StringUtil.toCamelCase(columnName); String key = propertyName; if (data.containsKey(propertyName)) { String modelName = StringUtil.toUpperCamelCase(meta.getTableName(i)); key = modelName + "." + propertyName; } // data.put(key, rs.getObject(columnName)); } // datas.add(data); } } catch (SQLException e) { throw new SystemError(e); } finally { IOUtil.closeQuietly(rs); } } catch (SQLException e) { throw new SystemError(e); } finally { IOUtil.closeQuietly(ps); } // SQL? // ModelsCache.set(rawSql, datas); return datas; } /** * ???IO * * @param <T> * ?? * @param modelName * ?? * @param sql * ?sql * @param params * sql * @return ??? */ private static <T> List<T> getBeans(final String modelName, final String sql, final Object... params) { Class<?> type = ModelUtil.getBlankModel(modelName).getClass(); RowProcessor rp = getRowProcessor(modelName); @SuppressWarnings({ "rawtypes", "unchecked" }) ResultSetHandler rsh = new BeanListHandler(type, rp); List<T> list = query(sql, rsh, params); for (T bean : list) { cp2org(bean); } return list; } /** * ???IO * * @param <T> * ?? * @param modelName * ?? * @param sql * ?sql * @param params * sql * @return ?? */ private static <T> T getBean(final String modelName, final String sql, final Object... params) { Class<?> type = ModelUtil.getBlankModel(modelName).getClass(); RowProcessor rp = getRowProcessor(modelName); @SuppressWarnings({ "rawtypes", "unchecked" }) ResultSetHandler rsh = new BeanHandler(type, rp); T bean = query(sql, rsh, params); if (bean != null) { cp2org(bean); } return bean; } /** * * * @param rawSql * ?sql */ private static void statementLog(final String rawSql) { LOG.info("<query> " + rawSql); LogUtil.callerLog(); } /** * ?????sql?? * * @param sql * sql * @param params * * @return ???sql */ private static String getRawSql(final String sql, final Object... params) { String query = sql; for (Object param : params) { query = query.replaceFirst("\\?", "'" + String.valueOf(param).replaceAll("\\\\", "\\\\\\\\") + "'"); } return query; } /** * dbutils? * * @param modelName * ?? * @return RowProcessor */ private static RowProcessor getRowProcessor(final String modelName) { Map<String, String> mapping = new LinkedHashMap<String, String>(); Map<String, String> propertyMeis = ModelUtil.getPropertyMeis(modelName); TableInfo tableInfo = MetaData.getTableInfo(modelName); for (String propertyName : propertyMeis.keySet()) { ColumnInfo columnInfo = tableInfo.getColumnInfo(propertyName); String columnName = columnInfo.getColumnName(); mapping.put(columnName, propertyName); } BeanProcessor convert = new BeanProcessor(mapping); return new BasicRowProcessor(convert); } /** * IO * * @param <T> * ?? * @param sql * sql * @param rsh * ResultSetHandler * @param params * * @return ???? */ @SuppressWarnings("unchecked") private static <T> T query(final String sql, final ResultSetHandler<?> rsh, final Object... params) { String rawSql = getRawSql(sql, params); T result = (T) ModelsCache.get(rawSql); if (result != null) { return result; } statementLog(rawSql); QueryRunner runner = new QueryRunner(); Connection cn = Connections.get(); try { if (params == null || params.length == 0) { result = (T) runner.query(cn, sql, rsh); } else { result = (T) runner.query(cn, sql, rsh, params); } ModelsCache.set(rawSql, result); return result; } catch (Exception e) { throw new SystemError(e); } } }