You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/05/31 18:39:36 UTC

[isis] 01/01: ISIS-2711: merges LazyTreeNode up into TreeNode

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

danhaywood pushed a commit to branch ISIS-2711
in repository https://gitbox.apache.org/repos/asf/isis.git

commit d761a00026e073d267f4bfb21ef790cf4acbd041
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Mon May 31 19:39:07 2021 +0100

    ISIS-2711: merges LazyTreeNode up into TreeNode
    
    because:
    * LazyTreeNode is the only implementation of TreeNode
    * value types should not be part of an inheritance hierarchy
---
 .../modules/ROOT/pages/2020/2.0.0-M3/mignotes.adoc |   2 +-
 .../isis/applib/graph/tree/LazyTreeNode.java       | 145 ------------------
 .../apache/isis/applib/graph/tree/TreeNode.java    | 168 +++++++++++++++++----
 .../treenode/TreeNodeValueSemanticsProvider.java   |   3 +-
 .../valuetypes/ValueTypeProviderForBuiltin.java    |   4 +-
 5 files changed, 144 insertions(+), 178 deletions(-)

diff --git a/antora/components/relnotes/modules/ROOT/pages/2020/2.0.0-M3/mignotes.adoc b/antora/components/relnotes/modules/ROOT/pages/2020/2.0.0-M3/mignotes.adoc
index 899388d..386f685 100644
--- a/antora/components/relnotes/modules/ROOT/pages/2020/2.0.0-M3/mignotes.adoc
+++ b/antora/components/relnotes/modules/ROOT/pages/2020/2.0.0-M3/mignotes.adoc
@@ -924,7 +924,7 @@ Note: Currently does not implement a Table Tree View but just a Tree View.
 public API is:
 
 * `TreeAdapter` (provides the parent/child relationship information between pojos to derive a tree-structure)
-* `TreeNode` (with `LazyTreeNode` as the default implementation)
+* `TreeNode`
 * `TreePath` (represents a coordinate-system to navigate any tree-structure)
 
 [source,java]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/graph/tree/LazyTreeNode.java b/api/applib/src/main/java/org/apache/isis/applib/graph/tree/LazyTreeNode.java
deleted file mode 100644
index 38b32a5..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/graph/tree/LazyTreeNode.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- *  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.applib.graph.tree;
-
-import java.util.Objects;
-import java.util.concurrent.atomic.LongAdder;
-import java.util.stream.Stream;
-
-import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.commons.internal.base._Lazy;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
-
-/**
- * @since 2.0 {@index}
- */
-@Value(semanticsProviderName="org.apache.isis.core.metamodel.facets.value.treenode.TreeNodeValueSemanticsProvider")
-public class LazyTreeNode<T> implements TreeNode<T> {
-
-    private final TreeState sharedState;
-    private final T value;
-    private final Class<? extends TreeAdapter<T>> treeAdapterClass;
-    private final _Lazy<TreeAdapter<T>> treeAdapter = _Lazy.of(this::newTreeAdapter);
-    private final _Lazy<TreePath> treePath = _Lazy.of(this::resolveTreePath);
-
-    public static <T> TreeNode<T> of(T value, Class<? extends TreeAdapter<T>> treeAdapterClass, TreeState sharedState) {
-        return new LazyTreeNode<T>(value, treeAdapterClass, sharedState);
-    }
-
-    protected LazyTreeNode(T value, Class<? extends TreeAdapter<T>> treeAdapterClass, TreeState sharedState) {
-        this.value = Objects.requireNonNull(value);
-        this.treeAdapterClass = Objects.requireNonNull(treeAdapterClass);
-        this.sharedState = sharedState;
-    }
-
-    @Override
-    public T getValue() {
-        return value;
-    }
-
-    @Override
-    public TreeNode<T> getParentIfAny() {
-        return treeAdapter().parentOf(getValue())
-                .map(this::toTreeNode)
-                .orElse(null);
-    }
-
-    @Override
-    public int getChildCount() {
-        return treeAdapter().childCountOf(value);
-    }
-
-    @Override
-    public Stream<TreeNode<T>> streamChildren() {
-        if(isLeaf()) {
-            return Stream.empty();
-        }
-        return treeAdapter().childrenOf(value)
-                .map(this::toTreeNode);
-    }
-
-    @Override
-    public Class<? extends TreeAdapter<T>> getTreeAdapterClass() {
-        return treeAdapterClass;
-    }
-
-    @Override
-    public TreePath getPositionAsPath() {
-        return treePath.get();
-    }
-
-    @Override
-    public TreeState getTreeState() {
-        return sharedState;
-    }
-
-    // -- HELPER
-
-    private TreeAdapter<T> newTreeAdapter() {
-        try {
-            return treeAdapterClass.newInstance();
-        } catch (InstantiationException | IllegalAccessException e) {
-            throw new IllegalArgumentException(
-                    String.format("failed to instantiate TreeAdapter '%s'", treeAdapterClass.getName()), e);
-        }
-    }
-
-    private TreeAdapter<T> treeAdapter() {
-        return treeAdapter.get();
-    }
-
-    private TreeNode<T> toTreeNode(T value){
-        return of(value, getTreeAdapterClass(), sharedState);
-    }
-
-    private TreePath resolveTreePath() {
-        final TreeNode<T> parent = getParentIfAny();
-        if(parent==null) {
-            return TreePath.root();
-        }
-        return parent.getPositionAsPath().append(indexWithinSiblings(parent));
-    }
-
-    /*
-     * @return zero based index
-     */
-    private int indexWithinSiblings(TreeNode<T> parent) {
-        final LongAdder indexOneBased = new LongAdder();
-
-        boolean found = parent.streamChildren()
-                .peek(__->indexOneBased.increment())
-                .anyMatch(this::isEqualTo);
-
-        if(!found) {
-            throw _Exceptions.unexpectedCodeReach();
-        }
-
-        return indexOneBased.intValue()-1;
-    }
-
-    private boolean isEqualTo(TreeNode<T> other) {
-        if(other==null) {
-            return false;
-        }
-        return Objects.equals(this.getValue(), other.getValue());
-    }
-
-
-
-}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/graph/tree/TreeNode.java b/api/applib/src/main/java/org/apache/isis/applib/graph/tree/TreeNode.java
index 79fa9a6..f030437 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/graph/tree/TreeNode.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/graph/tree/TreeNode.java
@@ -19,77 +19,134 @@
 package org.apache.isis.applib.graph.tree;
 
 import java.util.Iterator;
+import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.atomic.LongAdder;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
 import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Value;
 import org.apache.isis.applib.graph.Edge;
 import org.apache.isis.applib.graph.SimpleEdge;
 import org.apache.isis.applib.graph.Vertex;
+import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 /**
- * Fundamental building block of Tree structures. 
- * 
+ * Fundamental building block of Tree structures.
+ *
  * @since 2.0 {@index}
  *
  * @param <T> type constraint for values contained by this node
  */
-public interface TreeNode<T> extends Vertex<T> {
+@Value(semanticsProviderName="org.apache.isis.core.metamodel.facets.value.treenode.TreeNodeValueSemanticsProvider")
+public class TreeNode<T> implements Vertex<T> {
+
+    private final TreeState sharedState;
+    private final T value;
+    private final Class<? extends TreeAdapter<T>> treeAdapterClass;
+    private final _Lazy<TreeAdapter<T>> treeAdapter = _Lazy.of(this::newTreeAdapter);
+    private final _Lazy<TreePath> treePath = _Lazy.of(this::resolveTreePath);
+
+    public static <T> TreeNode<T> of(T value, Class<? extends TreeAdapter<T>> treeAdapterClass, TreeState sharedState) {
+        return new TreeNode<T>(value, treeAdapterClass, sharedState);
+    }
+
+    protected TreeNode(T value, Class<? extends TreeAdapter<T>> treeAdapterClass, TreeState sharedState) {
+        this.value = Objects.requireNonNull(value);
+        this.treeAdapterClass = Objects.requireNonNull(treeAdapterClass);
+        this.sharedState = sharedState;
+    }
+
+    @Override
+    public T getValue() {
+        return value;
+    }
+
 
     // -- VERTEX - IMPLEMENTATION
-    
-    default int getIncomingCount() {
+
+    @Override
+    public int getIncomingCount() {
         return isRoot() ? 0 : 1;
     }
-    default int getOutgoingCount() {
+    @Override
+    public int getOutgoingCount() {
         return getChildCount();
     }
-    default Stream<Edge<T>> streamIncoming() {
+    @Override
+    public Stream<Edge<T>> streamIncoming() {
         return isRoot() ? Stream.empty() : Stream.of(SimpleEdge.<T>of(getParentIfAny(), this));
     }
-    default Stream<Edge<T>> streamOutgoing() {
+    @Override
+    public Stream<Edge<T>> streamOutgoing() {
         return streamChildren()
                 .map(to->SimpleEdge.<T>of(this, to));
     }
-    
+
     // -- PARENT
 
-    public @Nullable TreeNode<T> getParentIfAny();
+    public @Nullable TreeNode<T> getParentIfAny() {
+        return treeAdapter().parentOf(getValue())
+                .map(this::toTreeNode)
+                .orElse(null);
+    }
+
+
 
     // -- CHILDREN
 
-    public int getChildCount();
+    public int getChildCount() {
+        return treeAdapter().childCountOf(value);
+    }
+
+    public Stream<TreeNode<T>> streamChildren() {
+        if(isLeaf()) {
+            return Stream.empty();
+        }
+        return treeAdapter().childrenOf(value)
+                .map(this::toTreeNode);
+    }
+
+
 
-    public Stream<TreeNode<T>> streamChildren();
 
     // -- BASIC PREDICATES
 
-    public default boolean isRoot() {
+    public boolean isRoot() {
         return getParentIfAny() == null;
     }
 
-    public default boolean isLeaf() {
+    public boolean isLeaf() {
         return getChildCount() == 0;
     }
 
     // -- PATH INFO
 
-    public TreePath getPositionAsPath();
+
+    public TreePath getPositionAsPath() {
+        return treePath.get();
+    }
+
+
 
     // -- COLLAPSE/EXPAND
 
     /**
      * @return this tree's shared state object, holding e.g. the collapse/expand state
      */
-    public TreeState getTreeState();
+    public TreeState getTreeState() {
+        return sharedState;
+    }
+
 
-    public default boolean isExpanded(TreePath treePath) {
+    public boolean isExpanded(TreePath treePath) {
         final Set<TreePath> expandedPaths = getTreeState().getExpandedNodePaths();
         return expandedPaths.contains(treePath);
     }
@@ -99,7 +156,7 @@ public interface TreeNode<T> extends Vertex<T> {
      * @param treePaths
      */
     @Programmatic
-    public default void expand(TreePath ... treePaths) {
+    public void expand(TreePath ... treePaths) {
         final Set<TreePath> expandedPaths = getTreeState().getExpandedNodePaths();
         _NullSafe.stream(treePaths).forEach(expandedPaths::add);
     }
@@ -108,7 +165,7 @@ public interface TreeNode<T> extends Vertex<T> {
      * Expands this node and all its parents.
      */
     @Programmatic
-    public default void expand() {
+    public void expand() {
         final Set<TreePath> expandedPaths = getTreeState().getExpandedNodePaths();
         streamHierarchyUp()
             .map(TreeNode::getPositionAsPath)
@@ -120,7 +177,7 @@ public interface TreeNode<T> extends Vertex<T> {
      * @param treePaths
      */
     @Programmatic
-    public default void collapse(TreePath ... treePaths) {
+    public void collapse(TreePath ... treePaths) {
         final Set<TreePath> expandedPaths = getTreeState().getExpandedNodePaths();
         _NullSafe.stream(treePaths).forEach(expandedPaths::remove);
     }
@@ -134,18 +191,18 @@ public interface TreeNode<T> extends Vertex<T> {
      * @return new LazyTreeNode
      */
     public static <T> TreeNode<T> lazy(T node, Class<? extends TreeAdapter<T>> treeAdapterClass) {
-        return LazyTreeNode.of(node, treeAdapterClass, TreeState.rootCollapsed());
+        return TreeNode.of(node, treeAdapterClass, TreeState.rootCollapsed());
     }
 
     // -- PARENT NODE ITERATION
 
-    public default Iterator<TreeNode<T>> iteratorHierarchyUp(){
+    public Iterator<TreeNode<T>> iteratorHierarchyUp(){
         return new TreeNode_iteratorHierarchyUp<>(this);
     }
 
     // -- PARENT NODE STREAMING
 
-    public default Stream<TreeNode<T>> streamHierarchyUp(){
+    public Stream<TreeNode<T>> streamHierarchyUp(){
         return StreamSupport.stream(
                 Spliterators.spliteratorUnknownSize(iteratorHierarchyUp(), Spliterator.ORDERED),
                 false); // not parallel
@@ -153,23 +210,23 @@ public interface TreeNode<T> extends Vertex<T> {
 
     // -- CHILD NODE ITERATION
 
-    public default Iterator<TreeNode<T>> iteratorDepthFirst(){
+    public Iterator<TreeNode<T>> iteratorDepthFirst(){
         return new TreeNode_iteratorDepthFirst<>(this);
     }
 
-    public default Iterator<TreeNode<T>> iteratorBreadthFirst(){
+    public Iterator<TreeNode<T>> iteratorBreadthFirst(){
         return new TreeNode_iteratorBreadthFirst<>(this);
     }
 
     // -- CHILD NODE STREAMING
 
-    public default Stream<TreeNode<T>> streamDepthFirst(){
+    public Stream<TreeNode<T>> streamDepthFirst(){
         return StreamSupport.stream(
                 Spliterators.spliteratorUnknownSize(iteratorDepthFirst(), Spliterator.ORDERED),
                 false); // not parallel
     }
 
-    public default Stream<TreeNode<T>> streamBreadthFirst(){
+    public Stream<TreeNode<T>> streamBreadthFirst(){
         return StreamSupport.stream(
                 Spliterators.spliteratorUnknownSize(iteratorBreadthFirst(), Spliterator.ORDERED),
                 false); // not parallel
@@ -181,7 +238,62 @@ public interface TreeNode<T> extends Vertex<T> {
      * @apiNote a class rather than an instance, because otherwise
      * the adapter would need to be serializable for Wicket's trees to work correctly.
      */
-    public Class<? extends TreeAdapter<T>> getTreeAdapterClass();
+    public Class<? extends TreeAdapter<T>> getTreeAdapterClass() {
+        return treeAdapterClass;
+    }
+
+
+
+
+    // -- HELPER
+
+    private TreeAdapter<T> newTreeAdapter() {
+        try {
+            return treeAdapterClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new IllegalArgumentException(
+                    String.format("failed to instantiate TreeAdapter '%s'", treeAdapterClass.getName()), e);
+        }
+    }
+
+    private TreeAdapter<T> treeAdapter() {
+        return treeAdapter.get();
+    }
+
+    private TreeNode<T> toTreeNode(T value){
+        return of(value, getTreeAdapterClass(), sharedState);
+    }
+
+    private TreePath resolveTreePath() {
+        final TreeNode<T> parent = getParentIfAny();
+        if(parent==null) {
+            return TreePath.root();
+        }
+        return parent.getPositionAsPath().append(indexWithinSiblings(parent));
+    }
+
+    /*
+     * @return zero based index
+     */
+    private int indexWithinSiblings(TreeNode<T> parent) {
+        final LongAdder indexOneBased = new LongAdder();
 
+        boolean found = parent.streamChildren()
+                .peek(__->indexOneBased.increment())
+                .anyMatch(this::isEqualTo);
+
+        if(!found) {
+            throw _Exceptions.unexpectedCodeReach();
+        }
+
+        return indexOneBased.intValue()-1;
+    }
+
+    private boolean isEqualTo(TreeNode<T> other) {
+        if(other==null) {
+            return false;
+        }
+        return Objects.equals(this.getValue(), other.getValue());
+    }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/treenode/TreeNodeValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/treenode/TreeNodeValueSemanticsProvider.java
index d6e7906..9e59fca 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/treenode/TreeNodeValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/treenode/TreeNodeValueSemanticsProvider.java
@@ -22,7 +22,6 @@ package org.apache.isis.core.metamodel.facets.value.treenode;
 import org.apache.isis.applib.adapters.DefaultsProvider;
 import org.apache.isis.applib.adapters.EncoderDecoder;
 import org.apache.isis.applib.adapters.Parser;
-import org.apache.isis.applib.graph.tree.LazyTreeNode;
 import org.apache.isis.applib.graph.tree.TreeNode;
 import org.apache.isis.applib.graph.tree.TreeState;
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
@@ -105,7 +104,7 @@ implements TreeNodeValueFacet {
     @Override
     protected TreeNode<?> doRestore(final String input) {
         final Memento memento = parseMemento(input);
-        return LazyTreeNode.of(
+        return TreeNode.of(
                 memento.get("primaryValue", Object.class),
                 memento.get("adapterClass", Class.class),
                 memento.get("treeState", TreeState.class));
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
index 26f884c..030580c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
@@ -27,7 +27,7 @@ import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.graph.SimpleEdge;
-import org.apache.isis.applib.graph.tree.LazyTreeNode;
+import org.apache.isis.applib.graph.tree.TreeNode;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureDefault;
@@ -46,7 +46,7 @@ public class ValueTypeProviderForBuiltin implements ValueTypeProvider {
 
                     // these are not yet part of the schema (do not map onto any value-types there)
                     ValueTypeDefinition.of(SimpleEdge.class, ValueType.STRING),
-                    ValueTypeDefinition.of(LazyTreeNode.class, ValueType.STRING),
+                    ValueTypeDefinition.of(TreeNode.class, ValueType.STRING),
 
                     ValueTypeDefinition.of(ApplicationFeatureDefault.class, ValueType.STRING)