This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new 5dd891d634 Let ModelReader and ModelGroupReader reload their model in
place
5dd891d634 is described below
commit 5dd891d634cfe662614dc9155c2b831ff001bf58
Author: Mridul Pathak <[email protected]>
AuthorDate: Sun Nov 1 14:19:00 2026 +0530
Let ModelReader and ModelGroupReader reload their model in place
ModelGroupReader loaded its entity-group map from its constructor through
the overridable getGroupCache, a this-escape. getModelGroupReader now loads the
map before publishing the reader, as getModelReader already does for
ModelReader, and the constructor only collects the resources.
Both readers get a public reload method that builds the new model on the
side and swaps it in only once it is complete, so lookups keep using the
previous model while it runs and still use it if the definitions cannot be
loaded. ModelReader now builds its entity cache in a separate map that only the
loading thread sees, answering the calls back into the reader made while it
loads, such as those from ModelViewEntity.populateFields, from that map.
---
.../ofbiz/entity/model/ModelGroupReader.java | 136 +++---
.../org/apache/ofbiz/entity/model/ModelReader.java | 480 +++++++++++----------
2 files changed, 330 insertions(+), 286 deletions(-)
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
index 9d4d1aa8fc..d287a29333 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelGroupReader.java
@@ -58,7 +58,8 @@ public class ModelGroupReader implements Serializable {
private volatile Map<String, String> groupCache = null;
private Set<String> groupNames = null;
- private List<ResourceHandler> entityGroupResourceHandlers = new
LinkedList<>();
+ private final String delegatorName;
+ private final List<ResourceHandler> entityGroupResourceHandlers = new
LinkedList<>();
public static ModelGroupReader getModelGroupReader(String delegatorName)
throws GenericEntityConfException {
DelegatorElement delegatorInfo =
EntityConfig.getInstance().getDelegator(delegatorName);
@@ -71,12 +72,16 @@ public class ModelGroupReader implements Serializable {
ModelGroupReader reader = READERS.get(tempModelName);
if (reader == null) {
- reader = READERS.putIfAbsentAndGet(tempModelName, new
ModelGroupReader(delegatorName, tempModelName));
+ reader = new ModelGroupReader(delegatorName, tempModelName);
+ // preload caches...
+ reader.getGroupCache(delegatorName);
+ reader = READERS.putIfAbsentAndGet(tempModelName, reader);
}
return reader;
}
public ModelGroupReader(String delegatorName, String modelName) throws
GenericEntityConfException {
+ this.delegatorName = delegatorName;
EntityGroupReader entityGroupReaderInfo =
EntityConfig.getInstance().getEntityGroupReader(modelName);
if (entityGroupReaderInfo == null) {
@@ -93,9 +98,6 @@ public class ModelGroupReader implements Serializable {
this.entityGroupResourceHandlers.add(componentResourceInfo.createResourceHandler());
}
}
-
- // preload caches...
- getGroupCache(delegatorName);
}
/**
@@ -108,69 +110,83 @@ public class ModelGroupReader implements Serializable {
synchronized (ModelGroupReader.class) {
// must check if null again as one of the blocked threads can
still enter
if (this.groupCache == null) {
- // build into locals and publish only once complete, so
readers never see a partial map
- Map<String, String> newGroupCache = new HashMap<>();
- Set<String> newGroupNames = new TreeSet<>();
+ try {
+ loadGroupCache(delegatorName);
+ } catch (GenericConfigException e) {
+ Debug.logError(e, "Error loading entity group model",
MODULE);
+ return null;
+ }
+ }
+ }
+ }
+ return this.groupCache;
+ }
- UtilTimer utilTimer = new UtilTimer();
- // utilTimer.timerString("[ModelGroupReader.getGroupCache]
Before getDocument");
+ /**
+ * Re-reads the entity group definitions and replaces the group cache once
they are fully loaded. Lookups keep using
+ * the previous group cache until then, and still use it if the
definitions cannot be read.
+ * @throws GenericConfigException if an entity group resource cannot be
read
+ */
+ public void reload() throws GenericConfigException {
+ synchronized (ModelGroupReader.class) {
+ loadGroupCache(this.delegatorName);
+ }
+ }
- int i = 0;
- for (ResourceHandler entityGroupResourceHandler:
this.entityGroupResourceHandlers) {
- Document document = null;
+ // builds into locals and publishes only once complete, so readers never
see a partial map
+ private void loadGroupCache(String delegatorName) throws
GenericConfigException {
+ Map<String, String> newGroupCache = new HashMap<>();
+ Set<String> newGroupNames = new TreeSet<>();
- try {
- document =
entityGroupResourceHandler.getDocument();
- } catch (GenericConfigException e) {
- Debug.logError(e, "Error loading entity group
model", MODULE);
- }
- if (document == null) {
- return null;
- }
+ UtilTimer utilTimer = new UtilTimer();
+ // utilTimer.timerString("[ModelGroupReader.getGroupCache] Before
getDocument");
- //
utilTimer.timerString("[ModelGroupReader.getGroupCache] Before
getDocumentElement");
- Element docElement = document.getDocumentElement();
- if (docElement == null) {
- continue;
- }
- docElement.normalize();
-
- Node curChild = docElement.getFirstChild();
- if (curChild != null) {
-
utilTimer.timerString("[ModelGroupReader.getGroupCache] Before start of entity
loop");
- do {
- if (curChild.getNodeType() ==
Node.ELEMENT_NODE && "entity-group".equals(curChild.getNodeName())) {
- Element curEntity = (Element) curChild;
- String entityName =
UtilXml.checkEmpty(curEntity.getAttribute("entity")).intern();
- String groupName =
UtilXml.checkEmpty(curEntity.getAttribute("group")).intern();
-
- try {
- if (null ==
EntityConfig.getInstance().getDelegator(delegatorName).getGroupDataSource(groupName))
{
- Debug.logError("The declared group
name " + groupName
- + " has no corresponding
group-map in entityengine.xml: ", MODULE);
- }
- } catch (GenericEntityConfException e) {
- Debug.logWarning(e, "Exception thrown
while getting group name: ", MODULE);
- }
- newGroupNames.add(groupName);
- newGroupCache.put(entityName, groupName);
- // utilTimer.timerString(" After
entityEntityName -- " + i + " --");
- i++;
- }
- curChild = curChild.getNextSibling();
- } while (curChild != null);
- } else {
- Debug.logWarning("[ModelGroupReader.getGroupCache]
No child nodes found.", MODULE);
+ int i = 0;
+ for (ResourceHandler entityGroupResourceHandler:
this.entityGroupResourceHandlers) {
+ Document document = entityGroupResourceHandler.getDocument();
+ if (document == null) {
+ throw new GenericConfigException("Could not get document for "
+ entityGroupResourceHandler);
+ }
+
+ // utilTimer.timerString("[ModelGroupReader.getGroupCache] Before
getDocumentElement");
+ Element docElement = document.getDocumentElement();
+ if (docElement == null) {
+ continue;
+ }
+ docElement.normalize();
+
+ Node curChild = docElement.getFirstChild();
+ if (curChild != null) {
+ utilTimer.timerString("[ModelGroupReader.getGroupCache] Before
start of entity loop");
+ do {
+ if (curChild.getNodeType() == Node.ELEMENT_NODE &&
"entity-group".equals(curChild.getNodeName())) {
+ Element curEntity = (Element) curChild;
+ String entityName =
UtilXml.checkEmpty(curEntity.getAttribute("entity")).intern();
+ String groupName =
UtilXml.checkEmpty(curEntity.getAttribute("group")).intern();
+
+ try {
+ if (null ==
EntityConfig.getInstance().getDelegator(delegatorName).getGroupDataSource(groupName))
{
+ Debug.logError("The declared group name " +
groupName
+ + " has no corresponding group-map in
entityengine.xml: ", MODULE);
+ }
+ } catch (GenericEntityConfException e) {
+ Debug.logWarning(e, "Exception thrown while
getting group name: ", MODULE);
}
+ newGroupNames.add(groupName);
+ newGroupCache.put(entityName, groupName);
+ // utilTimer.timerString(" After entityEntityName --
" + i + " --");
+ i++;
}
- utilTimer.timerString("[ModelGroupReader.getGroupCache]
FINISHED - Total Entity-Groups: " + i + " FINISHED");
- // groupNames first: the volatile write of groupCache
makes both visible to readers that see the map
- this.groupNames = newGroupNames;
- this.groupCache = newGroupCache;
- }
+ curChild = curChild.getNextSibling();
+ } while (curChild != null);
+ } else {
+ Debug.logWarning("[ModelGroupReader.getGroupCache] No child
nodes found.", MODULE);
}
}
- return this.groupCache;
+ utilTimer.timerString("[ModelGroupReader.getGroupCache] FINISHED -
Total Entity-Groups: " + i + " FINISHED");
+ // groupNames first: the volatile write of groupCache makes both
visible to readers that see the map
+ this.groupNames = newGroupNames;
+ this.groupCache = newGroupCache;
}
/** Gets a group name based on a definition from the specified XML Entity
Group descriptor file.
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelReader.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelReader.java
index a7bb9e10b4..4fbf7d6174 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelReader.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelReader.java
@@ -61,6 +61,8 @@ public final class ModelReader implements Serializable {
private static final UtilCache<String, ModelReader> READERS =
UtilCache.createUtilCache("entity.ModelReader", 0, 0);
private volatile Map<String, ModelEntity> entityCache = null;
+ /** the cache being built, only set and read by the thread loading it
while it holds the ModelReader class lock */
+ private Map<String, ModelEntity> loadingCache = null;
private int numEntities = 0;
private int numViewEntities = 0;
@@ -102,8 +104,6 @@ public final class ModelReader implements Serializable {
private ModelReader(String modelName) throws GenericEntityException {
entityResourceHandlers = new LinkedList<>();
- resourceHandlerEntities = new HashMap<>();
- entityResourceHandlerMap = new HashMap<>();
EntityModelReader entityModelReaderInfo =
EntityConfig.getInstance().getEntityModelReader(modelName);
@@ -142,7 +142,7 @@ public final class ModelReader implements Serializable {
resourceHandlerEntityNames.add(entityName);
// check to see if entity with same name has already been read
- if (entityCache.containsKey(entityName) && !redefinedEntity) {
+ if (loadingCache.containsKey(entityName) && !redefinedEntity) {
Debug.logWarning("Entity " + entityName
+ " is defined more than once, most recent will over-write
"
+ "previous definition(s)", MODULE);
@@ -191,262 +191,290 @@ public final class ModelReader implements Serializable {
}
public Map<String, ModelEntity> getEntityCache() throws
GenericEntityException {
+ if (Thread.holdsLock(ModelReader.class) && loadingCache != null) {
+ // called back while this thread loads the cache, e.g. from
ModelViewEntity.populateFields: answer from the
+ // cache being built, which other threads never see
+ return loadingCache;
+ }
if (entityCache == null) { // don't want to block here
synchronized (ModelReader.class) {
// must check if null again as one of the blocked threads can
still enter
if (entityCache == null) { // now it's safe
- numEntities = 0;
- numViewEntities = 0;
- numFields = 0;
- numRelations = 0;
- numAutoRelations = 0;
+ entityCache = loadEntityCache();
+ }
+ }
+ }
+ return entityCache;
+ }
- entityCache = new HashMap<>();
- List<ModelViewEntity> tempViewEntityList = new
LinkedList<>();
- List<Element> tempExtendEntityElementList = new
LinkedList<>();
+ /**
+ * Re-reads the entity definitions and replaces the entity cache once they
are fully loaded. Lookups keep using the
+ * previous entity cache until then, and still use it if the definitions
cannot be loaded.
+ * @throws GenericEntityException if the entity definitions cannot be
loaded
+ */
+ public void reload() throws GenericEntityException {
+ synchronized (ModelReader.class) {
+ entityCache = loadEntityCache();
+ }
+ }
- UtilTimer utilTimer = new UtilTimer();
+ // builds into loadingCache and returns it only once complete, so readers
never see a partial map
+ private Map<String, ModelEntity> loadEntityCache() throws
GenericEntityException {
+ try {
+ numEntities = 0;
+ numViewEntities = 0;
+ numFields = 0;
+ numRelations = 0;
+ numAutoRelations = 0;
- for (ResourceHandler entityResourceHandler :
entityResourceHandlers) {
+ resourceHandlerEntities = new HashMap<>();
+ entityResourceHandlerMap = new HashMap<>();
+ loadingCache = new HashMap<>();
+ List<ModelViewEntity> tempViewEntityList = new LinkedList<>();
+ List<Element> tempExtendEntityElementList = new LinkedList<>();
- // utilTimer.timerString("Before getDocument in file "
+ entityFileName);
- Document document = null;
+ UtilTimer utilTimer = new UtilTimer();
- try {
- document = entityResourceHandler.getDocument();
- } catch (GenericConfigException e) {
- throw new GenericEntityConfException("Error
getting document from resource handler", e);
- }
- if (document == null) {
- throw new GenericEntityConfException("Could not
get document for " + entityResourceHandler.toString());
- }
+ for (ResourceHandler entityResourceHandler :
entityResourceHandlers) {
- // utilTimer.timerString("Before getDocumentElement in
" + entityResourceHandler.toString());
- Element docElement = document.getDocumentElement();
+ // utilTimer.timerString("Before getDocument in file " +
entityFileName);
+ Document document = null;
- if (docElement == null) {
- return null;
- }
- docElement.normalize();
- Node curChild = docElement.getFirstChild();
-
- ModelInfo def =
ModelInfo.createFromElements(ModelInfo.DEFAULT, docElement);
- int i = 0;
-
- if (curChild != null) {
- utilTimer.timerString("Before start of entity loop
in " + entityResourceHandler.toString());
- do {
- boolean isEntity =
"entity".equals(curChild.getNodeName());
- boolean isViewEntity =
"view-entity".equals(curChild.getNodeName());
- boolean isExtendEntity =
"extend-entity".equals(curChild.getNodeName());
-
- if ((isEntity || isViewEntity) &&
curChild.getNodeType() == Node.ELEMENT_NODE) {
- i++;
- ModelEntity modelEntity =
buildEntity(entityResourceHandler, (Element) curChild, i, def);
- // put the view entity in a list to get
ready for the second pass to populate fields...
- if (isViewEntity) {
-
tempViewEntityList.add((ModelViewEntity) modelEntity);
- } else {
-
entityCache.put(modelEntity.getEntityName(), modelEntity);
- }
- } else if (isExtendEntity &&
curChild.getNodeType() == Node.ELEMENT_NODE) {
- tempExtendEntityElementList.add((Element)
curChild);
- }
- curChild = curChild.getNextSibling();
- } while (curChild != null);
- } else {
- Debug.logWarning("No child nodes found.", MODULE);
- }
- utilTimer.timerString("Finished " +
entityResourceHandler.toString() + " - Total Entities: " + i + " FINISHED");
- }
+ try {
+ document = entityResourceHandler.getDocument();
+ } catch (GenericConfigException e) {
+ throw new GenericEntityConfException("Error getting
document from resource handler", e);
+ }
+ if (document == null) {
+ throw new GenericEntityConfException("Could not get
document for " + entityResourceHandler.toString());
+ }
- // all entity elements in, now go through extend-entity
elements and add their stuff
- for (Element extendEntityElement :
tempExtendEntityElementList) {
- String entityName =
UtilXml.checkEmpty(extendEntityElement.getAttribute("entity-name"));
- ModelEntity modelEntity = entityCache.get(entityName);
- if (modelEntity == null) {
- throw new GenericEntityConfException("Entity to
extend does not exist: " + entityName);
- }
- modelEntity.addExtendEntity(this, extendEntityElement);
- }
+ // utilTimer.timerString("Before getDocumentElement in " +
entityResourceHandler.toString());
+ Element docElement = document.getDocumentElement();
- // do a pass on all of the view entities now that all of
the entities have loaded and populate the fields
- while (!tempViewEntityList.isEmpty()) {
- int startSize = tempViewEntityList.size();
- Iterator<ModelViewEntity> mveIt =
tempViewEntityList.iterator();
- TEMP_VIEW_LOOP: while (mveIt.hasNext()) {
- ModelViewEntity curViewEntity = mveIt.next();
- for (ModelViewEntity.ModelMemberEntity mve :
curViewEntity.getAllModelMemberEntities()) {
- if
(!entityCache.containsKey(mve.getEntityName())) {
- continue TEMP_VIEW_LOOP;
- }
- }
- mveIt.remove();
- curViewEntity.populateFields(this);
- for (ModelViewEntity.ModelMemberEntity mve :
curViewEntity.getAllModelMemberEntities()) {
- ModelEntity me =
entityCache.get(mve.getEntityName());
- me.addViewEntity(curViewEntity);
+ if (docElement == null) {
+ throw new GenericEntityConfException("Could not get
document element for " + entityResourceHandler.toString());
+ }
+ docElement.normalize();
+ Node curChild = docElement.getFirstChild();
+
+ ModelInfo def =
ModelInfo.createFromElements(ModelInfo.DEFAULT, docElement);
+ int i = 0;
+
+ if (curChild != null) {
+ utilTimer.timerString("Before start of entity loop in " +
entityResourceHandler.toString());
+ do {
+ boolean isEntity =
"entity".equals(curChild.getNodeName());
+ boolean isViewEntity =
"view-entity".equals(curChild.getNodeName());
+ boolean isExtendEntity =
"extend-entity".equals(curChild.getNodeName());
+
+ if ((isEntity || isViewEntity) &&
curChild.getNodeType() == Node.ELEMENT_NODE) {
+ i++;
+ ModelEntity modelEntity =
buildEntity(entityResourceHandler, (Element) curChild, i, def);
+ // put the view entity in a list to get ready for
the second pass to populate fields...
+ if (isViewEntity) {
+ tempViewEntityList.add((ModelViewEntity)
modelEntity);
+ } else {
+ loadingCache.put(modelEntity.getEntityName(),
modelEntity);
}
- entityCache.put(curViewEntity.getEntityName(),
curViewEntity);
+ } else if (isExtendEntity && curChild.getNodeType() ==
Node.ELEMENT_NODE) {
+ tempExtendEntityElementList.add((Element)
curChild);
}
- if (tempViewEntityList.size() == startSize) {
- // Oops, the remaining views reference other
entities
- // that can't be found, or they reference other
views
- // that have some reference problem.
- break;
+ curChild = curChild.getNextSibling();
+ } while (curChild != null);
+ } else {
+ Debug.logWarning("No child nodes found.", MODULE);
+ }
+ utilTimer.timerString("Finished " +
entityResourceHandler.toString() + " - Total Entities: " + i + " FINISHED");
+ }
+
+ // all entity elements in, now go through extend-entity elements
and add their stuff
+ for (Element extendEntityElement : tempExtendEntityElementList) {
+ String entityName =
UtilXml.checkEmpty(extendEntityElement.getAttribute("entity-name"));
+ ModelEntity modelEntity = loadingCache.get(entityName);
+ if (modelEntity == null) {
+ throw new GenericEntityConfException("Entity to extend
does not exist: " + entityName);
+ }
+ modelEntity.addExtendEntity(this, extendEntityElement);
+ }
+
+ // do a pass on all of the view entities now that all of the
entities have loaded and populate the fields
+ while (!tempViewEntityList.isEmpty()) {
+ int startSize = tempViewEntityList.size();
+ Iterator<ModelViewEntity> mveIt =
tempViewEntityList.iterator();
+ TEMP_VIEW_LOOP: while (mveIt.hasNext()) {
+ ModelViewEntity curViewEntity = mveIt.next();
+ for (ModelViewEntity.ModelMemberEntity mve :
curViewEntity.getAllModelMemberEntities()) {
+ if (!loadingCache.containsKey(mve.getEntityName())) {
+ continue TEMP_VIEW_LOOP;
}
}
- if (!tempViewEntityList.isEmpty()) {
- StringBuilder sb = new StringBuilder("View entities
reference non-existant members:\n");
- Set<String> allViews = new HashSet<>();
- for (ModelViewEntity curViewEntity :
tempViewEntityList) {
- allViews.add(curViewEntity.getEntityName());
- }
- for (ModelViewEntity curViewEntity :
tempViewEntityList) {
- Set<String> perViewMissingEntities = new
HashSet<>();
- Iterator<ModelViewEntity.ModelMemberEntity> mmeIt
= curViewEntity.getAllModelMemberEntities().iterator();
- while (mmeIt.hasNext()) {
- ModelViewEntity.ModelMemberEntity mme =
mmeIt.next();
- String memberEntityName = mme.getEntityName();
- if
(!entityCache.containsKey(memberEntityName)) {
- // this member is not a real entity
- // check to see if it is a view
- if (!allViews.contains(memberEntityName)) {
- // not a view, it's a real missing
entity
-
perViewMissingEntities.add(memberEntityName);
- }
- }
- }
- for (String perViewMissingEntity :
perViewMissingEntities) {
-
sb.append("\t[").append(curViewEntity.getEntityName()).append("] missing member
entity [")
-
.append(perViewMissingEntity).append("]\n");
+ mveIt.remove();
+ curViewEntity.populateFields(this);
+ for (ModelViewEntity.ModelMemberEntity mve :
curViewEntity.getAllModelMemberEntities()) {
+ ModelEntity me = loadingCache.get(mve.getEntityName());
+ me.addViewEntity(curViewEntity);
+ }
+ loadingCache.put(curViewEntity.getEntityName(),
curViewEntity);
+ }
+ if (tempViewEntityList.size() == startSize) {
+ // Oops, the remaining views reference other entities
+ // that can't be found, or they reference other views
+ // that have some reference problem.
+ break;
+ }
+ }
+ if (!tempViewEntityList.isEmpty()) {
+ StringBuilder sb = new StringBuilder("View entities reference
non-existant members:\n");
+ Set<String> allViews = new HashSet<>();
+ for (ModelViewEntity curViewEntity : tempViewEntityList) {
+ allViews.add(curViewEntity.getEntityName());
+ }
+ for (ModelViewEntity curViewEntity : tempViewEntityList) {
+ Set<String> perViewMissingEntities = new HashSet<>();
+ Iterator<ModelViewEntity.ModelMemberEntity> mmeIt =
curViewEntity.getAllModelMemberEntities().iterator();
+ while (mmeIt.hasNext()) {
+ ModelViewEntity.ModelMemberEntity mme = mmeIt.next();
+ String memberEntityName = mme.getEntityName();
+ if (!loadingCache.containsKey(memberEntityName)) {
+ // this member is not a real entity
+ // check to see if it is a view
+ if (!allViews.contains(memberEntityName)) {
+ // not a view, it's a real missing entity
+ perViewMissingEntities.add(memberEntityName);
}
-
}
- throw new GenericEntityConfException(sb.toString());
+ }
+ for (String perViewMissingEntity : perViewMissingEntities)
{
+
sb.append("\t[").append(curViewEntity.getEntityName()).append("] missing member
entity [")
+ .append(perViewMissingEntity).append("]\n");
}
- // auto-create relationships
- Set<String> orderedMessages = new TreeSet<>();
- for (String curEntityName : new
TreeSet<>(this.getEntityNames())) {
- ModelEntity curModelEntity =
this.getModelEntity(curEntityName);
- if (curModelEntity instanceof ModelViewEntity) {
- Debug.logVerbose("for view-entities auto-create
relationships for all member-entity"
- + "relationships that have all
corresponding fields in the view-entity...", MODULE);
- } else {
- // for entities auto-create many relationships for
all type one relationships
- // just in case we add a new relation to the same
entity, keep in a separate
- // list and add them at the end
- List<ModelRelation> newSameEntityRelations = new
LinkedList<>();
-
- Iterator<ModelRelation> relationsIter =
curModelEntity.getRelationsIterator();
- while (relationsIter.hasNext()) {
- ModelRelation modelRelation =
relationsIter.next();
- if (("one".equals(modelRelation.getType())
- ||
"one-nofk".equals(modelRelation.getType()))
- && !modelRelation.isAutoRelation()) {
- ModelEntity relatedEnt = null;
- try {
- relatedEnt =
this.getModelEntity(modelRelation.getRelEntityName());
- } catch (GenericModelException e) {
- throw new GenericModelException(
- "Error getting related entity
[" + modelRelation.getRelEntityName()
- + "] definition from
entity [" + curEntityName + "]", e);
- }
- // create the new relationship even if one
exists so we can show what we are
- // looking for in the info message
- // don't do relationship to the same
entity, unless title is "Parent", then do a
- // "Child" automatically
- String title = modelRelation.getTitle();
- if
(curModelEntity.getEntityName().equals(relatedEnt.getEntityName()) &&
"Parent".equals(title)) {
- title = "Child";
- }
- String description = "";
- String type = "";
- String relEntityName =
curModelEntity.getEntityName();
- String fkName = "";
- ArrayList<ModelKeyMap> keyMaps = new
ArrayList<>();
- boolean isAutoRelation = true;
- Set<String> curEntityKeyFields = new
HashSet<>();
- for (ModelKeyMap curkm :
modelRelation.getKeyMaps()) {
- keyMaps.add(new
ModelKeyMap(curkm.getRelFieldName(), curkm.getFieldName()));
-
curEntityKeyFields.add(curkm.getFieldName());
- }
- keyMaps.trimToSize();
- // decide whether it should be one or many
by seeing if the key map represents
- // the complete pk of the relEntity
- if
(curModelEntity.containsAllPkFieldNames(curEntityKeyFields)) {
- // always use one-nofk, we don't want
auto-fks getting in for these automatic ones
- type = "one-nofk";
- // to keep it clean, remove any
additional keys that aren't part of the PK
- List<String> curPkFieldNames =
curModelEntity.getPkFieldNames();
- Iterator<ModelKeyMap> nrkmIter =
keyMaps.iterator();
- while (nrkmIter.hasNext()) {
- ModelKeyMap nrkm = nrkmIter.next();
- String checkField =
nrkm.getRelFieldName();
- if
(!curPkFieldNames.contains(checkField)) {
- nrkmIter.remove();
- }
- }
- } else {
- type = "many";
- }
- ModelRelation newRel =
ModelRelation.create(relatedEnt, description, type, title, relEntityName,
- fkName, keyMaps, isAutoRelation);
-
- ModelRelation existingRelation =
relatedEnt.getRelation(title + curModelEntity.getEntityName());
- if (existingRelation == null) {
- numAutoRelations++;
- if
(curModelEntity.getEntityName().equals(relatedEnt.getEntityName())) {
- newSameEntityRelations.add(newRel);
- } else {
- relatedEnt.addRelation(newRel);
- }
- } else {
- if (newRel.equals(existingRelation)) {
- // don't warn if the target
title+entity = current title+entity
- if (Debug.infoOn()
- && !(title +
curModelEntity.getEntityName()).equals(modelRelation.getTitle()
- +
modelRelation.getRelEntityName())) {
- String message = "Entity [" +
relatedEnt.getPackageName() + ":" + relatedEnt.getEntityName()
- + "] already has
identical relationship to entity [" + curModelEntity.getEntityName()
- + "] title [" + title
- + "]; would
auto-create: type [" + newRel.getType() + "] and fields ["
- +
newRel.keyMapString(",", "") + "]";
- orderedMessages.add(message);
- }
- } else {
- String message = "Existing
relationship with the same name, but different specs found from what would"
- + " be auto-created for
Entity [" + relatedEnt.getEntityName() + "] and relationship to entity ["
- +
curModelEntity.getEntityName() + "] title [" + title + "]; would auto-create:
type ["
- + newRel.getType() + "]
and fields [" + newRel.keyMapString(",", "") + "]";
- if (Debug.verboseOn()) {
- Debug.logVerbose(message,
MODULE);
- }
- }
+ }
+ throw new GenericEntityConfException(sb.toString());
+ }
+
+ // auto-create relationships
+ Set<String> orderedMessages = new TreeSet<>();
+ for (String curEntityName : new TreeSet<>(this.getEntityNames())) {
+ ModelEntity curModelEntity =
this.getModelEntity(curEntityName);
+ if (curModelEntity instanceof ModelViewEntity) {
+ Debug.logVerbose("for view-entities auto-create
relationships for all member-entity"
+ + "relationships that have all corresponding
fields in the view-entity...", MODULE);
+ } else {
+ // for entities auto-create many relationships for all
type one relationships
+ // just in case we add a new relation to the same entity,
keep in a separate
+ // list and add them at the end
+ List<ModelRelation> newSameEntityRelations = new
LinkedList<>();
+
+ Iterator<ModelRelation> relationsIter =
curModelEntity.getRelationsIterator();
+ while (relationsIter.hasNext()) {
+ ModelRelation modelRelation = relationsIter.next();
+ if (("one".equals(modelRelation.getType())
+ || "one-nofk".equals(modelRelation.getType()))
+ && !modelRelation.isAutoRelation()) {
+ ModelEntity relatedEnt = null;
+ try {
+ relatedEnt =
this.getModelEntity(modelRelation.getRelEntityName());
+ } catch (GenericModelException e) {
+ throw new GenericModelException(
+ "Error getting related entity [" +
modelRelation.getRelEntityName()
+ + "] definition from entity ["
+ curEntityName + "]", e);
+ }
+ // create the new relationship even if one exists
so we can show what we are
+ // looking for in the info message
+ // don't do relationship to the same entity,
unless title is "Parent", then do a
+ // "Child" automatically
+ String title = modelRelation.getTitle();
+ if
(curModelEntity.getEntityName().equals(relatedEnt.getEntityName()) &&
"Parent".equals(title)) {
+ title = "Child";
+ }
+ String description = "";
+ String type = "";
+ String relEntityName =
curModelEntity.getEntityName();
+ String fkName = "";
+ ArrayList<ModelKeyMap> keyMaps = new ArrayList<>();
+ boolean isAutoRelation = true;
+ Set<String> curEntityKeyFields = new HashSet<>();
+ for (ModelKeyMap curkm :
modelRelation.getKeyMaps()) {
+ keyMaps.add(new
ModelKeyMap(curkm.getRelFieldName(), curkm.getFieldName()));
+ curEntityKeyFields.add(curkm.getFieldName());
+ }
+ keyMaps.trimToSize();
+ // decide whether it should be one or many by
seeing if the key map represents
+ // the complete pk of the relEntity
+ if
(curModelEntity.containsAllPkFieldNames(curEntityKeyFields)) {
+ // always use one-nofk, we don't want auto-fks
getting in for these automatic ones
+ type = "one-nofk";
+ // to keep it clean, remove any additional
keys that aren't part of the PK
+ List<String> curPkFieldNames =
curModelEntity.getPkFieldNames();
+ Iterator<ModelKeyMap> nrkmIter =
keyMaps.iterator();
+ while (nrkmIter.hasNext()) {
+ ModelKeyMap nrkm = nrkmIter.next();
+ String checkField = nrkm.getRelFieldName();
+ if (!curPkFieldNames.contains(checkField))
{
+ nrkmIter.remove();
}
}
+ } else {
+ type = "many";
}
-
- if (!newSameEntityRelations.isEmpty()) {
- for (ModelRelation newRel :
newSameEntityRelations) {
- curModelEntity.addRelation(newRel);
+ ModelRelation newRel =
ModelRelation.create(relatedEnt, description, type, title, relEntityName,
+ fkName, keyMaps, isAutoRelation);
+
+ ModelRelation existingRelation =
relatedEnt.getRelation(title + curModelEntity.getEntityName());
+ if (existingRelation == null) {
+ numAutoRelations++;
+ if
(curModelEntity.getEntityName().equals(relatedEnt.getEntityName())) {
+ newSameEntityRelations.add(newRel);
+ } else {
+ relatedEnt.addRelation(newRel);
+ }
+ } else {
+ if (newRel.equals(existingRelation)) {
+ // don't warn if the target title+entity =
current title+entity
+ if (Debug.infoOn()
+ && !(title +
curModelEntity.getEntityName()).equals(modelRelation.getTitle()
+ +
modelRelation.getRelEntityName())) {
+ String message = "Entity [" +
relatedEnt.getPackageName() + ":" + relatedEnt.getEntityName()
+ + "] already has identical
relationship to entity [" + curModelEntity.getEntityName()
+ + "] title [" + title
+ + "]; would auto-create: type
[" + newRel.getType() + "] and fields ["
+ + newRel.keyMapString(",", "")
+ "]";
+ orderedMessages.add(message);
+ }
+ } else {
+ String message = "Existing relationship
with the same name, but different specs found from what would"
+ + " be auto-created for Entity ["
+ relatedEnt.getEntityName() + "] and relationship to entity ["
+ + curModelEntity.getEntityName() +
"] title [" + title + "]; would auto-create: type ["
+ + newRel.getType() + "] and fields
[" + newRel.keyMapString(",", "") + "]";
+ if (Debug.verboseOn()) {
+ Debug.logVerbose(message, MODULE);
+ }
}
}
}
}
- if (Debug.infoOn()) {
- for (String message : orderedMessages) {
- Debug.logInfo(message, MODULE);
+
+ if (!newSameEntityRelations.isEmpty()) {
+ for (ModelRelation newRel : newSameEntityRelations) {
+ curModelEntity.addRelation(newRel);
}
- Debug.logInfo("Finished loading entities; #Entities="
+ numEntities + " #ViewEntities="
- + numViewEntities + " #Fields=" + numFields +
" #Relationships=" + numRelations
- + " #AutoRelationships=" + numAutoRelations,
MODULE);
}
}
}
+ if (Debug.infoOn()) {
+ for (String message : orderedMessages) {
+ Debug.logInfo(message, MODULE);
+ }
+ Debug.logInfo("Finished loading entities; #Entities=" +
numEntities + " #ViewEntities="
+ + numViewEntities + " #Fields=" + numFields + "
#Relationships=" + numRelations
+ + " #AutoRelationships=" + numAutoRelations, MODULE);
+ }
+ return loadingCache;
+ } finally {
+ loadingCache = null;
}
- return entityCache;
}
/**