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/09/04 13:36:47 UTC

[isis] branch master updated: ISIS-2864: AsciiDocReaderService: dynamically fix all java source references

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 dee73cc  ISIS-2864: AsciiDocReaderService: dynamically fix all java source references
dee73cc is described below

commit dee73cc2f3cbb82d59c80739a1675eef41113bee
Author: andi-huber <ah...@apache.org>
AuthorDate: Sat Sep 4 15:36:39 2021 +0200

    ISIS-2864: AsciiDocReaderService: dynamically fix all java source
    references
    
    yet more a workaround, than a rigorous solution
---
 .../apache/isis/commons/internal/base/_Refs.java   |  5 +-
 .../_infra/resources/AsciiDocReaderService.java    | 72 ++++++++++++++++++----
 .../navigable/FileTreeNodeService.java             | 19 ++++--
 .../valuetypes/asciidoc/applib/value/AsciiDoc.java |  2 +-
 .../asciidoc/applib/value/Converter.java           | 52 ++++++++++------
 5 files changed, 111 insertions(+), 39 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java
index 6aa1276..72c4ba1 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java
@@ -198,8 +198,9 @@ public final class _Refs {
     public static final class StringReference {
         private @NonNull String value;
 
-        public String update(final @NonNull UnaryOperator<String> operator) {
-            return value = Objects.requireNonNull(operator.apply(value));
+        public StringReference update(final @NonNull UnaryOperator<String> operator) {
+            value = Objects.requireNonNull(operator.apply(value));
+            return this;
         }
 
         public boolean isSet(final String other) {
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocReaderService.java b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocReaderService.java
index 8639dc6..4e1ca97 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocReaderService.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocReaderService.java
@@ -18,11 +18,17 @@
  */
 package demoapp.dom._infra.resources;
 
+import java.util.stream.Collectors;
+
 import javax.inject.Named;
 
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.commons.internal.base._Refs;
+import org.apache.isis.commons.internal.base._Refs.StringReference;
+import org.apache.isis.commons.internal.base._Text;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.valuetypes.asciidoc.applib.value.AsciiDoc;
-import org.springframework.stereotype.Service;
 
 import lombok.RequiredArgsConstructor;
 import lombok.val;
@@ -36,31 +42,75 @@ public class AsciiDocReaderService {
     final ResourceReaderService resourceReaderService;
     final IsisConfiguration configuration;
 
-    public AsciiDoc readFor(Object anObject) {
+    public AsciiDoc readFor(final Object anObject) {
         return readFor(anObject.getClass());
     }
 
-    public AsciiDoc readFor(Object anObject, final String member) {
+    public AsciiDoc readFor(final Object anObject, final String member) {
         return readFor(anObject.getClass(), member);
     }
 
-    public AsciiDoc readFor(Class<?> aClass) {
+    public AsciiDoc readFor(final Class<?> aClass) {
         val adocResourceName = String.format("%s.adoc", aClass.getSimpleName());
-        val asciiDoc = readResourceAndReplaceProperties(aClass, adocResourceName);
-        return AsciiDoc.valueOfAdoc(asciiDoc);
+        val adocResource = readResource(aClass, adocResourceName);
+        return toAsciiDoc(adocResource, aClass);
     }
 
-    public AsciiDoc readFor(Class<?> aClass, final String member) {
+    public AsciiDoc readFor(final Class<?> aClass, final String member) {
         val adocResourceName = String.format("%s-%s.%s", aClass.getSimpleName(), member, "adoc");
-        val asciiDoc = readResourceAndReplaceProperties(aClass, adocResourceName);
-        return AsciiDoc.valueOfAdoc(asciiDoc);
+        val adocResource = readResource(aClass, adocResourceName);
+        return toAsciiDoc(adocResource, aClass);
     }
 
-    private String readResourceAndReplaceProperties(Class<?> aClass, String adocResourceName) {
-        val adoc = resourceReaderService.readResource(aClass, adocResourceName);
+    // -- HELPER
+
+    private StringReference readResource(final Class<?> aClass, final String adocResourceName) {
+        return _Refs.stringRef(resourceReaderService.readResource(aClass, adocResourceName));
+    }
+
+    private String replaceVersion(final String adoc) {
         return adoc.replace("{isis-version}",
                 configuration.getViewer().getWicket().getApplication().getVersion());
     }
 
+    private String replaceJavaSourceReferences(final String adoc) {
+        return _Text.getLines(adoc)
+        .stream()
+        .map(line->line.startsWith("include::")
+                        && line.contains(".java")
+                ? replaceJavaSourceReference(line)
+                : line
+        )
+        .collect(Collectors.joining("\n"));
+    }
+
+    //  "include::DemoHomePage.java" -> "include::{sourcedir}/DemoHomePage.java
+    private String replaceJavaSourceReference(final String line) {
+        val lineRef = _Refs.stringRef(line);
+        lineRef.cutAtIndexOfAndDrop("::");
+        val classFileSimpleName = lineRef.cutAtIndexOf(".java");
+        val remainder = lineRef.getValue();
+        return "include::{sourcedir}/" + classFileSimpleName + remainder;
+    }
+
+    // setting up the java source root relative to the current directory (application main)
+    //XXX dependent on the location of the 'main' class within the file system,
+    // if we ever want to improve on that, we should place a marker file on the project root,
+    // so we can search up the folder hierarchy on dynamically figure out how many ../
+    // actually are required
+    private String prependSource(final String adoc, final Class<?> aClass) {
+        val packagePath = aClass.getPackage().getName().replace('.', '/');
+        return ":sourcedir: ../../domain/src/main/java/" + packagePath + "\n\n" + adoc;
+    }
+
+    private AsciiDoc toAsciiDoc(final StringReference adocRef, final Class<?> aClass) {
+        return AsciiDoc.valueOfAdoc(
+                adocRef
+                .update(this::replaceVersion)
+                .update(this::replaceJavaSourceReferences)
+                .update(adoc->prependSource(adoc, aClass))
+                .getValue());
+    }
+
 
 }
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/properties/PropertyLayout/navigable/FileTreeNodeService.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/properties/PropertyLayout/navigable/FileTreeNodeService.java
index 0d6095b..f600eaf 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/properties/PropertyLayout/navigable/FileTreeNodeService.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/properties/PropertyLayout/navigable/FileTreeNodeService.java
@@ -19,6 +19,7 @@
 package demoapp.dom.domain.properties.PropertyLayout.navigable;
 
 import java.nio.file.FileSystems;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -42,12 +43,18 @@ public class FileTreeNodeService {
     final Provider<HttpSession> httpSessionProvider;
 
     public TreeNode<FileNodeVm> sessionTree() {
-        TreeNode<FileNodeVm> tree = (TreeNode<FileNodeVm>) httpSessionProvider.get().getAttribute(TreeNode.class.getName());
-        if(tree == null) {
-            tree = newTree();
-            httpSessionProvider.get().setAttribute(TreeNode.class.getName(), tree);
-        }
-        return tree;
+        val session = httpSessionProvider.get();
+        val key = TreeNode.class.getName();
+
+        return Optional
+            .ofNullable(session.getAttribute(key))
+            .map(TreeNode.class::isInstance)
+            .<TreeNode<FileNodeVm>>map(TreeNode.class::cast)
+            .orElseGet(()->{
+                val tree = newTree();
+                session.setAttribute(key, tree);
+                return tree;
+            });
     }
 //end::sessionTree[]
 
diff --git a/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/AsciiDoc.java b/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/AsciiDoc.java
index cc0a8fb..e383d35 100644
--- a/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/AsciiDoc.java
+++ b/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/AsciiDoc.java
@@ -83,7 +83,7 @@ public class AsciiDoc implements HasHtml, Serializable {
 
     @Override
     public String toString() {
-        return "AsciiDoc[length="+ adoc.length()+", html="+ adoc +"]";
+        return "AsciiDoc[length="+ adoc.length()+"]";
     }
 
 }
diff --git a/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/Converter.java b/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/Converter.java
index 76d3bcf..3a06410 100644
--- a/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/Converter.java
+++ b/valuetypes/asciidoc/applib/src/main/java/org/apache/isis/valuetypes/asciidoc/applib/value/Converter.java
@@ -18,11 +18,17 @@
  */
 package org.apache.isis.valuetypes.asciidoc.applib.value;
 
+import java.util.Optional;
+
 import org.asciidoctor.Asciidoctor;
-import org.asciidoctor.AttributesBuilder;
+import org.asciidoctor.Attributes;
 import org.asciidoctor.Options;
-import org.asciidoctor.OptionsBuilder;
 import org.asciidoctor.SafeMode;
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.commons.internal.base._Strings;
+
+import lombok.Getter;
 
 final class Converter {
 
@@ -50,28 +56,36 @@ final class Converter {
      * </pre>
      *
      * @param adoc - formatted input to be converted to HTML
+     * @param options - if {@code null} uses built-in default options
+     */
+    public static String adocToHtml(final @Nullable String adoc, final @Nullable Options options) {
+        return _Strings.isEmpty(adoc)
+                ? ""
+                : getAsciidoctor().convert(adoc,
+                    Optional
+                    .ofNullable(options)
+                    .orElseGet(Converter::getDefaultOptions));
+    }
+
+    /**
+     * Shortcut to {@link #adocToHtml(String, Options)} using default options.
      */
-    public static String adocToHtml(String adoc) {
-        if(asciidoctor==null) {
-            asciidoctor = Asciidoctor.Factory.create();
-            options = defaultOptions();
-        }
-        return asciidoctor.convert(adoc, options);
+    public static String adocToHtml(final String adoc) {
+        return adocToHtml(adoc, null);
     }
 
     // -- HELPER
 
-    private static Asciidoctor asciidoctor;
-    private static Options options;
+    @Getter(lazy = true)
+    private final static Asciidoctor asciidoctor = Asciidoctor.Factory.create();
 
-    private static Options defaultOptions() {
-        return OptionsBuilder.options()
-                .safe(SafeMode.UNSAFE)
-                .toFile(false)
-                .attributes(AttributesBuilder.attributes()
-                        .sourceHighlighter("prism")
-                        .get())
-                .get();
-    }
+    @Getter(lazy = true)
+    private final static Options defaultOptions = Options.builder()
+            .safe(SafeMode.UNSAFE)
+            .toFile(false)
+            .attributes(Attributes.builder()
+                    .sourceHighlighter("prism")
+                    .build())
+            .build();
 
 }