package org.fireflow.engine.modules.persistence.nutz.support;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.sql.DataSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.fireflow.engine.entity.runtime.impl.ProcessInstanceImpl;
import org.fireflow.model.io.Util4Deserializer;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.entity.MappingField;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.impl.EntityHolder;
import org.nutz.dao.impl.entity.AnnotationEntityMaker;
import org.nutz.dao.impl.entity.NutEntity;
import org.nutz.dao.impl.entity.field.NutMappingField;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.jdbc.ValueAdaptor;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.eject.EjectByGetter;
import org.nutz.lang.inject.InjectBySetter;
import org.nutz.lang.segment.CharSegment;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.trans.Trans;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class ExAnnotationEntityMaker extends AnnotationEntityMaker {
private static final Log log = Logs.get();
private static final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
private static final String ELM_CLASS = "class";
private static final String ELM_PROPERTY = "property";
public static final String FIREFLOW_ENTITY_PKG_PREFIX = "org.fireflow";
private static List<String> allMappingFiles = new ArrayList<String>();
static {
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ActivityInstanceHistory.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ActivityInstanceImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/FireflowConfigImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/LocalWorkItemImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ProcessDescriptor.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ProcessInstanceHistory.nutzmp.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ProcessInstanceImpl.nutzmp.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ProcessRepositoryImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ReassignConfigImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/RemoteWorkItemImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ScheduleJobHistory.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/ScheduleJobImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/TokenHistory.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/TokenImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/VariableHistory.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/VariableImpl.nutzmap.xml");
allMappingFiles.add("/org/fireflow/engine/modules/persistence/nutz/WorkItemHistory.nutzmap.xml");
}
private Map<Class,Element> classDefinitionsMap = new HashMap<Class,Element>();
private DataSource datasource;
private JdbcExpert expert;
private EntityHolder holder;
public ExAnnotationEntityMaker(DataSource datasource, JdbcExpert expert,
EntityHolder holder) {
super(datasource, expert, holder);
this.datasource = datasource;
this.expert = expert;
this.holder = holder;
try{
init();
}catch(Exception e){
log.error("初始化ExAnnotationEntityMaker错误。", e);
}
}
public <T> Entity<T> make(Class<T> type) {
if (type!=null && type.getName().startsWith(FIREFLOW_ENTITY_PKG_PREFIX)){
Element classElm = classDefinitionsMap.get(type);
if (classElm!=null){
Entity<T> result = makeEntity(type,classElm);
return result;
}
}
return super.make(type);
}
// private TableInfo _createTableInfo(Class<?> type) {
// TableInfo info = new TableInfo();
// Mirror<?> mirror = Mirror.me(type);
// info.annTable = mirror.getAnnotation(Table.class);
// info.annView = mirror.getAnnotation(View.class);
// info.annMeta = mirror.getAnnotation(TableMeta.class);
// info.annPK = mirror.getAnnotation(PK.class);
// info.annIndexes = mirror.getAnnotation(TableIndexes.class);
// info.tableComment = mirror.getAnnotation(Comment.class);
// return info;
// }
protected <T> Entity<T> makeEntity(Class<T> type,Element classElm){
NutEntity<T> en = _createNutEntity(type);
/*
* 获取实体的扩展描述
*/
// 全局
if (expert!=null && null != expert.getConf()) {
for (String key : expert.getConf().keySet())
en.getMetas().put(key, expert.getConf().get(key));
}
/*
* 获得表名以及视图名称及注释
*/
String tableName = classElm.getAttribute("table");
String viewName = classElm.getAttribute("view");
if (viewName==null || viewName.trim().equals("")){
viewName = tableName;
}
en.setTableName(tableName);
en.setViewName(viewName);
Element tableCommentElm = Util4Deserializer.child(classElm, "comment");
if (tableCommentElm!=null){
en.setHasTableComment(true);
en.setTableComment(tableCommentElm.getTextContent());
}
/*
* 获取所有的数据库字段
*/
// 字段里面是不是有声明过 '@Column' @Comment
// boolean shouldUseColumn = false;
// boolean hasColumnComment = false;
// for (Field field : en.getMirror().getFields()) {
// if (shouldUseColumn && hasColumnComment) {
// break;
// }
// if (!shouldUseColumn && null != field.getAnnotation(Column.class)) {
// shouldUseColumn = true;
// }
// if (!hasColumnComment && null != field.getAnnotation(Comment.class)) {
// hasColumnComment = true;
// }
// }
//
// en.setHasColumnComment(hasColumnComment);
//读取复合主键
String pkFieldStrs = classElm.getAttribute("pk");
List<String> pkFields = new ArrayList<String>();
if (pkFieldStrs!=null && !pkFieldStrs.trim().equals("")){
StringTokenizer tokenizer = new StringTokenizer(pkFieldStrs,",");
while(tokenizer.hasMoreTokens()){
String tk = tokenizer.nextToken();
pkFields.add(tk);
}
}
/*
* 循环获取实体字段
*/
//首先获取id,此处的id即nutz的name
Element idElm = Util4Deserializer.child(classElm, "id");
if (idElm!=null){
MappingField mf = createMappingField(en,type,idElm,false,true,pkFields);
en.addMappingField(mf);
}
List<Element> propertyElms = Util4Deserializer.children(classElm, ELM_PROPERTY);
for (Element elm : propertyElms){
MappingField mf = createMappingField(en,type,elm,false,false,pkFields);
en.addMappingField(mf);
}
if (holder!=null){
holder.set(en); // 保存一下,这样别的实体映射到这里时会用的到
}
try {
/*
* 解析所有关联字段
*/
// // 一对一 '@One'
// for (LinkInfo li : ones) {
// en.addLinkField(new OneLinkField(en, holder, li));
// }
// // 一对多 '@Many'
// for (LinkInfo li : manys) {
// en.addLinkField(new ManyLinkField(en, holder, li));
// }
// // 多对多 '@ManyMany'
// for (LinkInfo li : manymanys) {
// en.addLinkField(new ManyManyLinkField(en, holder, li));
// }
// 检查复合主键
en.checkCompositeFields(pkFields.toArray(new String[pkFields.size()]));
/*
* 交付给 expert 来检查一下数据库一致性
*/
if (null != datasource && null != expert) {
_my_checkupEntityFieldsWithDatabase(en);
}
} catch (RuntimeException e) {
holder.remove(en);
throw e;
} catch (Throwable e) {
holder.remove(en);
throw Lang.wrapThrow(e);
}
return en;
}
private void _my_checkupEntityFieldsWithDatabase(NutEntity<?> en) {
Connection conn = null;
try {
conn = Trans.getConnectionAuto(datasource);
expert.setupEntityField(conn, en);
}
catch (Exception e) {
if (log.isDebugEnabled())
log.debugf("Fail to setup '%s'(%s) by DB, because: (%s)'%s'",
en.getType().getName(),
en.getTableName(),
e.getClass().getName(),
e.getMessage());
}
finally {
Trans.closeConnectionAuto(conn);
}
}
private MappingField createMappingField(Entity en,Class type,Element fieldElm, boolean isId,boolean isName,List<String> pkFields){
NutMappingField ef = new NutMappingField(en);
String fieldName = fieldElm.getAttribute("name");
String s = null;
if (fieldName.length()>1){
s = fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
}else{
s = fieldName.toUpperCase();
}
String setterName = "set"+s;
String getterName = "get"+s;
String getterName2 = "is"+s;
Method setter = null;
Method getter = null;
// Field field;
try {
Method[] allMethods = type.getMethods();
for (Method m : allMethods){
if(m.getName().equals(setterName)){
setter = m;
}else if (m.getName().equals(getterName) || m.getName().equals(getterName2)){
getter = m;
}
}
} catch (SecurityException e1) {
throw new RuntimeException(e1);
}
Element columnElem = Util4Deserializer.child(fieldElm,"column");
// 字段的 Java 名称
ef.setName(fieldName);
if (getter!=null){
ef.setType(getter.getGenericReturnType());
}
// 字段的数据库名
if (null == columnElem || Strings.isBlank(columnElem.getAttribute("name")))
ef.setColumnName(fieldName);
else
ef.setColumnName(columnElem.getAttribute("name"));
// 字段的注释
if (columnElem!=null ){
Element commentElm = Util4Deserializer.child(columnElem,"comment");
boolean hasColumnComment = null != commentElm;
ef.setHasColumnComment(hasColumnComment);
if (hasColumnComment) {
String comment = commentElm.getTextContent();
if (Strings.isBlank(comment)) {
ef.setColumnComment(fieldName);
} else {
ef.setColumnComment(comment);
}
}
}
//处理主键
// Id 字段
if (isId) {
ef.setAsId();
}
// Name 字段
if (isName) {
ef.setAsName();
}
if (pkFields.contains(fieldName)){
ef.setAsCompositePk();
}
// 检查 @Id 和 @Name 的冲突
if (ef.isId() && ef.isName())
throw Lang.makeThrow("Field '%s'(%s) can not be @Id and @Name at same time!",
ef.getName(),
ef.getEntity().getType().getName());
// 只读
// if (null != info.annReadonly)
// ef.setAsReadonly();
// 字段更多定义
if (null != columnElem) {
// if (fieldName.equals("suspended")){
// System.out.println("======");
// };
// 类型
// ef.setColumnType(info.annDefine.type());
Jdbcs.guessEntityFieldColumnType(ef);
// 宽度
String length = columnElem.getAttribute("length");
if (length==null || length.trim().equals("")){
if (ef.getWidth() == 0 && ef.getColumnType() == ColType.VARCHAR) {
ef.setWidth(50);
}
}else{
ef.setWidth(Integer.parseInt(length));
}
// // 精度
// ef.setPrecision(info.annDefine.precision());
// 无符号
// if (info.annDefine.unsigned())
// ef.setAsUnsigned();
// 非空约束
String notNull = columnElem.getAttribute("not-null");
if (notNull!=null && !notNull.trim().equals("")){
if (notNull.equalsIgnoreCase("true") || notNull.equalsIgnoreCase("t") || notNull.equalsIgnoreCase("1")){
ef.setAsNotNull();
}
}
// 自增,如果 @Id(auto=false),则忽略
// if (info.annDefine.auto() && !ef.isId())
// ef.setAsAutoIncreasement();
// 是否为自定义类型呢?
// if (info.annDefine.customType().length() > 0) {
// ef.setCustomDbType(info.annDefine.customType());
// }
// 插入更新操作
// ef.setInsert(info.annDefine.insert());
String update = fieldElm.getAttribute("update");
if (update!=null && !update.trim().equals("")){
ef.setUpdate(Boolean.parseBoolean(update));
}
// 默认值
if (columnElem!=null ){
String defaultValue = columnElem.getAttribute("default");
if (null != defaultValue ){
if (defaultValue.equals("CURRENT_TIMESTAMP")){
ef.setUpdate(false);//mysql 数据库自动设值
ef.setInsert(false);//mysql 数据库自动设值
}else{
ef.setDefaultValue(new CharSegment(defaultValue));
}
}
}
}
// 猜测字段类型
else {
Jdbcs.guessEntityFieldColumnType(ef);
}
// 字段值的适配器
String adaptorClzName = fieldElm.getAttribute("adaptor");
if (null==adaptorClzName || adaptorClzName.trim().equals("")){
if (expert!=null){
ef.setAdaptor(expert.getAdaptor(ef));
}
}else{
try {
Class clz = Class.forName(adaptorClzName);
ValueAdaptor adaptor = (ValueAdaptor)clz.newInstance();
ef.setAdaptor(adaptor);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}catch (ClassNotFoundException e){
throw new RuntimeException(e);
}
}
// 输入输出
ef.setInjecting(new InjectBySetter(setter));
ef.setEjecting(new EjectByGetter(getter));
return ef;
}
public static void main(String[] args){
// File f = new File("C:/Users/SX-7F-01-006/git/FireflowEngine20/fireflow-nutz/src/main/resources/org/fireflow/engine/modules/persisence/nutz");
// File[] allxmls = f.listFiles();
// for (File x :allxmls){
// System.out.println("allMappingFiles.add(\"/org/fireflow/engine/modules/persistence/nutz/"+x.getName()+"\");");
// }
System.out.println("Begin~~~~~~~~~~~~~~~~~~~~~~~~");
ExAnnotationEntityMaker maker = new ExAnnotationEntityMaker(null,null,null);
Entity entity = maker.make(ProcessInstanceImpl.class);
System.out.println("end!!!");
}
/**
* 加载所有的映射文件
*/
protected void init()throws Exception{
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
for (String fileName : allMappingFiles){
try{
InputStream instream = ExAnnotationEntityMaker.class.getResourceAsStream(fileName);
Document document = docBuilder.parse(instream);
parseClassElment(document);
instream.close();
}catch(Throwable t){
t.printStackTrace();
throw new RuntimeException(t);
}
}
}
protected void parseClassElment(Document document) throws ClassNotFoundException{
Element nutzMappingElm = document.getDocumentElement();
List<Element> classElmList = Util4Deserializer.children(nutzMappingElm, ELM_CLASS);
for (Element clzElm : classElmList){
String className = clzElm.getAttribute("name");
Class clz = Class.forName(className);
classDefinitionsMap.put(clz, clzElm);
}
}
}