package com.jqmobile.core.server.db.orm;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import com.jqmobile.core.orm.DBColumn;
import com.jqmobile.core.orm.ORM;
import com.jqmobile.core.orm.TableUtil;
import com.jqmobile.core.orm.exception.ORMException;
import com.jqmobile.core.orm.exception.ORMNotDBTableException;
import com.jqmobile.core.utils.plain.BeanUtils;
import com.jqmobile.core.utils.plain.GUIDUtils;
import com.jqmobile.core.utils.plain.Log;
class BaseTableUtil implements TableUtil {
private Connection connection;
private Object lock = new Object();
private BaseTableUtil() {
}
private Connection getConnection() {
return connection;
}
private void setConnection(Connection connection) {
try {
L10010: if (null == this.connection || this.connection.isClosed()) {
this.connection = connection;
} else {
synchronized (lock) {
try {
lock.wait(1000);
} catch (InterruptedException e) {
}
}
break L10010;
}
} catch (SQLException e) {
Log.getLog(getClass()).e(e);
}
this.connection = connection;
}
public static TableUtil getInstance(Connection conn) {
BaseTableUtil util = new BaseTableUtil();
util.setConnection(conn);
return util;
}
@Override
public void createTable(Class<?> c) throws ORMException {
PreparedStatement ps = null;
try {
BaseDBTable param = BaseDBTable.getInstance(c);
try {
if(!BaseTableUtil.getInstance(getConnection()).valiTableExist(param.getTableName())){
ps = getConnection()
.prepareStatement(param.getCreateTableSql());
ps.execute();
insertORMDBTable(param);
}
} catch (SQLException e) {
throw new ORMException(e);
}
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public void createMiddleTable(Class<?> c, Class<?> childClass) throws ORMException {
List<String> tableNames=getTableName(c, childClass);
boolean isCreate=false;
for(String tableName:tableNames){
if(valiTableExist(tableName)){
isCreate=true;
}
}
if(!isCreate){
PreparedStatement ps=null;
try {
String sql = "create table "+tableNames.get(0)+" (C1 binary(16),C2 binary(16)"+")";
ps = getConnection().prepareStatement(sql);
ps.execute();
} catch (SQLException e) {
throw new ORMException(e);
}finally {
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 获取自动生成列名
* @param c
* @param childClass
* @return
* @throws ORMNotDBTableException
*/
public static List<String> getTableName(Class<?> c, Class<?> childClass) throws ORMNotDBTableException{
List<String> names=new ArrayList<String>();
String name="";
String mainTableName=BaseDBTable.getInstance(c).getTableName();
String otherTableName=BaseDBTable.getInstance(childClass).getTableName();
mainTableName=mainTableName.length()>6?mainTableName.substring(mainTableName.length()-6):mainTableName;
otherTableName=otherTableName.length()>6?otherTableName.substring(otherTableName.length()-6):otherTableName;
int size=mainTableName.length()+otherTableName.length();
for (int i = 0; i < 2; i++) {
if(i==0){
name=mainTableName+size+"_"+otherTableName+size;
}else{
name=otherTableName+size+"_"+mainTableName+size;
}
names.add(name);
}
return names;
}
/**
* 判断此属性是否是想要映射的实体类
* @param f
* @return
*/
public static boolean isMappingObject(Field f){
if(f.getAnnotation(DBColumn.class)==null){
return !f.getType().isAssignableFrom(UUID.class)
&& !f.getType().isAssignableFrom(String.class)
&& !f.getType().isPrimitive();
}else{
return f.getAnnotation(DBColumn.class).mapping()&&!f.getType().isAssignableFrom(UUID.class)
&& !f.getType().isAssignableFrom(String.class)
&& !f.getType().isPrimitive();
}
}
/**
* 是否包含子查询对象
*
* @param c
* @return
*/
public static boolean isObject(Class<?> c) {
Field[] fields = BeanUtils.getAllFields_Cache(c);
for (Field f : fields) {
if (isMappingObject(f)) {
return true;
}
}
return false;
}
private void insertORMDBTable(BaseDBTable t) throws ORMNotDBTableException,
ORMException, SQLException {
// 修改表记录
Connection conn=getConnection();
ORM<ORMDBTable> orm = ORMFactory.instance(conn,
ORMDBTable.class);
ORMDBTable sdt = new ORMDBTable();
sdt.setClassUrl(t.getTableClass().getName());
sdt.setName(t.getTableName());
sdt.setRecid(GUIDUtils.getUUIDByText(sdt.getName()));
ORMDBTable sdt2 = orm.find(GUIDUtils.getUUIDByText(sdt.getName()));
int oldVersion;
if(sdt2==null){
oldVersion=1;
sdt.setVersion(oldVersion);
orm.insert(sdt);
conn.commit();
}else{
oldVersion=sdt2.getVersion();
sdt.setVersion(oldVersion+1);
orm.update(sdt);
conn.commit();
}
}
@Override
public void updateTable(Class<?> c) throws ORMException {
BaseDBTable param = BaseDBTable.getInstance(c);
// if not find table, create table.
if (!valiTableExist(param.getTableName())) {
createTable(c);
} else {
try {
PreparedStatement pre = getConnection()
.prepareStatement(
"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?");
List<String> oldColumn = new ArrayList<String>();
List<Field> newColumn = new ArrayList<Field>();
try {
pre.setString(1, param.getTableName());
ResultSet rs = pre.executeQuery();
try {
while (rs.next()) {
oldColumn.add(rs.getString(1));
}
} finally {
rs.close();
}
} finally {
pre.close();
}
Field[] fields = BeanUtils.getAllFields_Cache(c);
// 20130705
List<Field> oldFields = new ArrayList<Field>();
//
for (Field field : fields) {
if (field.getName().contains("$"))
continue;
BaseDBColumn lable = BaseDBColumn.getInstance(field);
if (!lable.isMapping())//未映射的跳过
continue;
if(Collection.class.isAssignableFrom(field.getType()))//集合属性跳过
continue;
if (!String.class.isAssignableFrom(field.getType())&&!UUID.class.isAssignableFrom(field.getType())&&!field.getType().isPrimitive()) {
continue;
}
String columnName = lable.getColumnName();
if (!oldColumn.contains(columnName)
&& !oldColumn.contains(columnName.toUpperCase())) {
newColumn.add(field);
}
// 20130705
else {
oldFields.add(field);
}
//
}
if (!newColumn.isEmpty()) {
// (加入字段)
StringBuilder sql = new StringBuilder("ALTER TABLE ");// SaasDBTable
// ADD
// sex
// BOOLEAN
// ")
sql.append(param.getTableName());
String columnName, columnType;
for (int i = 0; i < newColumn.size(); i++) {
sql.append(" ADD ");
BaseDBColumn column = BaseDBColumn
.getInstance(newColumn.get(i));
columnName = column.getColumnName();
columnType = column.getColumnType();
//
sql.append(" ");
sql.append(columnName);
sql.append(" ");
sql.append(columnType);
if (i != newColumn.size() - 1)
sql.append(", \n");
}
Statement stat = getConnection().createStatement();
try {
stat.execute(sql.toString());
} finally {
stat.close();
}
insertORMDBTable(param);
}
} catch (SQLException e) {
throw new ORMException(e);
}
}
}
@Override
public void autoUpdateAllTables() throws ORMException {
ORM<ORMDBTable> orm = ORMFactory.instance(getConnection(),
ORMDBTable.class);
List<ORMDBTable> tables = orm.getAll();
Class<?> c;
for (ORMDBTable t : tables) {
try {
c = Class.forName(t.getClassUrl(), true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
Log.getLog(this).w(e);
continue;
}
if (!valiTableExist(t.getName())) {
createTable(c);
} else if (BaseDBTable.getInstance(c).getDBTable().version() > t
.getVersion()) {
updateTable(c);
}
}
}
/**
* 自动建表
*/
@Override
public void autoUpdateTable(Class<?> c) throws ORMException {
BaseDBTable param = BaseDBTable.getInstance(c);
// if not find table, create table.
if (!valiTableExist(param.getTableName())) {
createTable(c);
return;
}
// if have new version, update table.
if (param.getDBTable().version() > 0) {
ORM<ORMDBTable> orm = ORMFactory.instance(getConnection(),
ORMDBTable.class);
ORMDBTable table = orm.find(GUIDUtils.getUUIDByText(param
.getTableName()));
if (null == table) {
table = new ORMDBTable(c);
orm.insert(table);
updateTable(c);
} else if (param.getDBTable().version() > table.getVersion()) {
updateTable(c);
}
}
}
@Override
public boolean valiTableExist(String tableName) throws ORMException {
boolean isExist = false;
try {
PreparedStatement pre = getConnection().prepareStatement(
"SHOW TABLES LIKE ?");
try {
pre.setString(1, tableName);
ResultSet rs = pre.executeQuery();
try {
isExist = rs.next();
} finally {
rs.close();
}
} finally {
pre.close();
}
} catch (SQLException e) {
throw new ORMException(e);
}
return isExist;
}
}