public class Model implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 3485804608796833321L;

    private final LinkedHashMap<String, Object> content;

    private final Map<String, Object> context;

    public static final String MODEL_NAME = "table_name";

    public static final String DATA_BASE = "data_base";

    public static final String MODEL_ID = "single_primary_key";
    
    public static final String VERSION = "version";

    public Model(String modelName) {
        content = new LinkedHashMap<String, Object>();
        context = new HashMap<String, Object>();
        context.put(MODEL_NAME, modelName.toLowerCase().trim());
    }

    public Model(String database, String modelName) {
        content = new LinkedHashMap<String, Object>();
        context = new HashMap<String, Object>();
        context.put(MODEL_NAME, modelName.toLowerCase().trim());
        context.put(DATA_BASE, database.toLowerCase().trim());
    }

    public Model(Class<?> clazz) {
        content = new LinkedHashMap<String, Object>();
        context = new HashMap<String, Object>();
        String name = clazz.getName();
        name = name.substring(name.lastIndexOf(".") + 1);
        char[] array = name.toCharArray();
        array[0] += 32;
        context.put(MODEL_NAME, String.valueOf(array).toLowerCase().trim());
    }
    
    public Model(Object obj) {
    	this(null, obj);
    }

    public Model(String database, Object obj) {
    	if(obj instanceof Model){
    		Model temp = (Model) obj;
    		content = temp.getContent();
    		context = temp.getContext(); 
    	}else{
    		content = new LinkedHashMap<String, Object>();
            context = new HashMap<String, Object>();
            Map<String, Object> map = null;
            if(obj instanceof Map){
            	map = (Map<String, Object>) obj;
            }else{
            	String name = obj.getClass().getName();
                context.put(MODEL_NAME, name.substring(name.lastIndexOf(".") + 1).toLowerCase().trim());
                map = (Map<String, Object>) JsonUtils.objToMap(obj);
            }
            content.putAll(map);
            if(StringUtils.isNotEmpty(database)){
            	context.put(DATA_BASE, database.toLowerCase().trim());
            }
            if(null != map && map.containsKey("id")){
            	this.setSinglePrimaryKey(map.get("id"));
            }
    	}
    }

    public Model(String modelName, Map<String, Object> obj) {
        context = new HashMap<String, Object>();
        content = new LinkedHashMap<String, Object>();
        context.put(MODEL_NAME, modelName.toLowerCase().trim());
        content.putAll(obj);
        if(null != obj && obj.containsKey("id")){
        	this.setSinglePrimaryKey(obj.get("id"));
        }
    }

    public void setSinglePrimaryKey(Object primaryKey) {
        context.put(MODEL_ID, primaryKey);
    }

    public void setDatabase(String database) {
        context.put(DATA_BASE, database);
    }
    
    public void setVersion(Object version) {
        context.put(VERSION, version);
    }

    public String getSinglePrimaryKey() {
    	Object id = context.get(MODEL_ID);
    	if(null != id){
    		return String.valueOf(id);
    	}
        return null;
    }

    public String getDatabase() {
        return (String) context.get(DATA_BASE);
    }

    public String getTableName() {
        return (String) context.get(MODEL_NAME);
    }
    
    public Object getVersion() {
        return content.get(VERSION);
    }

    public void setField(String field, Object value) {
        if (StringUtils.isEmpty(field)) {
            return;
        }
        content.put(field, value);
    }

    public Object getField(String field) {
        if (StringUtils.isEmpty(field)) {
            return null;
        }
        return content.get(field);
    }

    public LinkedHashMap<String, Object> getContent() {
        return content;
    }

    public void addContent(Map<String, Object> content) {
        this.content.putAll(content);
    }
    
    public Map<String, Object> getContext() {
		return context;
	}

	public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + content.hashCode();
        result = prime * result + context.hashCode();
        return result;
    }
    
    private String firstToLower(String str) {
        char[] array = str.toCharArray();
        array[0] += 32;
        return String.valueOf(array);
    }

} public class QueryCriteria {
	
	private String database;
    
    private String table;
    
    private String orderByClause;

    private String groupBy;
    
    private boolean distinct;

    private List<Criteria> oredCriteria;

    private boolean selectOne;
    
    private int pageIndex = 1;
    
    private int pageSize = 15;
    
    private int recordIndex = 0;
    
    private int limit;
    
    private Object version;
    
    public QueryCriteria() {
        oredCriteria = new ArrayList<Criteria>();
    }

    public void setOrderByClause(String orderByClause) {
        this.orderByClause = orderByClause;
    }

    public String getOrderByClause() {
        return orderByClause;
    }
    
    public String getGroupBy() {
		return groupBy;
	}

	public void setGroupBy(String groupBy) {
		this.groupBy = groupBy;
	}

	public void setDistinct(boolean distinct) {
        this.distinct = distinct;
    }

    public boolean getDistinct() {
        return distinct;
    }
    
    public int getPageIndex() {
        return pageIndex;
    }

    public void setPageIndex(int pageIndex) {
        this.pageIndex = pageIndex;
    }

    public int getPageSize() {
    	
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public String getTable() {
        return table;
    }

    public void setTable(String table) {
        this.table = table.toLowerCase().trim();
    }
    
    public String getDatabase() {
		return database;
	}

	public void setDatabase(String database) {
		this.database = database;
	}

	public Object getVersion() {
		return version;
	}

	public void setVersion(Object version) {
		this.version = version;
	}
	
	public int getRecordIndex() {
		return recordIndex;
	}

	public void setRecordIndex(int recordIndex) {
		this.recordIndex = recordIndex;
	}

	public int getLimit() {
		return limit;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

	public void setTable(Class<?> clazz) {
        String name = clazz.getName();
        name = name.substring(name.lastIndexOf(".")+1);
        char[] array = name.toCharArray();
        array[0] += 32;
        this.table = String.valueOf(array).toLowerCase().trim();
    }
    
    public List<Criteria> getOredCriteria() {
        return oredCriteria;
    }

    public void or(Criteria criteria) {
        oredCriteria.add(criteria);
    }

    public Criteria or() {
        Criteria criteria = createCriteriaInternal();
        oredCriteria.add(criteria);
        return criteria;
    }

    public Criteria createCriteria() {
        Criteria criteria = createCriteriaInternal();
        if (oredCriteria.size() == 0) {
            oredCriteria.add(criteria);
        }
        return criteria;
    }

    protected Criteria createCriteriaInternal() {
        Criteria criteria = new Criteria();
        return criteria;
    }

    public void clear() {
        oredCriteria.clear();
        orderByClause = null;
        distinct = false;
    }

    public void setSelectOne(boolean selectOne) {
        this.selectOne = selectOne;
    }

    public boolean getSelectOne() {
        return this.selectOne;
    }
    
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((orderByClause == null) ? 0 : orderByClause.hashCode());
        result = prime * result + ((database == null) ? 0 : database.hashCode());
        result = prime * result + ((table == null) ? 0 : table.hashCode());
        result = prime * result + ((version == null) ? 0 : version.hashCode());
        result = prime * result + ((groupBy == null) ? 0 : groupBy.hashCode());
        result = prime * result + (distinct ? 1231 : 1237);
        result = prime * result + (selectOne ? 1231 : 1237);
        result = prime * result + pageIndex + pageSize;
        result = prime * result + recordIndex + limit;
        if (oredCriteria != null) {
            for (Criteria criteria : oredCriteria) {
                for (Criterion cter : criteria.getAllCriteria()) {
                	result = prime * result + ((cter== null)?0:cter.hashCode());
                }
            }
        }
        return result;
    }
    
    public String toString(){
    	StringBuffer sb = new StringBuffer();
    	if(StringUtils.isNotEmpty(database)){
    		sb.append("database:").append(database).append(",");
    	}
    	if(StringUtils.isNotEmpty(table)){
    		sb.append("table:").append(table).append(",");
    	}
    	if(StringUtils.isNotEmpty(orderByClause)){
    		sb.append("orderByClause:").append(orderByClause).append(",");
    	}
    	if(StringUtils.isNotEmpty(groupBy)){
    		sb.append("groupBy:").append(groupBy).append(",");
    	}
    	sb.append("distinct:").append(distinct).append(",");
    	if(null != oredCriteria){
    		sb.append("oredCriteria:").append(oredCriteria).append(",");
    	}
    	sb.append("selectOne:").append(selectOne).append(",");
    	sb.append("pageIndex:").append(pageIndex).append(",");
    	sb.append("pageSize:").append(pageSize).append(",");
    	sb.append("recordIndex:").append(recordIndex).append(",");
    	if(null != version){
    		sb.append("version:").append(version).append(",");
    	}
    	sb.deleteCharAt(sb.lastIndexOf(","));
        
    	return sb.toString();
    }

    protected abstract static class GeneratedCriteria {
        protected List<Criterion> criteria;

        protected GeneratedCriteria() {
            super();
            criteria = new ArrayList<Criterion>();
        }

        public boolean isValid() {
            return criteria.size() > 0;
        }

        public List<Criterion> getAllCriteria() {
            return criteria;
        }

        public List<Criterion> getCriteria() {
            return criteria;
        }
        
        protected void addCriterion(String sql) {
            if (StringUtils.isEmpty(sql)) {
                throw new RuntimeException("Sql cannot be null");
            }
            criteria.add(new Criterion(sql));
        }
        
        protected void addCriterion(Condition condition, String column) {
            if (condition == null || StringUtils.isEmpty(column)) {
                throw new RuntimeException("Column for condition cannot be null");
            }
            criteria.add(new Criterion(condition, column));
        }
        
        protected void addCriterion(Condition condition, Object value, String typeHandler, String column) {
            if (value == null || condition == null || StringUtils.isEmpty(column)) {
                throw new RuntimeException("Value for condition cannot be null");
            }
            criteria.add(new Criterion(condition, value, typeHandler, column));
        }

        protected void addCriterion(Condition condition, Object value1, Object value2, String typeHandler, String column) {
            if (value1 == null || value2 == null) {
                throw new RuntimeException("Between values for " + column + " cannot be null");
            }
            criteria.add(new Criterion(condition, value1, value2, typeHandler, column));
        }
        
        public Criteria andColumnSql(String sql) {
            addCriterion(sql);
            return (Criteria) this;
        }

        public Criteria andColumnIsNull(String column) {
            addCriterion(Condition.IS_NULL, column);
            return (Criteria) this;
        }

        public Criteria andColumnIsNotNull(String column) {
            addCriterion(Condition.IS_NOT_NULL, column);
            return (Criteria) this;
        }

        public Criteria andColumnEqualTo(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.EQUAL, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnNotEqualTo(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.NOT_EQUAL, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnGreaterThan(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.GREATER_THAN, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnGreaterThanOrEqualTo(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.GREATER_THAN_OR_EQUAL, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnLessThan(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.LESS_THAN, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnLessThanOrEqualTo(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.LESS_THAN_OR_EQUAL, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnIn(String column, List<?> values) {
        	if(null != values && values.size() > 0){
        		addCriterion(Condition.IN, values, values.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnNotIn(String column, List<Object> values) {
        	if(null != values && values.size() > 0){
        		addCriterion(Condition.NOT_IN, values, values.getClass().getName(), column);
        	}
            return (Criteria) this;
        }
        
        public Criteria andColumnLike(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.LIKE, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }
        
        public Criteria andColumnNotLike(String column, Object value) {
        	if(null != value){
        		addCriterion(Condition.NOT_LIKE, value, value.getClass().getName(), column);
        	}
            return (Criteria) this;
        }

        public Criteria andColumnBetween(String column, Object value1, Object value2) {
            addCriterion(Condition.BETWEEN, value1, value2, value1.getClass().getName(), column);
            return (Criteria) this;
        }

        public Criteria andColumnNotBetween(String column, Object value1, Object value2) {
            addCriterion(Condition.NOT_BETWEEN, value1, value2, value1.getClass().getName(), column);
            return (Criteria) this;
        }

    }

    public class Criteria extends GeneratedCriteria {

        protected Criteria() {
            super();
        }
        /**
         * 快速封装查询条件
         * @param condition Condition条件枚举
         * @param filed 字段
         * @param value 值
         * @return
         */
        public Criteria append(Condition condition, String filed, Object value){
        	if(condition == Condition.EQUAL){
        		andColumnEqualTo(filed, value);
    		}else if(condition == Condition.NOT_EQUAL){
    			andColumnNotEqualTo(filed, value);
    		}else if(condition == Condition.GREATER_THAN){
    			andColumnGreaterThan(filed, value);
    		}else if(condition == Condition.GREATER_THAN_OR_EQUAL){
    			andColumnGreaterThanOrEqualTo(filed, value);
    		}else if(condition == Condition.LESS_THAN){
    			andColumnLessThan(filed, value);
    		}else if(condition == Condition.LESS_THAN_OR_EQUAL){
    			andColumnLessThanOrEqualTo(filed, value);
    		}else if(condition == Condition.LIKE){
    			andColumnLike(filed, value);
    		}else if(condition == Condition.SQL){
    			andColumnSql(value.toString());
    		}else{
    			andColumnEqualTo(filed, value);
    		}
        	return this;
        }
        
        /**
         * 快速封装查询条件
         * @param filed 字段
         * @param value 值
         * @return
         */
        public Criteria append(String filed, Object value){
        	return append(Condition.EQUAL, filed, value);
        }
        
        /**
         * 快速封装sql查询条件
         * @param sql sql片段
         * @return
         */
        public Criteria append(String sql){
        	return append(Condition.SQL, null, sql);
        }
        
        public String toString(){
        	if(null != criteria){
        		return criteria.toString();
        	}
        	return null;
        }
    }
    
    
    

} public class DBContextHolder {
	
	public static final String WRITE = "write";
	public static final String READ = "read";
	public static final String STANDBY = "standby";
	public static final String REPORT = "report";
	public static final String TRANSACTION = "transaction";
	
	private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>();

	public static void swithToWrite() {
		if(!TRANSACTION.equals(CONTEXT_HOLDER.get())){
			CONTEXT_HOLDER.set(WRITE);
		}
	}
	
	public static void swithToRead() {
		if(!TRANSACTION.equals(CONTEXT_HOLDER.get())){
			CONTEXT_HOLDER.set(READ);
		}
	}
	
	public static void swithToReport() {
		CONTEXT_HOLDER.set(REPORT);
	}
	
	public static void swithTotransaction() {
		CONTEXT_HOLDER.set(TRANSACTION);
	}
	
	public static void swithTo(String dbType) {
		CONTEXT_HOLDER.set(dbType);
	}

	public static String getCurrentDataSourceKey() {
		return CONTEXT_HOLDER.get();
	}

	public static void clear() {
		CONTEXT_HOLDER.remove();
	}
	
} public class Content implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -4742799207318016984L;

	/**
     * 所有字段-字符串
     */
    private String columns;
    
    
    private String database;
    
    /**
     * 表名
     */
    private String tableName;
    
    /**
     * 字段列表
     */
    private Map<String, Column> fields;
    
    /**
     * 索索列表
     */
    private Map<String, List<String>> indexs;
    
    /**
     * 索索字段-名称对应
     */
    private Map<String, String> indexFields;
    
    /**
     * 主键
     */
    private PrimaryKey primaryKey;
    
    /**
     * 版本字段
     */
    private Column versionField;
    
    public Content(){
    	super();
        fields = new HashMap<String, Column>();
        indexs = new HashMap<String, List<String>>();
        indexFields = new HashMap<String, String>();
        primaryKey = new PrimaryKey();
    }
    
    /**
     * 处理后的表字段 {@code String} 格式的字符串
     * <ul>
     * <li>对字段时行排序处理，sql也会进行排序；</li>
     * <li>最高级别隐藏不需要显示的字段；</li>
     * <li>生成主键相关信息；</li>
     * <li>生成外键相关信息；</li>
     * <li>生成自定义显示信息；</li>
     * </ul>
     * @return 处理后的表字段 {@code String} 格式的字符串。
     * @since 1.0
     */
    public String caculationAllColumn(){
        if(StringUtils.isNotEmpty(columns)){
            return columns;
        }else{
            StringBuffer sb = new StringBuffer();
            List<Column> fds = new ArrayList<Column>();
            if(fds == null || fds.size() == 0){
                fds.addAll(this.fields.values());
            }
            for(Column f:fds){
                sb.append(ColumnWrapperUtils.wrap(f.getFieldName())).append(",");
            }
            if(sb.length() > 0){
                columns = sb.deleteCharAt(sb.lastIndexOf(",")).toString();
            }
        }
        return columns;
    }
    
    public String getTableName() {
        return tableName;
    }
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    
    public Map<String, Column> getFields() {
        return fields;
    }
    
    public Column getField(String fieldName) {
        return fields.get(fieldName);
    }

    public void setFields(Map<String, Column> fields) {
        this.fields = fields;
    }

    public PrimaryKey getPrimaryKey() {
        return primaryKey;
    }
    
    public void addPrimaryFieldName(String fieldName){
        primaryKey.addFieldName(fieldName.toLowerCase());
    }
    
    public void addField(Column field){
        this.fields.put(field.getFieldName().toLowerCase(), field);
    }
    
    public String getColumns() {
        return columns;
    }

	public void setColumns(String columns) {
		this.columns = columns;
	}

	public void setPrimaryKey(PrimaryKey primaryKey) {
		this.primaryKey = primaryKey;
	}

	public Column getVersionField() {
		return versionField;
	}

	public void setVersionField(Column versionField) {
		this.versionField = versionField;
	}

	public String getDatabase() {
		return database;
	}

	public void setDatabase(String database) {
		this.database = database;
	}

	public Map<String, List<String>> getIndexs() {
		return indexs;
	}

	public void setIndexs(Map<String, List<String>> indexs) {
		this.indexs = indexs;
	}

	public Map<String, String> getIndexFields() {
		return indexFields;
	}

	public void setIndexFields(Map<String, String> indexFields) {
		this.indexFields = indexFields;
	}

	
	
	
    
} public class QueryResult implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 5675310807548144110L;
    
    private List<Map<String, Object>> copyForShardResult = new ArrayList<Map<String, Object>>();
    
    private List<Map<String, Object>> resultList;
    
    private Map<String, Object> resultMap;
    
    private Map<String, Object> page;
    
    public void addShardResult(List<Map<String, Object>> shardResult){
    	copyForShardResult.addAll(shardResult);
    }

    public void setResultList(List<Map<String, Object>> resultList) {
        this.resultList = resultList;
    }

    public void setResultMap(Map<String, Object> resultMap) {
        this.resultMap = resultMap;
    }
    
    public Map<String, Object> get(){
    	if(resultMap != null && resultMap.size() > 0){
    		return resultMap;
    	}
    	if(resultList != null && resultList.size() > 0){
    		return resultList.get(0);
    	}
        return resultMap;
    }
    
    public Map<String, Object> getWithAliasName(Map<String, String> aliasName){
    	Map<String, Object> result = get();
        return getResultWithAliasName(result, aliasName);
    }
    
    public Map<String, Object> getWithAliasName(List<String> hiddenFields, Map<String, String> aliasName){
    	Map<String, Object> result = get(hiddenFields);
    	result = getResultWithAliasName(result, aliasName);
        return result;
    }
    
    
    public Map<String, Object> get(List<String> hiddenFields){
    	Map<String, Object> temp = get();
    	if(temp != null){
    		for(String field : hiddenFields){
    			if(temp.containsKey(field)){
    				temp.remove(field);
    			}
        	}
    	}
        return temp;
    }
    
    public List<Map<String, Object>> getList(){
        return resultList;
    }
    
    public List<Map<String, Object>> getList(List<String> hiddenFields){
    	if(hiddenFields != null && resultList != null){
    		for(String field : hiddenFields){
        		for(Map<String, Object> map : resultList){
        			if(map.containsKey(field)){
        				map.remove(field);
        			}
        		}
        	}
    	}
        return resultList;
    }
    
    @Deprecated
    public List<Map<String, Object>> getList(Map<String, String> aliasName){
        return getResultListWithAliasName(resultList, aliasName);
    }
    
    public List<Map<String, Object>> getListWithAliasName(Map<String, String> aliasName){
    	if(aliasName != null && resultList != null){
    		resultList = getResultListWithAliasName(resultList, aliasName);
    	}
        return resultList;
    }
    
    @Deprecated
    public List<Map<String, Object>> getList(List<String> hiddenFields, Map<String, String> aliasName){
    	resultList = getList(hiddenFields);
    	resultList = getListWithAliasName(aliasName);
        return resultList;
    }
    
    public List<Map<String, Object>> getListWithAliasName(List<String> hiddenFields, Map<String, String> aliasName){
    	resultList = getList(hiddenFields);
    	resultList = getListWithAliasName(aliasName);
        return resultList;
    }
    
    public <T> T as(Class<T> beanClass){
    	Map<String, Object> result = get();
    	if(result != null){
    		return JsonUtils.mapToObj(result, beanClass);
    	}
        return null;
    }
    
    public <T> List<T> asList(Class<T> beanClass){
        if(resultList != null){
        	return JsonUtils.mapListToObjList(resultList, beanClass);
        }
        return null;
    }

	public Map<String, Object> getPage() {
		return page;
	}
	

	public void setPage(Map<String, Object> page) {
		this.page = page;
	}
    
	private Map<String, Object> getResultWithAliasName(Map<String, Object> result, Map<String, String> aliasName){
    	if(result != null && result.size() > 0 && null != aliasName){
    		for(Entry<String, String> item : aliasName.entrySet()){
    			if(StringUtils.isNotBlank(item.getKey()) && StringUtils.isNotBlank(item.getValue())){
    				result.put(item.getValue(), result.get(item.getKey()));
    				result.remove(item.getKey());
    			}
    		}
    	}
        return result;
    }
	
	private List<Map<String, Object>> getResultListWithAliasName(List<Map<String, Object>> result, Map<String, String> aliasName){
    	if(result != null && result.size() > 0 && null != aliasName){
    		for(Entry<String, String> item : aliasName.entrySet()){
    			for(Map<String, Object> map : result){
    				if(StringUtils.isNotBlank(item.getKey()) && StringUtils.isNotBlank(item.getValue())){
    					map.put(item.getValue(), map.get(item.getKey()));
    					map.remove(item.getKey());
        			}
    			}
    		}
    	}
        return result;
    }
    
} public interface ResolveDataBase {
    
    /**
     * 解析表
     * @param tableName table name
     * @return table
     */
    public Table loadTable(String tableName);
    
    /**
     * 重新加载表数据
     * @param tableName table name
     * @return table
     */
    public Table reloadTable(String tableName);
    
    /**
     * 解析表
     * 
     * @param database database
     * @param tableName table name
     * @return table
     */
    public Table loadTable(String database, String tableName);
    
    public Table loadTable(String database, String tableName, String versionField);
    
    /**
     * 重新加载表数据
     * @param database database
     * @param tableName table name
     * @return table
     */
    public Table reloadTable(String database, String tableName);
    
    public Table reloadTable(String database, String tableName, String versionField);
    
    /**
     * 加载所有页面
     * @return all table names
     */
    public List<String> loadTables();
    
    public void setCacheManager(CacheManager cacheManager);

    public void setDataSource(DataSource dataSource);

} public class JavaTypeConversion {
	
	private static final Logger LOG = LoggerFactory.getLogger(JavaTypeConversion.class);
	
	private static final SimpleDateFormat[] formats = new SimpleDateFormat[] {
    	new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
    	new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US),
        new SimpleDateFormat("EEE MMM dd hh:mm:ss z yyyy", Locale.US),
        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US),
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US),
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US),
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss", Locale.US),
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss"),
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss"),
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.ss"),
        new SimpleDateFormat("yyyy年MM月dd日"),
        new SimpleDateFormat("yyyy-MM-dd")};
	
	
	public static <T> T convert(JavaType type, Object valueObj, Class<T> beanClass){
		return beanClass.cast(convert(type, valueObj));
	}
	
	public static Object convert(JavaType type, Object valueObj){
		if(null == type){
			return valueObj;
		}
		
		Object result = null;
		if (JavaType.DATE == type) {
			if(valueObj instanceof String){
				boolean fmtFlag = false;
				LOG.debug("时间格式转换开始value:" + valueObj);
				String value = String.valueOf(valueObj);
				for (SimpleDateFormat format : formats) {
				    try {
				    	Date date = format.parse(value);
				    	LOG.info("时间格式转换成功format:" + format.toPattern());
				        result = new Timestamp(date.getTime());
				        fmtFlag = true;
				        break;
				    } catch (ParseException e) {
				    	LOG.debug("时间格式转换失败format:" + format.toPattern());
				    }
				}
				if (!fmtFlag) {// 如果格式没转换成功 尝试毫秒值转换
				    if (NumberUtils.isNumber(value)) {
				        Long lv = NumberUtils.toLong(value);
				        result = new Timestamp(lv);
				        LOG.debug("时间格式转换成功:" + new Timestamp(lv));
				    } 
				}
			}else if(valueObj instanceof Long){
				result = new Timestamp((Long)valueObj);
			}else{
	        	result = valueObj;
	        }
        }else if (JavaType.INTEGER == type) {
        	if(valueObj instanceof String){
        		if(((String) valueObj).indexOf("=") == -1){
        			String[] vals = valueObj.toString().split("\\.");
                    result = Integer.valueOf(vals[0]);
        		}else{
        			result = valueObj;
        		}
			}else if(valueObj instanceof Float || valueObj instanceof Double){
				result = (Integer)valueObj;
			}else{
	        	result = valueObj;
	        }
        }else{
        	result = valueObj;
        }
		return result;
	}

} public class DalSqlException extends RuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	
	public DalSqlException() {
        super();
    }

    public DalSqlException(String message) {
        super(message);
    }


    public DalSqlException(String message, Throwable cause) {
        super(message, cause);
    }


    public DalSqlException(Throwable cause) {
        super(cause);
    }


    protected DalSqlException(String message, Throwable cause,
                               boolean enableSuppression,
                               boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }


} public interface ShardStrategy {
	
	int SHARDS_GROUP_TOTAL = 100;
	
	String[] selectShardForNewObject(long id);
	String[] selectShardFromData(String table);
	String[] selectShardForPrimaryKey(String table, Object id);
	
	
/*	ShardSelectionStrategy getShardSelectionStrategy();

	ShardResolutionStrategy getShardResolutionStrategy();

	ShardAccessStrategy getShardAccessStrategy();
	
	ShardReduceStrategy getShardReduceStrategy();*/
	
} public interface ShardStrategyFactory {

	ShardStrategy newShardStrategy();
} public class DefaultShardStrategyFactory extends AbstractShardStrategyFactory{

	@Override
	public ShardStrategy newShardStrategy() {
		return new ShardStrategy(){
			@Override
			public String[] selectShardFromData(String table) {
				if(tableShard.containsKey(table)){
					Shard shard = tableShard.get(table);
					return (String[])shard.getAllPartition().toArray();
				}
				return null;
			}

			@Override
			public String[] selectShardForNewObject(long id) {
				// TODO Auto-generated method stub
				return null;
			}

			@Override
			public String[] selectShardForPrimaryKey(String table, Object id) {
				if(tableShard.containsKey(table)){
					long idLong = Long.valueOf(id.toString());
					long psd = idLong % SHARDS_GROUP_TOTAL;
					return new String[]{tableShard.get(table).getPartition().get(psd)};
				}
				return null;
			}

		};
	}

} public class Observable {

	private Lock lock = new ReentrantLock(true);

	private List<OprateListener> listeners = new ArrayList<OprateListener>();

	public void addListener(OprateListener listener) {
		lock.lock();
		try {
			if (listener != null)
				listeners.add(listener);
		} finally {
			lock.unlock();
		}
	}

	public void deleteListener(OprateListener listener) {
		lock.lock();
		try {
			if (listener != null)
				listeners.remove(listener);
		} finally {
			lock.unlock();
		}
	}

	public void notifyListeners(Oprator oprator, OprateInfo oprateInfo) {
		lock.lock();
		try {
			if (listeners != null) {
				for (OprateListener obs : listeners) {
					obs.oprate(oprator, oprateInfo);
				}
			}
		} finally {
			lock.unlock();
		}
	}

} public class OprateInfo implements Serializable {

    //
    private static final long serialVersionUID = 7100282651039776916L;
    
    private String table;
    private List<String> fields;
    private QueryCriteria queryCriteria;
    private int seconds;
    private boolean useCache;
    private Map<String, Object> resultMap;
    private List<Map<String, Object>> resultList;
    private Object result;
    private Object id;
    
    public OprateInfo(String table, Map<String, Object> resultMap) {
		this.table = table;
		this.resultMap = resultMap;
	}
    
    public OprateInfo(String table, Object id) {
		this.table = table;
		this.id = id;
	}
    
    public OprateInfo(String table, int seconds, boolean useCache, Object id, Map<String, Object> resultMap) {
		this.table = table;
		this.seconds = seconds;
		this.useCache = useCache;
		this.id = id;
		this.resultMap = resultMap;
	}
    
    public OprateInfo(String table, QueryCriteria queryCriteria) {
		this.table = table;
		this.queryCriteria = queryCriteria;
	}
    
    public OprateInfo(String table, QueryCriteria queryCriteria, 
    		int seconds, boolean useCache, Object result) {
		this.table = table;
		this.queryCriteria = queryCriteria;
		this.seconds = seconds;
		this.useCache = useCache;
		this.result = result;
	}
    
    public OprateInfo(String table, QueryCriteria queryCriteria, Map<String, Object> resultMap) {
		this.table = table;
		this.queryCriteria = queryCriteria;
		this.resultMap = resultMap;
	}
    
    public OprateInfo(String table, Object id, Map<String, Object> resultMap) {
		this.table = table;
		this.id = id;
		this.resultMap = resultMap;
	}

    public OprateInfo(String table, List<String> fields, QueryCriteria queryCriteria, 
    		int seconds, boolean useCache, List<Map<String, Object>> resultList) {
		this.table = table;
		this.fields = fields;
		this.queryCriteria = queryCriteria;
		this.seconds = seconds;
		this.useCache = useCache;
		this.resultList = resultList;
	}
    
    public OprateInfo(String table, List<String> fields,
			QueryCriteria queryCriteria, int seconds, boolean useCache,
			Map<String, Object> resultMap, List<Map<String, Object>> resultList) {
		this.table = table;
		this.fields = fields;
		this.queryCriteria = queryCriteria;
		this.seconds = seconds;
		this.useCache = useCache;
		this.resultMap = resultMap;
		this.resultList = resultList;
	}

	public String getTable() {
		return table;
	}

	public void setTable(String table) {
		this.table = table;
	}

	public List<String> getFields() {
		return fields;
	}

	public void setFields(List<String> fields) {
		this.fields = fields;
	}

	public QueryCriteria getQueryCriteria() {
		return queryCriteria;
	}

	public void setQueryCriteria(QueryCriteria queryCriteria) {
		this.queryCriteria = queryCriteria;
	}

	public int getSeconds() {
		return seconds;
	}

	public void setSeconds(int seconds) {
		this.seconds = seconds;
	}

	public boolean isUseCache() {
		return useCache;
	}

	public void setUseCache(boolean useCache) {
		this.useCache = useCache;
	}

	public Map<String, Object> getResultMap() {
		return resultMap;
	}

	public void setResultMap(Map<String, Object> resultMap) {
		this.resultMap = resultMap;
	}

	public List<Map<String, Object>> getResultList() {
		return resultList;
	}

	public void setResultList(List<Map<String, Object>> resultList) {
		this.resultList = resultList;
	}

	public Object getResult() {
		return result;
	}

	public void setResult(Object result) {
		this.result = result;
	}

	public Object getId() {
		return id;
	}

	public void setId(Object id) {
		this.id = id;
	}



} public interface OprateListener {
	

	void oprate(Oprator oprator, OprateInfo oprateInfo);

} public enum Oprator {
	
	GET("GET"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"), COUNT("COUNT"), LIST("LIST"), PAGE("PAGE");
	
	public final String type;

	Oprator(String type) {
		this.type = type;
	}

} public class DefaultMasterSlaveRouter implements MasterSlaveRouter {

	@Override
	public void routeToMaster() {
		DBContextHolder.swithToWrite();

	}

	@Override
	public void routeToSlave() {
		DBContextHolder.swithToRead();

	}

	@Override
	public void routeToShard(String shard) {
		DBContextHolder.swithTo(shard);
	}

} public interface MasterSlaveRouter {
    
    public void routeToMaster();
    
    public void routeToSlave();
    
    public void routeToShard(String shard);

} public class ShardsUtils {
	
	public static List<Map<String, Object>> complieResult(List<Map<String, Object>> result, final QueryCriteria queryCriteria) {
		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		if (StringUtils.isNotEmpty(queryCriteria.getOrderByClause())) {
			final String[] fds = queryCriteria.getOrderByClause().split(" ");
			Collections.sort(result, new Comparator<Map<String, Object>>() {
				@Override
				public int compare(Map<String, Object> a, Map<String, Object> b) {
					Object va = a.get(fds[0]);
					Object vb = b.get(fds[0]);
					if(fds.length > 1 && "desc".equals(fds[1].toLowerCase())){
						return String.valueOf(va).compareTo(String.valueOf(vb))*-1;
					}else{
						return String.valueOf(va).compareTo(String.valueOf(vb));
					}
				}
			});
		}
		if(queryCriteria.getSelectOne()){
			resultList.add(result.get(0));
		}else{
			resultList.addAll(result.subList(0, queryCriteria.getPageSize()));
		}
		return resultList;
	}
	
	
	public final static long BASE_TIME = 1422766646843L;

	private static int SEQUENCE = (int) System.currentTimeMillis() % 10000;

	/**
	 * 生成唯一ID
	 * 
	 */
	public static long generateId() {
		long time = System.currentTimeMillis() - BASE_TIME;
		SEQUENCE++;
		if (SEQUENCE == 9999) {
			SEQUENCE = 1000;
		}
		time = time * 10000 + SEQUENCE;
		return time;
	}
    
	public static void main(String[] args) {
		String[] tt = "aaa desc".split(" ");
		for(int i=0;i<tt.length;i++){
			System.out.println(tt[i]);
		}

    }

}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import cn.uncode.dal.cache.CacheManager;
import cn.uncode.dal.criteria.Model;
import cn.uncode.dal.criteria.QueryCriteria;
import cn.uncode.dal.datasource.DBContextHolder;
import cn.uncode.dal.descriptor.Content;
import cn.uncode.dal.descriptor.QueryResult;
import cn.uncode.dal.descriptor.Table;
import cn.uncode.dal.descriptor.db.ResolveDataBase;
import cn.uncode.dal.descriptor.resolver.JavaType;
import cn.uncode.dal.descriptor.resolver.JavaTypeConversion;
import cn.uncode.dal.descriptor.resolver.JavaTypeResolver;
import cn.uncode.dal.exception.DalSqlException;
import cn.uncode.dal.internal.shards.strategy.ShardStrategy;
import cn.uncode.dal.internal.shards.strategy.ShardStrategyFactory;
import cn.uncode.dal.internal.shards.strategy.impl.DefaultShardStrategyFactory;
import cn.uncode.dal.internal.util.message.Messages;
import cn.uncode.dal.listener.Observable;
import cn.uncode.dal.listener.OprateInfo;
import cn.uncode.dal.listener.OprateListener;
import cn.uncode.dal.listener.Oprator;
import cn.uncode.dal.router.DefaultMasterSlaveRouter;
import cn.uncode.dal.router.MasterSlaveRouter;
import cn.uncode.dal.utils.ShardsUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package cn.uncode.dal.core;




public abstract class AbstractShardsBaseDAL extends Observable implements BaseDAL, InitializingBean {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractShardsBaseDAL.class);
    
    //------------------------------
  	// 可配置变量
  	//------------------------------
    protected CacheManager cacheManager;

    protected ResolveDataBase resolveDatabase;

    protected boolean useCache = true;
    
    protected String version;
    
    protected List<String> listenerNames;
    
    protected ShardStrategyFactory shardStrategyFactory;
    
    //------------------------------
  	// 私有变量
  	//------------------------------
    protected ShardStrategy shardStrategy;