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)