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; }

|