You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2023/01/28 07:09:33 UTC

[causeway] branch master updated: CAUSEWAY-3344: diagram improvements

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/master by this push:
     new 454a104ba2 CAUSEWAY-3344: diagram improvements
454a104ba2 is described below

commit 454a104ba2c5c622f27bc19d47a166b656aa8fc7
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jan 28 08:09:27 2023 +0100

    CAUSEWAY-3344: diagram improvements
    
    - consolidate association relations if these share the same end points
    (objects)
    
    - don't register relations that cross namespace boundaries
---
 .../docgen/topics/domainobjects/ObjectGraph.java   | 110 +++++++++++++++++----
 1 file changed, 93 insertions(+), 17 deletions(-)

diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/domainobjects/ObjectGraph.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/domainobjects/ObjectGraph.java
index 8ac18b572b..6de11bfc48 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/domainobjects/ObjectGraph.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/domainobjects/ObjectGraph.java
@@ -81,16 +81,26 @@ class ObjectGraph {
                             || elementType.isAbstract()) {
                         val referencedObj = registerObject(elementType);
 
-                        val thisCls = objSpec.getLogicalType().getCorrespondingClass();
-                        val refCls = elementType.getLogicalType().getCorrespondingClass();
-                        if(thisCls.equals(refCls)
-                                || !refCls.isAssignableFrom(thisCls)) {
-                            // we found a 1-x relation
-                            registerRelation(
-                                    ass.isOneToOneAssociation()
-                                        ? ObjectGraph.Relation.RelationType.ONE_TO_ONE
-                                        : ObjectGraph.Relation.RelationType.ONE_TO_MANY,
-                                    obj.id, referencedObj.id, ass.getId());
+                        val thisType = objSpec.getLogicalType();
+                        val refType = elementType.getLogicalType();
+
+                        val thisNs = thisType.getNamespace();
+                        val refNs = refType.getNamespace();
+
+                        // only register association relations if they don't cross namespace boundaries
+                        // in other words: only include, if they share the same namespace
+                        if(thisNs.equals(refNs)) {
+                            val thisCls = thisType.getCorrespondingClass();
+                            val refCls = refType.getCorrespondingClass();
+                            if(thisCls.equals(refCls)
+                                    || !refCls.isAssignableFrom(thisCls)) {
+                                // we found a 1-x relation
+                                registerRelation(
+                                        ass.isOneToOneAssociation()
+                                            ? ObjectGraph.Relation.RelationType.ONE_TO_ONE
+                                            : ObjectGraph.Relation.RelationType.ONE_TO_MANY,
+                                        obj.id, referencedObj.id, ass.getId());
+                            }
                         }
 
                     }
@@ -106,11 +116,66 @@ class ObjectGraph {
                 final String fromId,
                 final String toId,
                 final String label) {
-            val relation = new ObjectGraph.Relation(relationType, fromId, toId, label);
+            val relation = new ObjectGraph.Relation(relationType, fromId, toId, label, "");
             relations.add(relation);
             return relation;
         }
 
+        public void consolidateAssociationRelations() {
+
+            // collect association-relations into a list-multi-map,
+            // where each key references a list of relations that need to be merged into one
+            final ListMultimap<String, ObjectGraph.Relation> shared = _Multimaps.newListMultimap();
+            relations.stream()
+                .filter(ObjectGraph.Relation::isAssociation)
+                .forEach(ass->{
+                    shared.putElement(ass.toId + " " + ass.fromId, ass);
+                });
+
+            relations.removeIf(ObjectGraph.Relation::isAssociation);
+
+            shared.forEach((key, list) -> {
+                val merged = list.stream().reduce((a, b)->new ObjectGraph.Relation(
+                        ObjectGraph.Relation.RelationType.MERGED_ASSOCIATIONS,
+                        a.fromId, a.toId,
+                        a.labelFormatted() + "," + b.labelFormatted(), ""));
+                merged.ifPresent(relations::add);
+            });
+
+            consolidateBidirRelations();
+        }
+
+        private void consolidateBidirRelations() {
+
+            // collect association-relations into a list-multi-map,
+            // where each key references a list of relations that need to be merged into one;
+            // we are using a sorted key where relation direction does not matter
+            final ListMultimap<String, ObjectGraph.Relation> shared = _Multimaps.newListMultimap();
+            relations.stream()
+                .filter(ObjectGraph.Relation::isAssociation)
+                .filter(ass->!ass.toId.equals(ass.fromId)) // exclude self referencing relations
+                .forEach(ass->{
+                    if(ass.fromId.compareTo(ass.toId)>0) {
+                        shared.putElement(ass.toId + " " + ass.fromId, ass);
+                    } else {
+                        shared.putElement(ass.fromId + " " + ass.toId, ass);
+                    }
+                });
+
+            shared.forEach((key, list) -> {
+                if(list.size()==2) {
+                    relations.removeAll(list);
+                    val a = list.get(0);
+                    val b = list.get(1);
+                    relations.add(new ObjectGraph.Relation(
+                            ObjectGraph.Relation.RelationType.BIDIR_ASSOCIATION,
+                            a.fromId, a.toId,
+                            a.labelFormatted(), b.labelFormatted()));
+                }
+            });
+        }
+
+
         public void createInheritanceRelations() {
 
             final Set<ObjectGraph.Relation> inheritanceRelations = new HashSet<>();
@@ -129,7 +194,7 @@ class ObjectGraph {
                         // we found an inheritance relation
                         val relation = new ObjectGraph.Relation(
                                 ObjectGraph.Relation.RelationType.INHERITANCE,
-                                o1.id, o2.id, "");
+                                o1.id, o2.id, "", "");
                         inheritanceRelations.add(relation);
                     }
                 }
@@ -176,18 +241,30 @@ class ObjectGraph {
         public static enum RelationType {
             ONE_TO_ONE,
             ONE_TO_MANY,
-            INHERITANCE,
+            MERGED_ASSOCIATIONS,
+            BIDIR_ASSOCIATION,
+            INHERITANCE;
+            public boolean isAssociation() { return this!=INHERITANCE; }
         }
         private final RelationType relationType;
         private final String fromId;
         private final String toId;
         private final String label;
+        private final String label2;
+        public String labelFormatted() {
+            return relationType==RelationType.ONE_TO_MANY
+                    ? String.format("[%s]", label)
+                    : label;
+        }
+        public boolean isAssociation() { return relationType.isAssociation(); }
         public String render() {
             switch(relationType) {
             case ONE_TO_ONE:
-                return String.format("%s -> %s : %s", fromId, toId, label);
             case ONE_TO_MANY:
-                return String.format("%s -> %s : [%s]", fromId, toId, label);
+            case MERGED_ASSOCIATIONS:
+                return String.format("%s -> \"%s\" %s", fromId, labelFormatted(), toId);
+            case BIDIR_ASSOCIATION:
+                return String.format("%s \"%s\" -- \"%s\" %s", fromId, label, label2, toId);
             case INHERITANCE:
                 return String.format("%s --|> %s", fromId, toId);
             }
@@ -266,6 +343,7 @@ class ObjectGraph {
 
         });
 
+        context.consolidateAssociationRelations();
         context.createInheritanceRelations();
 
         context.getRelations().stream()
@@ -282,6 +360,4 @@ class ObjectGraph {
         return plantuml;
     }
 
-
-
 }