GenericDelegator.java
protected GenericDelegator(String delegatorName) throws GenericEntityException {
if (Debug.infoOn()) Debug.logInfo("Creating new Delegator with name \"" + delegatorName + "\".", module);
this.delegatorName = delegatorName;
if (keepLocalReaders) {
/*
读取 components\accounting\entitydef\entitymodel.xml等文件,
这些文件是配置在components\...\ofbiz-component.xml中
*/
modelReader = ModelReader.getModelReader(delegatorName);
/*
Group的方法和Model的读取方法类似,也是先从entitymodel.xml和ofbiz-component.xml
取到资源文件,然后加载.
有一点须要说明:
*/
modelGroupReader = ModelGroupReader.getModelGroupReader(delegatorName);
}
primaryKeyCache = new UtilCache("entity.FindByPrimaryKey." + delegatorName, 0, 0, true);
allCache = new UtilCache("entity.FindAll." + delegatorName, 0, 0, true);
andCache = new UtilCache("entity.FindByAnd." + delegatorName, 0, 0, true);
// initialize helpers by group
/*
一个Group包含多个entitymodel.不同的Group可以对应不同的数据源,也就是说,可以和多个数据库相连
*/
Iterator groups = UtilMisc.toIterator(getModelGroupReader().getGroupNames());
while (groups != null && groups.hasNext()) {
/*
取到entityengine.xml中定义的group
比如:
<delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
<group-map group-name="org.ofbiz" datasource-name="localmssql"/>
<group-map group-name="other" datasource-name="localpostgres"/>
</delegator>
你定义entitygroup.xml文件中就可以这样定义
<entitygroup>
<entity-group group="other" entity="SequenceValueItem" />
<entity-group group="org.ofbiz" entity="SequenceValueItem" />
</entitygroup>
*/
String groupName = (String) groups.next();
String helperName = this.getGroupHelperName(groupName);
if (Debug.infoOn()) Debug.logInfo("Delegator \"" + delegatorName + "\" initializing helper \"" +
helperName + "\" for entity group \"" + groupName + "\".", module);
TreeSet helpersDone = new TreeSet();
if (helperName != null && helperName.length() > 0) {
// make sure each helper is only loaded once
if (helpersDone.contains(helperName)) {
if (Debug.infoOn()) Debug.logInfo("Helper \"" + helperName + "\" already initialized, not re-initializing.", module);
continue;
}
helpersDone.add(helperName);
// pre-load field type defs, the return value is ignored
/*
读取group 对应的fieldtype,这些文件处在entity/fieldtype
*/
ModelFieldTypeReader.getModelFieldTypeReader(helperName);
// get the helper and if configured, do the datasource check
GenericHelper helper = GenericHelperFactory.getHelper(helperName);
/*
生成group对应的datasourceinfo
*/
EntityConfigUtil.DatasourceInfo datasourceInfo = EntityConfigUtil.getDatasourceInfo(helperName);
if (datasourceInfo.checkOnStart) {
if (Debug.infoOn()) Debug.logInfo("Doing database check as requested in entityengine.xml with addMissing=" + datasourceInfo.addMissingOnStart, module);
try {
/*
1:读取group对应数据库所在的表
2:读取group对应数据所有的列
3:读到group对应的索引等...
它的读取方法有点特别,至少我是第一次见过,一般我们是从系统表里面去取,而它不是.
有兴趣可以看看DatabaseUtil.java里面的 checkdb方法,简单地copy一些代码出来
取table
DatabaseMetaData dbData = this.getDatabaseMetaData(connection, messages);
String[] types = {"TABLE", "VIEW", "ALIAS", "SYNONYM"};
tableSet = dbData.getTables(null, lookupSchemaName, null, types);
取 col
ResultSet rsCols = dbData.getColumns(null, lookupSchemaName, null, null);
4:this.getModelEntityMapByGroup(groupName)表示得到group对应的所有entity
checkDataSource的作用很明显,它用读到tables,columns,indexes等与entitymodel相比较,
如果不同,它就以entitymodel为基准,修改数据库,修改时都采用alert table等sql语句,
这样,ofbiz服务启动时,就会自动的把entitymodel中对应的关系反映到数据库,由于entitymodel]
并不是象hibenate那样,对应一个JavaBean,所以我们可以在系统运行时,很方便的修改entitymodel,
进而修改数据库,而不用动另何java文件.
*/
helper.checkDataSource(this.getModelEntityMapByGroup(groupName), null, datasourceInfo.addMissingOnStart);
} catch (GenericEntityException e) {
Debug.logWarning(e.getMessage(), module);
}
}
}
}
//time to do some tricks with manual class loading that resolves circular dependencies, like calling services...
ClassLoader loader = Thread.currentThread().getContextClassLoader();
// if useDistributedCacheClear is false do nothing since the
// distributedCacheClear member field with a null value will cause the
// dcc code to do nothing
if (getDelegatorInfo().useDistributedCacheClear) {
// initialize the distributedCacheClear mechanism
String distributedCacheClearClassName = getDelegatorInfo().distributedCacheClearClassName;
try {
Class dccClass = loader.loadClass(distributedCacheClearClassName);
this.distributedCacheClear = (DistributedCacheClear) dccClass.newInstance();
this.distributedCacheClear.setDelegator(this, getDelegatorInfo().distributedCacheClearUserLoginId);
} catch (ClassNotFoundException e) {
Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " was not found, distributed cache clearing will be disabled", module);
} catch (InstantiationException e) {
Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " could not be instantiated, distributed cache clearing will be disabled", module);
} catch (IllegalAccessException e) {
Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " could not be accessed (illegal), distributed cache clearing will be disabled", module);
} catch (ClassCastException e) {
Debug.logWarning(e, "DistributedCacheClear class with name " + distributedCacheClearClassName + " does not implement the DistributedCacheClear interface, distributed cache clearing will be disabled", module);
}
}
try {
/*
安装enitty eca处理器
*/
Class eecahClass = loader.loadClass(ECA_HANDLER_CLASS_NAME);
this.entityEcaHandler = (EntityEcaHandler) eecahClass.newInstance();
this.entityEcaHandler.setDelegator(this);
} catch (ClassNotFoundException e) {
Debug.logWarning(e, "EntityEcaHandler class with name " + ECA_HANDLER_CLASS_NAME + " was not found, Entity ECA Rules will be disabled", module);
} catch (InstantiationException e) {
Debug.logWarning(e, "EntityEcaHandler class with name " + ECA_HANDLER_CLASS_NAME + " could not be instantiated, Entity ECA Rules will be disabled", module);
} catch (IllegalAccessException e) {
Debug.logWarning(e, "EntityEcaHandler class with name " + ECA_HANDLER_CLASS_NAME + " could not be accessed (illegal), Entity ECA Rules will be disabled", module);
} catch (ClassCastException e) {
Debug.logWarning(e, "EntityEcaHandler class with name " + ECA_HANDLER_CLASS_NAME + " does not implement the EntityEcaHandler interface, Entity ECA Rules will be disabled", module);
}
}
/** Gets the name of the server configuration that corresponds to this delegator
* @return server configuration name
*/
public String getDelegatorName() {
return this.delegatorName;
}
ModelReader.java
public static ModelReader getModelReader(String delegatorName) throws GenericEntityException {
/*
EntityConfigUtil将读取component\entity\config\entityengine.xml文件
*/
EntityConfigUtil.DelegatorInfo delegatorInfo = EntityConfigUtil.getDelegatorInfo(delegatorName);
if (delegatorInfo == null) {
throw new GenericEntityConfException("Could not find a delegator with the name " + delegatorName);
}
String tempModelName = delegatorInfo.entityModelReader;
ModelReader reader = (ModelReader) readers.get(tempModelName);
if (reader == null) { // don't want to block here
synchronized (ModelReader.class) {
// must check if null again as one of the blocked threads can still enter
reader = (ModelReader) readers.get(tempModelName);
if (reader == null) {
/*
1:读取entityengine.xml定义的model文件
2:读取ofbiz-component.xml取到的model文件
*/
reader = new ModelReader(tempModelName);
// preload caches...
/*
1:加载所有的entity
每个entity对应一个ModelEntity对象
2:系统默认,每个entity将自动加上:lastUpdatedStamp,lastUpdatedTxStamp
,createdStamp,createdStamp,
这些是不需要在entitymodel.xml中定义的
3:ofbiz3中entitymodel.xml中每个node将会对应一个对象.
比如:
<field name="budgetId" type="id-ne"></field>
对应ModelField对象
<relation type="many" rel-entity-name="BudgetRevision">
对应 ModelRelation 对象
<index name="GLACCT_UNQCD" unique="true">
<index-field name="accountCode"/>
</index>
对应 ModelIndex 对象
等等
*/
reader.getEntityCache();
readers.put(tempModelName, reader);
}
}
}
return reader;
}