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 2021/06/11 20:16:41 UTC

[isis] branch master updated: ISIS-2736: Metamodel: add (diff friendly) download format ASCII (as a variant to XML)

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


The following commit(s) were added to refs/heads/master by this push:
     new 69f3aaf  ISIS-2736: Metamodel: add (diff friendly) download format ASCII (as a variant to XML)
69f3aaf is described below

commit 69f3aaf402138e28d3d94579a7deb0174749267e
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Jun 11 22:16:22 2021 +0200

    ISIS-2736: Metamodel: add (diff friendly) download format ASCII (as a
    variant to XML)
---
 .../metamodel/Object_downloadMetamodelXml.java     |   7 +-
 .../services/metamodel/MetaModelServiceMenu.java   | 214 ++++++++++++++++++---
 .../src/main/java/demoapp/dom/menubars.layout.xml  |   3 +-
 3 files changed, 187 insertions(+), 37 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/mixins/metamodel/Object_downloadMetamodelXml.java b/api/applib/src/main/java/org/apache/isis/applib/mixins/metamodel/Object_downloadMetamodelXml.java
index 2d657ad..2164292 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/mixins/metamodel/Object_downloadMetamodelXml.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/mixins/metamodel/Object_downloadMetamodelXml.java
@@ -111,16 +111,13 @@ public class Object_downloadMetamodelXml {
     /**
      * Defaults to the simple name of the domain object's class.
      */
-    @MemberSupport public String default0Act() {
+    @MemberSupport
+    public String default0Act() {
         return holder.getClass().getSimpleName();
     }
 
-
-
     @Inject MetaModelService metaModelService;
     @Inject MessageService messageService;
     @Inject JaxbService jaxbService;
 
-
-
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelServiceMenu.java b/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelServiceMenu.java
index 3c8b597..f26398a 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelServiceMenu.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelServiceMenu.java
@@ -20,12 +20,12 @@ package org.apache.isis.applib.services.metamodel;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.SortedSet;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import javax.activation.MimeType;
-import javax.activation.MimeTypeParseException;
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Named;
 
@@ -34,6 +34,7 @@ import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.applib.annotation.Optionality;
 import org.apache.isis.applib.annotation.Parameter;
 import org.apache.isis.applib.annotation.ParameterLayout;
@@ -41,10 +42,18 @@ import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.value.Clob;
+import org.apache.isis.applib.value.NamedWithMimeType.CommonMimeType;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.schema.metamodel.v2.Collection;
+import org.apache.isis.schema.metamodel.v2.DomainClassDto;
+import org.apache.isis.schema.metamodel.v2.FacetAttr;
+import org.apache.isis.schema.metamodel.v2.FacetHolder.Facets;
 import org.apache.isis.schema.metamodel.v2.MetamodelDto;
+import org.apache.isis.schema.metamodel.v2.Property;
+
+import lombok.val;
 
 /**
  *
@@ -65,17 +74,7 @@ public class MetaModelServiceMenu {
 
     public static abstract class ActionDomainEvent extends IsisModuleApplib.ActionDomainEvent<MetaModelServiceMenu> { }
 
-    final MimeType mimeTypeTextCsv;
-    final MimeType mimeTypeTextXml;
-
-    public MetaModelServiceMenu() {
-        try {
-            mimeTypeTextCsv = new MimeType("text", "csv");
-            mimeTypeTextXml = new MimeType("application", "xml");
-        } catch (final MimeTypeParseException ex) {
-            throw new RuntimeException(ex);
-        }
-    }
+    // -- CSV
 
     public static class DownloadMetaModelEvent extends ActionDomainEvent { }
 
@@ -96,18 +95,18 @@ public class MetaModelServiceMenu {
         final List<String> list = asList(domainMembers);
         final StringBuilder buf = asBuf(list);
 
-        return new Clob(
-                withSuffix(csvFileName, "csv"),
-                mimeTypeTextCsv, buf.toString().toCharArray());
+        return Clob.of(csvFileName, CommonMimeType.CSV, buf.toString());
 
         // ...
     }
 
-
+    @MemberSupport
     public String default0DownloadMetaModelCsv() {
         return "metamodel.csv";
     }
 
+    // -- XML
+
     public static class DownloadMetaModelXmlEvent extends ActionDomainEvent { }
     @Action(
             domainEvent = DownloadMetaModelXmlEvent.class,
@@ -121,9 +120,11 @@ public class MetaModelServiceMenu {
     public Clob downloadMetaModelXml(
             @ParameterLayout(named = ".xml file name")
             final String fileName,
+
             @ParameterLayout(named = "Packages",
             describedAs="Subset of the complete meta model, only including namespaces starting with given prefix")
             final List<String> namespaces,
+
             @ParameterLayout(named = "Ignore Interfaces")
             @Parameter(optionality=Optionality.MANDATORY)
             final boolean ignoreInterfaces
@@ -142,15 +143,16 @@ public class MetaModelServiceMenu {
             config = config.withIgnoreInterfaces();
         }
 
-
         final MetamodelDto metamodelDto =  metaModelService.exportMetaModel(config);
 
         final String xml = jaxbService.toXml(metamodelDto);
-        return new Clob(_Strings.asFileNameWithExtension(fileName,  ".xml"), "text/xml", xml);
+
+        return Clob.of(fileName, CommonMimeType.XML, xml);
 
         // ...
     }
 
+    @MemberSupport
     public String validateDownloadMetaModelXml(
             final String fileName, final List<String> packagePrefixes, final boolean ignoreInterfaces) {
         if(packagePrefixes == null || packagePrefixes.isEmpty()) {
@@ -159,10 +161,12 @@ public class MetaModelServiceMenu {
         return null;
     }
 
+    @MemberSupport
     public String default0DownloadMetaModelXml() {
         return "metamodel.xml";
     }
 
+    @MemberSupport
     public List<String> choices1DownloadMetaModelXml() {
         final DomainModel domainModel = metaModelService.getDomainModel();
         final List<DomainMember> export = domainModel.getDomainMembers();
@@ -182,10 +186,99 @@ public class MetaModelServiceMenu {
         return new ArrayList<>(namespaces);
     }
 
+    @MemberSupport
     public boolean default2DownloadMetaModelXml() {
         return true;
     }
 
+    // -- ASCII
+
+    public static class DownloadMetaModelAsciiEvent extends ActionDomainEvent { }
+    @Action(
+            domainEvent = DownloadMetaModelAsciiEvent.class,
+            semantics = SemanticsOf.NON_IDEMPOTENT, //disable client-side caching
+            restrictTo = RestrictTo.PROTOTYPING
+            )
+    @ActionLayout(
+            cssClassFa = "fa-download",
+            named = "Download Meta Model (Ascii)",
+            sequence="500.500.2")
+    public Clob downloadMetaModelAscii(
+            @ParameterLayout(named = ".txt file name")
+            final String fileName,
+
+            @ParameterLayout(named = "Packages",
+            describedAs="Subset of the complete meta model, only including namespaces starting with given prefix")
+            final List<String> namespaces,
+
+            @ParameterLayout(named = "Ignore Interfaces")
+            @Parameter(optionality=Optionality.MANDATORY)
+            final boolean ignoreInterfaces
+            ) {
+
+        Config config =
+                new Config()
+                .withIgnoreNoop()
+                .withIgnoreAbstractClasses()
+                .withIgnoreInterfaces()
+                .withIgnoreBuiltInValueTypes();
+        for (final String namespace : namespaces) {
+            config = config.withNamespacePrefix(namespace);
+        }
+        if(ignoreInterfaces) {
+            config = config.withIgnoreInterfaces();
+        }
+
+        final MetamodelDto metamodelDto =  metaModelService.exportMetaModel(config);
+
+        final StringBuffer ascii = toAscii(metamodelDto);
+
+        return Clob.of(fileName, CommonMimeType.TXT, ascii);
+
+        // ...
+    }
+
+    @MemberSupport
+    public String validateDownloadMetaModelAscii(
+            final String fileName, final List<String> packagePrefixes, final boolean ignoreInterfaces) {
+        if(packagePrefixes == null || packagePrefixes.isEmpty()) {
+            return "At least one package must be selected";
+        }
+        return null;
+    }
+
+    @MemberSupport
+    public String default0DownloadMetaModelAscii() {
+        return "metamodel.txt";
+    }
+
+    @MemberSupport
+    public List<String> choices1DownloadMetaModelAscii() {
+        final DomainModel domainModel = metaModelService.getDomainModel();
+        final List<DomainMember> export = domainModel.getDomainMembers();
+        final SortedSet<String> namespaces = _Sets.newTreeSet();
+        for (final DomainMember domainMember : export) {
+            final String namespace = domainMember.getNamespace();
+            final String[] split = namespace.split("[.]");
+            final StringBuilder buf = new StringBuilder();
+            for (final String part : split) {
+                if(buf.length() > 0) {
+                    buf.append(".");
+                }
+                buf.append(part);
+                namespaces.add(buf.toString());
+            }
+        }
+        return new ArrayList<>(namespaces);
+    }
+
+    @MemberSupport
+    public boolean default2DownloadMetaModelAscii() {
+        return true;
+    }
+
+    // -- HELPER
+
     private static StringBuilder asBuf(final List<String> list) {
         final StringBuilder buf = new StringBuilder();
         for (final String row : list) {
@@ -227,23 +320,82 @@ public class MetaModelServiceMenu {
                 .collect(Collectors.joining(","));
     }
 
+    private StringBuffer toAscii(MetamodelDto metamodelDto) {
+        val sb = new StringBuffer();
 
-    private static String withSuffix(String fileName, String suffix) {
-        if(!suffix.startsWith(".")) {
-            suffix = "." + suffix;
-        }
-        if(!fileName.endsWith(suffix)) {
-            fileName += suffix;
-        }
-        return fileName;
+        metamodelDto
+            .getDomainClassDto()
+            .forEach(typeDto->toAscii(typeDto, sb));
+
+        return sb;
+    }
+
+    private void toAscii(DomainClassDto typeDto, StringBuffer sb) {
+
+        sb.append(typeDto.getId()).append("\n");
+
+        toAscii("  * ", typeDto.getFacets(), sb);
+
+        Optional.ofNullable(typeDto.getProperties())
+        .map(props->props.getProp())
+        .ifPresent(list->list.forEach(propDto->toAscii(propDto, sb)));
+
+        Optional.ofNullable(typeDto.getCollections())
+        .map(colls->colls.getColl())
+        .ifPresent(list->list.forEach(collDto->toAscii(collDto, sb)));
+
+        Optional.ofNullable(typeDto.getActions())
+        .map(acts->acts.getAct())
+        .ifPresent(list->list.forEach(actDto->toAscii(actDto, sb)));
+
+    }
+
+    private void toAscii(final String prefix, @Nullable Facets facets, final StringBuffer sb) {
+
+        val attrPrefix = _Strings.of(prefix.length()-2, ' ') + "  | ";
+
+        Optional.ofNullable(facets)
+        .map(fac->fac.getFacet())
+        .ifPresent(list->list.forEach(facetDto->{
+            sb
+                .append(prefix)
+                .append(shorten(facetDto.getId()))
+                .append("\n");
+
+            Optional.ofNullable(facetDto.getAttr())
+            .ifPresent(attrs->attrs.forEach(attr->{
+                toAscii(attrPrefix, attr, sb);
+            }));
+
+        }));
     }
 
+    private void toAscii(String attrPrefix, FacetAttr attr, StringBuffer sb) {
+        sb.append(attrPrefix).append(attr.getName()).append('=').append(attr.getValue()).append("\n");
+    }
+
+    private void toAscii(Property propDto, StringBuffer sb) {
+        sb.append("+-- prop ").append(propDto.getId()).append("\n");
+        toAscii  ("      * ", propDto.getFacets(), sb);
+    }
+
+    private void toAscii(Collection collDto, StringBuffer sb) {
+        sb.append("+-- coll ").append(collDto.getId()).append("\n");
+        toAscii  ("      * ", collDto.getFacets(), sb);
+    }
+
+    private void toAscii(org.apache.isis.schema.metamodel.v2.Action actDto, StringBuffer sb) {
+        sb.append("+-- act  ").append(actDto.getId()).append("\n");
+        toAscii  ("      * ", actDto.getFacets(), sb);
+    }
+
+    private String shorten(String id) {
+        return id.replace("org.apache.isis.core.metamodel.facets", "..facets");
+    }
 
     // ...
 
-    @Inject
-    MetaModelService metaModelService;
-    @Inject
-    JaxbService jaxbService;
+    @Inject MetaModelService metaModelService;
+    @Inject JaxbService jaxbService;
 
 }
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml
index 04061a8..46e809a 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml
@@ -286,8 +286,9 @@ For latest we use: https://raw.githubusercontent.com/apache/isis/master/antora/s
             </mb3:section>
             <mb3:section>
                 <mb3:named>Meta Model and Features</mb3:named>
-                <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelXml"/>
+                <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelAscii"/>
                 <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelCsv"/>
+                <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelXml"/>
                 <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allNamespaces"/>
                 <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allTypes"/>
                 <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allActions"/>