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/05/19 18:49:36 UTC

[isis] branch master updated: ISIS-2677: recursively lookup the type hierarchy for layout candidate files

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 1cb644e  ISIS-2677: recursively lookup the type hierarchy for layout candidate files
1cb644e is described below

commit 1cb644eba95ec13540be402a3adfe57a7eb1fe1e
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed May 19 20:49:17 2021 +0200

    ISIS-2677: recursively lookup the type hierarchy for layout candidate
    files
---
 .../commons/internal/resources/_Resources.java     |   2 +-
 .../services/grid/GridLoaderServiceDefault.java    | 116 ++++++++++++---------
 ...dLoaderServiceDefault_resourceNameFor_Test.java |  54 ++++++----
 .../JavaLangStringEntity.layout.xml}               |   0
 4 files changed, 105 insertions(+), 67 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Resources.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Resources.java
index a3d9454..a45804c 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Resources.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Resources.java
@@ -57,7 +57,7 @@ public final class _Resources {
      * @param resourceName
      * @return An input stream for reading the resource, or null if the resource could not be found.
      */
-    public static InputStream load(
+    public static @Nullable InputStream load(
             final @NonNull Class<?> contextClass,
             final @NonNull String resourceName) {
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
index 2689b75..56a1074 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
@@ -19,11 +19,12 @@
 package org.apache.isis.core.metamodel.services.grid;
 
 import java.io.IOException;
-import java.net.URL;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Named;
 
@@ -36,12 +37,16 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.layout.grid.Grid;
 import org.apache.isis.applib.services.grid.GridLoaderService;
 import org.apache.isis.applib.services.message.MessageService;
-import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.reflection._Reflect;
+import org.apache.isis.commons.internal.reflection._Reflect.InterfacePolicy;
 import org.apache.isis.commons.internal.resources._Resources;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 
+import lombok.NonNull;
 import lombok.Value;
+import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Service
@@ -62,13 +67,20 @@ public class GridLoaderServiceDefault implements GridLoaderService {
         private final String layoutIfAny;
     }
 
+    @Value
+    static class XmlAndResourceName {
+        private final @NonNull String xmlContent;
+        private final @NonNull String resourceName;
+    }
+
+
     // for better logging messages (used only in prototyping mode)
     private final Map<DomainClassAndLayout, String> badXmlByDomainClassAndLayout = _Maps.newHashMap();
 
     @Value
     static class DomainClassAndLayoutAndXml {
         private final DomainClassAndLayout domainClassAndLayout;
-        private final String xml;
+        private final XmlAndResourceName xml;
     }
 
     // cache (used only in prototyping mode)
@@ -81,13 +93,13 @@ public class GridLoaderServiceDefault implements GridLoaderService {
 
     @Override
     public void remove(final Class<?> domainClass) {
-        final String layoutIfAny = null;
-        final DomainClassAndLayout dcal = new DomainClassAndLayout(domainClass, layoutIfAny);
         if(!supportsReloading()) {
             return;
         }
+        final String layoutIfAny = null;
+        final DomainClassAndLayout dcal = new DomainClassAndLayout(domainClass, layoutIfAny);
         badXmlByDomainClassAndLayout.remove(dcal);
-        final String xml = loadXml(dcal);
+        final XmlAndResourceName xml = loadXml(dcal).orElse(null);
         if(xml == null) {
             return;
         }
@@ -96,13 +108,13 @@ public class GridLoaderServiceDefault implements GridLoaderService {
 
     @Override
     public boolean existsFor(final Class<?> domainClass) {
-        return resourceNameFor(new DomainClassAndLayout(domainClass, null)) != null;
+        return loadXml(new DomainClassAndLayout(domainClass, null)).isPresent();
     }
 
     @Override
     public Grid load(final Class<?> domainClass, final String layoutIfAny) {
         final DomainClassAndLayout dcal = new DomainClassAndLayout(domainClass, layoutIfAny);
-        final String xml = loadXml(dcal);
+        final XmlAndResourceName xml = loadXml(dcal).orElse(null);
         if(xml == null) {
             return null;
         }
@@ -116,7 +128,7 @@ public class GridLoaderServiceDefault implements GridLoaderService {
 
             final String badXml = badXmlByDomainClassAndLayout.get(dcal);
             if(badXml != null) {
-                if(Objects.equals(xml, badXml)) {
+                if(Objects.equals(xml.getXmlContent(), badXml)) {
                     // seen this before and already logged; just quit
                     return null;
                 } else {
@@ -127,7 +139,7 @@ public class GridLoaderServiceDefault implements GridLoaderService {
         }
 
         try {
-            final Grid grid = gridReader.loadGrid(xml);
+            final Grid grid = gridReader.loadGrid(xml.getXmlContent());
             grid.setDomainClass(domainClass);
             if(supportsReloading()) {
                 gridByDomainClassAndLayoutAndXml.put(dcalax, grid);
@@ -137,12 +149,12 @@ public class GridLoaderServiceDefault implements GridLoaderService {
 
             if(supportsReloading()) {
                 // save fact that this was bad XML, so that we don't log again if called next time
-                badXmlByDomainClassAndLayout.put(dcal, xml);
+                badXmlByDomainClassAndLayout.put(dcal, xml.getXmlContent());
             }
 
             // note that we don't blacklist if the file exists but couldn't be parsed;
             // the developer might fix so we will want to retry.
-            final String resourceName = resourceNameFor(dcal);
+            final String resourceName = xml.getResourceName();
             final String message = "Failed to parse " + resourceName + " file (" + ex.getMessage() + ")";
             if(supportsReloading()) {
                 messageService.warnUser(message);
@@ -153,45 +165,55 @@ public class GridLoaderServiceDefault implements GridLoaderService {
         }
     }
 
+    // -- HELPER
 
+    Optional<XmlAndResourceName> loadXml(final DomainClassAndLayout dcal) {
+        return _Reflect.streamTypeHierarchy(dcal.getDomainClass(), InterfacePolicy.EXCLUDE)
+        .map(type->loadXml(type, dcal.getLayoutIfAny()))
+        .filter(Optional::isPresent)
+        .findFirst()
+        .map(Optional::get);
+    }
 
-    private String loadXml(final DomainClassAndLayout dcal) {
-        final String resourceName = resourceNameFor(dcal);
-        if(resourceName == null) {
-            log.debug("Failed to locate layout file for '{}'", dcal.toString());
-            return null;
-        }
-        try {
-            return _Resources.loadAsStringUtf8(dcal.domainClass, resourceName);
-        } catch (IOException ex) {
-            log.debug(
-                    "Failed to locate file {} (relative to {}.class)",
-                    resourceName, dcal.domainClass.getName(), ex);
-            return null;
-        }
+    private Optional<XmlAndResourceName> loadXml(
+            final @NonNull Class<?> domainClass,
+            final @Nullable String layoutIfAny) {
+        return streamResourceNameCandidatesFor(domainClass, layoutIfAny)
+        .map(candidateResourceName->tryLoadXml(domainClass, candidateResourceName))
+        .filter(Optional::isPresent)
+        .findFirst()
+        .map(Optional::get);
     }
 
-    String resourceNameFor(final DomainClassAndLayout dcal) {
-        final List<String> candidateResourceNames = _Lists.newArrayList();
-        if(dcal.layoutIfAny != null) {
-            candidateResourceNames.add(
-                    String.format("%s-%s.layout.xml", dcal.domainClass.getSimpleName(), dcal.layoutIfAny));
-        }
-        candidateResourceNames.add(
-                String.format("%s.layout.xml", dcal.domainClass.getSimpleName()));
-        candidateResourceNames.add(
-                String.format("%s.layout.fallback.xml", dcal.domainClass.getSimpleName()));
-        for (final String candidateResourceName : candidateResourceNames) {
-            try {
-                final URL resource = _Resources.getResourceUrl(dcal.domainClass, candidateResourceName);
-                if (resource != null) {
-                    return candidateResourceName;
-                }
-            } catch(IllegalArgumentException ex) {
-                // continue
-            }
+    private Stream<String> streamResourceNameCandidatesFor(
+            final @NonNull Class<?> domainClass,
+            final @Nullable String layoutIfAny) {
+
+        val typeSimpleName = domainClass.getSimpleName();
+
+        return _Strings.isNotEmpty(layoutIfAny)
+                ? Stream.of(
+                        String.format("%s-%s.layout.xml", typeSimpleName, layoutIfAny),
+                        String.format("%s.layout.xml", typeSimpleName),
+                        String.format("%s.layout.fallback.xml", typeSimpleName))
+                : Stream.of(
+                        String.format("%s.layout.xml", typeSimpleName),
+                        String.format("%s.layout.fallback.xml", typeSimpleName));
+    }
+
+    private Optional<XmlAndResourceName> tryLoadXml(
+            final @NonNull Class<?> type,
+            final @NonNull String candidateResourceName) {
+        try {
+            return Optional.ofNullable(
+                    _Resources.loadAsStringUtf8(type, candidateResourceName))
+                    .map(xml->new XmlAndResourceName(xml, candidateResourceName));
+        } catch (IOException ex) {
+            log.error(
+                    "Failed to load layout file {} (relative to {}.class)",
+                    candidateResourceName, type.getName(), ex);
         }
-        return null;
+        return Optional.empty();
     }
 
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameFor_Test.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameFor_Test.java
index 90132bf..7077150 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameFor_Test.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameFor_Test.java
@@ -18,41 +18,57 @@
  */
 package org.apache.isis.core.metamodel.services.grid;
 
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.isis.core.metamodel.services.grid.GridLoaderServiceDefault.DomainClassAndLayout;
 
 public class GridLoaderServiceDefault_resourceNameFor_Test {
 
     private GridLoaderServiceDefault gridLoaderServiceDefault;
 
-    @Before
-    public void setUp() throws Exception {
+    @BeforeEach
+    void setUp() throws Exception {
         gridLoaderServiceDefault = new GridLoaderServiceDefault();
     }
 
     @Test
-    public void when_default_exists() {
-        final String s = gridLoaderServiceDefault.resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo.class, null));
-        Assert.assertThat(s, is(equalTo("Foo.layout.xml")));
+    void when_default_exists() {
+        assertEquals(
+                "Foo.layout.xml",
+                resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo.class, null)));
     }
 
     @Test
-    public void when_fallback_exists() {
-        final String s = gridLoaderServiceDefault.resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo2.class, null));
-        Assert.assertThat(s, is(equalTo("Foo2.layout.fallback.xml")));
+    void when_fallback_exists() {
+        assertEquals(
+                "Foo2.layout.fallback.xml",
+                resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo2.class, null)));
     }
+
     @Test
-    public void when_default_and_fallback_both_exist() {
-        final String s = gridLoaderServiceDefault.resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo3.class, null));
-        Assert.assertThat(s, is(equalTo("Foo3.layout.xml")));
+    void when_default_and_fallback_both_exist() {
+        assertEquals(
+                "Foo3.layout.xml",
+                resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo3.class, null)));
     }
+
     @Test
-    public void when_neither_exist() {
-        final String s = gridLoaderServiceDefault.resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo4.class, null));
-        Assert.assertNull(s);
+    void when_neither_exist() {
+        assertEquals(
+                (String)null,
+                resourceNameFor(new GridLoaderServiceDefault.DomainClassAndLayout(Foo4.class, null)));
+    }
+
+    // -- HELPER
+
+    private String resourceNameFor(DomainClassAndLayout dcal) {
+        return gridLoaderServiceDefault.loadXml(dcal)
+        .map(xml->xml.getResourceName())
+        .orElse(null);
     }
+
+
 }
\ No newline at end of file
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/types/javalang/strings/jdo/JavaLangStringJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/types/javalang/strings/persistence/JavaLangStringEntity.layout.xml
similarity index 100%
rename from examples/demo/domain/src/main/java/demoapp/dom/types/javalang/strings/jdo/JavaLangStringJdo.layout.xml
rename to examples/demo/domain/src/main/java/demoapp/dom/types/javalang/strings/persistence/JavaLangStringEntity.layout.xml