You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/09/08 07:37:09 UTC

[isis] 02/02: ISIS-3206: [Metamodel] refactor shadow facet generation logic into a MetaModelAnnotator

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/isis.git

commit d210fd999bef8d783b1b51b623b55f8e103166ee
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Sep 8 09:37:01 2022 +0200

    ISIS-3206: [Metamodel] refactor shadow facet generation logic into a
    MetaModelAnnotator
    
    - yet requires update of Inspect MM View
---
 .../services/metamodel/MetaModelAnnotator.java     |  17 +++
 .../services/metamodel/MetaModelExporter.java      | 143 +------------------
 .../metamodel/MetaModelServiceDefault.java         |  13 +-
 .../ShadowedFactetAttributeAnnotator.java          |  92 +++++++++++++
 .../services/metamodel/TitleAnnotator.java         |   9 +-
 .../core/metamodel/services/metamodel/_Util.java   | 153 +++++++++++++++++++++
 6 files changed, 273 insertions(+), 154 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelAnnotator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelAnnotator.java
index 637d2e6fd5..c134506299 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelAnnotator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelAnnotator.java
@@ -30,9 +30,13 @@ import org.apache.isis.schema.metamodel.v2.Action;
 import org.apache.isis.schema.metamodel.v2.Collection;
 import org.apache.isis.schema.metamodel.v2.DomainClassDto;
 import org.apache.isis.schema.metamodel.v2.Facet;
+import org.apache.isis.schema.metamodel.v2.MetamodelElement;
+import org.apache.isis.schema.metamodel.v2.MetamodelElement.Annotations;
 import org.apache.isis.schema.metamodel.v2.Param;
 import org.apache.isis.schema.metamodel.v2.Property;
 
+import lombok.val;
+
 /**
  * SPI that allows to add arbitrary meta data as
  * {@link org.apache.isis.schema.metamodel.v2.Annotation}s
@@ -58,6 +62,19 @@ public interface MetaModelAnnotator {
 
     void annotate(Collection collectionType, OneToManyAssociation collection);
 
+    /**
+     * creates and adds to its parent
+     */
+    default <T extends MetamodelElement> T createAnnotation(final T t, final String name, final String value) {
+        val titleAnnot = new org.apache.isis.schema.metamodel.v2.Annotation();
+        titleAnnot.setName(name);
+        titleAnnot.setValue(value);
+        val annots = new Annotations();
+        t.setAnnotations(annots);
+        annots.getAsList().add(titleAnnot);
+        return t;
+    }
+
     public interface ExporterConfig {
 
         default String abbrev(final @Nullable Class<?> cls) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
index a1132ce04b..62290553f7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
@@ -18,20 +18,14 @@
  */
 package org.apache.isis.core.metamodel.services.metamodel;
 
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.regex.Pattern;
 
-import org.apache.isis.applib.services.commanddto.processor.CommandDtoProcessor;
 import org.apache.isis.applib.services.metamodel.Config;
-import org.apache.isis.applib.spec.Specification;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -41,7 +35,6 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
-import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
@@ -397,46 +390,14 @@ class MetaModelExporter {
         return facetType;
     }
 
-    private void visitNonNullAttributes(final Facet facet, final BiConsumer<String, String> visitor) {
-        facet.visitAttributes((key, attributeObj)->{
-            if(attributeObj == null) {
-                return;
-            }
-            String str = asStr(attributeObj);
-            visitor.accept(key, str);
-        });
-    }
+
 
     private void addFacetAttributes(
             final Facet facet,
             final org.apache.isis.schema.metamodel.v2.Facet facetType,
             final Config config) {
-
-        visitNonNullAttributes(facet, (key, str)->
+        _Util.visitNonNullAttributes(facet, (key, str)->
             addAttribute(facetType, key, str));
-
-        if(config.isIncludeShadowedFacets()) {
-            facet.getSharedFacetRanking()
-            .ifPresent(ranking->{
-                ranking.getTopRank(facet.facetType())
-                .stream()
-                // skip the winner, as its not shadowed
-                .skip(1)
-                //.filter(shadowedFacet->shadowedFacet.equals(facet))
-                .forEach(shadowedFacet->{
-                    visitNonNullAttributes(shadowedFacet, (key, str)->{
-                        if(key.equals("precedence")) {
-                            return; // skip
-                        }
-                        addAttribute(facetType, key, String.format("%s (shadowed %s)",
-                                str,
-                                shadowedFacet.getClass().getName()));
-                    });
-                });
-            });
-
-        }
-
         sortFacetAttributes(facetType.getAttr());
     }
 
@@ -491,107 +452,7 @@ class MetaModelExporter {
         return specification.getBeanSort().isValue();
     }
 
-    private String asStr(final Object attributeObj) {
-        String str;
-        if(attributeObj instanceof Method) {
-            str = asStr((Method) attributeObj);
-        } else if(attributeObj instanceof String) {
-            str = asStr((String) attributeObj);
-        } else if(attributeObj instanceof Enum) {
-            str = asStr((Enum<?>) attributeObj);
-        } else if(attributeObj instanceof Class) {
-            str = asStr((Class<?>) attributeObj);
-        } else if(attributeObj instanceof Specification) {
-            str = asStr((Specification) attributeObj);
-        } else if(attributeObj instanceof Facet) {
-            str = asStr((Facet) attributeObj);
-        } else if(attributeObj instanceof MetaModelExportSupport) {
-            str = asStr((MetaModelExportSupport) attributeObj);
-        } else if(attributeObj instanceof Pattern) {
-            str = asStr((Pattern) attributeObj);
-        } else if(attributeObj instanceof CommandDtoProcessor) {
-            str = asStr((CommandDtoProcessor) attributeObj);
-        } else if(attributeObj instanceof ObjectSpecification) {
-            str = asStr((ObjectSpecification) attributeObj);
-        } else if(attributeObj instanceof ObjectMember) {
-            str = asStr((ObjectMember) attributeObj);
-        } else if(attributeObj instanceof List) {
-            str = asStr((List<?>) attributeObj);
-        } else if(attributeObj instanceof Object[]) {
-            str = asStr((Object[]) attributeObj);
-        } else  {
-            str = "" + attributeObj;
-        }
-        return str;
-    }
-
-    private String asStr(final String attributeObj) {
-        return _Strings.emptyToNull(attributeObj);
-    }
-
-    private String asStr(final Specification attributeObj) {
-        return attributeObj.getClass().getName();
-    }
-
-    private String asStr(final ObjectSpecification attributeObj) {
-        return attributeObj.getFullIdentifier();
-    }
-
-    private String asStr(final MetaModelExportSupport attributeObj) {
-        return attributeObj.toMetamodelString();
-    }
-
-    private String asStr(final CommandDtoProcessor attributeObj) {
-        return attributeObj.getClass().getName();
-    }
-
-    private String asStr(final Pattern attributeObj) {
-        return attributeObj.pattern();
-    }
-
-    private String asStr(final Facet attributeObj) {
-        return attributeObj.getClass().getName();
-    }
-
-    private String asStr(final ObjectMember attributeObj) {
-        return attributeObj.getId();
-    }
-
-    private String asStr(final Class<?> attributeObj) {
-        return attributeObj.getCanonicalName();
-    }
-
-    private String asStr(final Enum<?> attributeObj) {
-        return attributeObj.name();
-    }
-
-    private String asStr(final Method attributeObj) {
-        return attributeObj.toGenericString();
-    }
-
-    private String asStr(final Object[] list) {
-        if(list.length == 0) {
-            return null; // skip
-        }
-        List<String> strings = _Lists.newArrayList();
-        for (final Object o : list) {
-            String s = asStr(o);
-            strings.add(s);
-        }
-        return String.join(";", strings);
-    }
 
-    private String asStr(final List<?> list) {
-        if(list.isEmpty()) {
-            return null; // skip
-        }
-        List<String> strings = _Lists.newArrayList();
-        for (final Object o : list) {
-            String s = asStr(o);
-            strings.add(s);
-        }
-        return String.join(";", strings);
-    }
 
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index 331ec60c34..8f94c18df8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -42,7 +42,6 @@ import org.apache.isis.applib.services.metamodel.Config;
 import org.apache.isis.applib.services.metamodel.DomainMember;
 import org.apache.isis.applib.services.metamodel.DomainModel;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
-import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -226,11 +225,15 @@ public class MetaModelServiceDefault implements MetaModelService {
         /*TODO[ISIS-3206] refactor: ideally config would provide the list, but unfortunately
          * MetaModelAnnotator type is not know to Config, which lives in applib.
          */
-        val annotators = config.isIncludeTitleAnnotations()
-                ? (Iterable) Can.<MetaModelAnnotator>of(new TitleAnnotator(new ExporterConfig(){}))
-                : Can.empty();
+        val metaModelAnnotators = _Lists.<MetaModelAnnotator>newArrayList();
+        if(config.isIncludeTitleAnnotations()) {
+            metaModelAnnotators.add(new TitleAnnotator(new ExporterConfig(){}));
+        }
+        if(config.isIncludeShadowedFacets()) {
+            metaModelAnnotators.add(new ShadowedFactetAttributeAnnotator(new ExporterConfig(){}));
+        }
 
-        return new MetaModelExporter(specificationLoader, annotators)
+        return new MetaModelExporter(specificationLoader, metaModelAnnotators)
                 .exportMetaModel(config);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/ShadowedFactetAttributeAnnotator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/ShadowedFactetAttributeAnnotator.java
new file mode 100644
index 0000000000..eeb987bb38
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/ShadowedFactetAttributeAnnotator.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.services.metamodel;
+
+import java.util.Optional;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.schema.metamodel.v2.Action;
+import org.apache.isis.schema.metamodel.v2.Collection;
+import org.apache.isis.schema.metamodel.v2.DomainClassDto;
+import org.apache.isis.schema.metamodel.v2.Facet;
+import org.apache.isis.schema.metamodel.v2.FacetAttr;
+import org.apache.isis.schema.metamodel.v2.Param;
+import org.apache.isis.schema.metamodel.v2.Property;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Accessors;
+
+@RequiredArgsConstructor
+public class ShadowedFactetAttributeAnnotator implements MetaModelAnnotator {
+
+    @Getter(onMethod_={@Override}) @Accessors(fluent=true)
+    private final ExporterConfig config;
+
+    @Override
+    public void annotate(final DomainClassDto domainClass, final ObjectSpecification specification) {}
+    @Override
+    public void annotate(final Action actionType, final ObjectAction action) {}
+    @Override
+    public void annotate(final Param parameterType, final ObjectActionParameter parameter) {}
+    @Override
+    public void annotate(final Property propertyType, final OneToOneAssociation property) {}
+    @Override
+    public void annotate(final Collection collectionType, final OneToManyAssociation collection) {}
+
+    @Override
+    public void annotate(final Facet facetType, final org.apache.isis.core.metamodel.facetapi.Facet facet) {
+        facet.getSharedFacetRanking()
+        .ifPresent(ranking->{
+            ranking.getTopRank(facet.facetType())
+            .stream()
+            // skip the winner, as its not shadowed
+            .skip(1)
+            //.filter(shadowedFacet->shadowedFacet.equals(facet))
+            .forEach(shadowedFacet->{
+                _Util.visitNonNullAttributes(shadowedFacet, (attributeName, str)->{
+                    if(attributeName.equals("precedence")) {
+                        return; // skip
+                    }
+                    addAttributeAnnotation(facetType, attributeName, String.format("%s (shadowed %s)",
+                            str,
+                            shadowedFacet.getClass().getName()));
+                });
+            });
+        });
+    }
+
+    // -- HELPER
+
+    private void addAttributeAnnotation(final Facet facetType, final String attributeName, final String annotation) {
+        lookupByName(facetType, attributeName)
+        .ifPresent(facetAttr->{
+            createAnnotation(facetAttr, "@shadowed", annotation);
+        });
+    }
+
+    private Optional<FacetAttr> lookupByName(final Facet facetType, final String attributeName) {
+        return Optional.empty();
+    }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/TitleAnnotator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/TitleAnnotator.java
index 2357707368..d2dfe7ef6d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/TitleAnnotator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/TitleAnnotator.java
@@ -30,7 +30,6 @@ import org.apache.isis.schema.metamodel.v2.Collection;
 import org.apache.isis.schema.metamodel.v2.DomainClassDto;
 import org.apache.isis.schema.metamodel.v2.Facet;
 import org.apache.isis.schema.metamodel.v2.MetamodelElement;
-import org.apache.isis.schema.metamodel.v2.MetamodelElement.Annotations;
 import org.apache.isis.schema.metamodel.v2.Param;
 import org.apache.isis.schema.metamodel.v2.Property;
 
@@ -118,13 +117,7 @@ public class TitleAnnotator implements MetaModelAnnotator {
     }
 
     private <T extends MetamodelElement> T titleAnnotation(final T t, final String title) {
-        val titleAnnot = new org.apache.isis.schema.metamodel.v2.Annotation();
-        titleAnnot.setName("@title");
-        titleAnnot.setValue(title);
-        val annots = new Annotations();
-        t.setAnnotations(annots);
-        annots.getAsList().add(titleAnnot);
-        return t;
+        return createAnnotation(t, "@title", title);
     }
 
     private String titleSuffix(final boolean isMixedIn) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/_Util.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/_Util.java
new file mode 100644
index 0000000000..73e18a2002
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/_Util.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.services.metamodel;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.regex.Pattern;
+
+import org.apache.isis.applib.services.commanddto.processor.CommandDtoProcessor;
+import org.apache.isis.applib.spec.Specification;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+class _Util {
+
+    void visitNonNullAttributes(final Facet facet, final BiConsumer<String, String> visitor) {
+        facet.visitAttributes((key, attributeObj)->{
+            if(attributeObj == null) {
+                return;
+            }
+            String str = asStr(attributeObj);
+            visitor.accept(key, str);
+        });
+    }
+
+    String asStr(final Object attributeObj) {
+        String str;
+        if(attributeObj instanceof Method) {
+            str = asStr((Method) attributeObj);
+        } else if(attributeObj instanceof String) {
+            str = asStr((String) attributeObj);
+        } else if(attributeObj instanceof Enum) {
+            str = asStr((Enum<?>) attributeObj);
+        } else if(attributeObj instanceof Class) {
+            str = asStr((Class<?>) attributeObj);
+        } else if(attributeObj instanceof Specification) {
+            str = asStr((Specification) attributeObj);
+        } else if(attributeObj instanceof Facet) {
+            str = asStr((Facet) attributeObj);
+        } else if(attributeObj instanceof MetaModelExportSupport) {
+            str = asStr((MetaModelExportSupport) attributeObj);
+        } else if(attributeObj instanceof Pattern) {
+            str = asStr((Pattern) attributeObj);
+        } else if(attributeObj instanceof CommandDtoProcessor) {
+            str = asStr((CommandDtoProcessor) attributeObj);
+        } else if(attributeObj instanceof ObjectSpecification) {
+            str = asStr((ObjectSpecification) attributeObj);
+        } else if(attributeObj instanceof ObjectMember) {
+            str = asStr((ObjectMember) attributeObj);
+        } else if(attributeObj instanceof List) {
+            str = asStr((List<?>) attributeObj);
+        } else if(attributeObj instanceof Object[]) {
+            str = asStr((Object[]) attributeObj);
+        } else  {
+            str = "" + attributeObj;
+        }
+        return str;
+    }
+
+    // -- HELPER
+
+    private String asStr(final String attributeObj) {
+        return _Strings.emptyToNull(attributeObj);
+    }
+
+    private String asStr(final Specification attributeObj) {
+        return attributeObj.getClass().getName();
+    }
+
+    private String asStr(final ObjectSpecification attributeObj) {
+        return attributeObj.getFullIdentifier();
+    }
+
+    private String asStr(final MetaModelExportSupport attributeObj) {
+        return attributeObj.toMetamodelString();
+    }
+
+    private String asStr(final CommandDtoProcessor attributeObj) {
+        return attributeObj.getClass().getName();
+    }
+
+    private String asStr(final Pattern attributeObj) {
+        return attributeObj.pattern();
+    }
+
+    private String asStr(final Facet attributeObj) {
+        return attributeObj.getClass().getName();
+    }
+
+    private String asStr(final ObjectMember attributeObj) {
+        return attributeObj.getId();
+    }
+
+    private String asStr(final Class<?> attributeObj) {
+        return attributeObj.getCanonicalName();
+    }
+
+    private String asStr(final Enum<?> attributeObj) {
+        return attributeObj.name();
+    }
+
+    private String asStr(final Method attributeObj) {
+        return attributeObj.toGenericString();
+    }
+
+    private String asStr(final Object[] list) {
+        if(list.length == 0) {
+            return null; // skip
+        }
+        List<String> strings = _Lists.newArrayList();
+        for (final Object o : list) {
+            String s = asStr(o);
+            strings.add(s);
+        }
+        return String.join(";", strings);
+    }
+
+    private String asStr(final List<?> list) {
+        if(list.isEmpty()) {
+            return null; // skip
+        }
+        List<String> strings = _Lists.newArrayList();
+        for (final Object o : list) {
+            String s = asStr(o);
+            strings.add(s);
+        }
+        return String.join(";", strings);
+    }
+
+}