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 2018/05/04 15:19:20 UTC

[isis] branch master updated (f4c9cdd -> a8646c4)

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

ahuber pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git.


    from f4c9cdd  ISIS-898: cleanup debug code, also suppress unchecked+rawtypes warnings
     new f485b1b  ISIS-1943: extending the tree API: introduces TreePath
     new 9aa747e  ISIS-1943: introduces TreeModel that extends EntityModel
     new a8646c4  ISIS-1943: Internal API: introduces _Functions

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../{_Constants.java => functions/_Functions.java} |  36 +++---
 .../_Functions_IndexAwareFunctionAdapter.java}     |  34 +++---
 .../internal/{base => functions}/package-info.java |   2 +-
 .../org/apache/isis/applib/tree/LazyTreeNode.java  |  35 ++++++
 .../java/org/apache/isis/applib/tree/TreeNode.java |   4 +
 .../_Comparators.java => tree/TreePath.java}       |  49 ++++----
 .../apache/isis/applib/tree/TreePath_Default.java  |  77 ++++++++++++
 .../components/tree/IsisToWicketTreeAdapter.java   | 131 +++++++++++++--------
 8 files changed, 260 insertions(+), 108 deletions(-)
 copy core/applib/src/main/java/org/apache/isis/applib/internal/{_Constants.java => functions/_Functions.java} (64%)
 copy core/{applib-legacy/src/main/java/org/apache/isis/applib/layout/component/FieldSet_legacy.java => applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions_IndexAwareFunctionAdapter.java} (57%)
 copy core/applib/src/main/java/org/apache/isis/applib/internal/{base => functions}/package-info.java (95%)
 copy core/applib/src/main/java/org/apache/isis/applib/{internal/compare/_Comparators.java => tree/TreePath.java} (50%)
 create mode 100644 core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.

[isis] 02/03: ISIS-1943: introduces TreeModel that extends EntityModel

Posted by ah...@apache.org.
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

commit 9aa747ead77790658bcd591b697cc20fb170ad8d
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri May 4 16:38:24 2018 +0200

    ISIS-1943: introduces TreeModel that extends EntityModel
    
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1943
---
 .../java/org/apache/isis/applib/tree/TreePath.java |  10 ++
 .../apache/isis/applib/tree/TreePath_Default.java  |  32 +++++-
 .../components/tree/IsisToWicketTreeAdapter.java   | 125 +++++++++++++--------
 3 files changed, 119 insertions(+), 48 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java
index 0e8c349..0ecda6c 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java
@@ -20,6 +20,8 @@ package org.apache.isis.applib.tree;
 
 import java.io.Serializable;
 
+import javax.annotation.Nullable;
+
 /**
  * Provides an unambiguous way to address nodes by position within a tree-structure. Examples:
  * <ul>
@@ -37,6 +39,14 @@ public interface TreePath extends Serializable {
 	 */
 	public TreePath append(int indexWithinSiblings);
 	
+	/**
+	 * 
+	 * @return a new TreePath instance that represents the parent path of this
+	 */
+	public @Nullable TreePath getParentIfAny();
+	
+	public boolean isRoot();
+	
 	// -- CONSTRUCTION
 	
 	public static TreePath of(final int ... canonicalPath) {
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java
index ce30341..4851572 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java
@@ -18,6 +18,7 @@
  */
 package org.apache.isis.applib.tree;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -38,10 +39,39 @@ class TreePath_Default implements TreePath {
 
 	@Override
 	public TreePath append(int indexWithinSiblings) {
-		int[] newCanonicalPath = new int[canonicalPath.length+1];
+		final int[] newCanonicalPath = new int[canonicalPath.length+1];
 		System.arraycopy(canonicalPath, 0, newCanonicalPath, 0, canonicalPath.length);
 		newCanonicalPath[canonicalPath.length] = indexWithinSiblings;
 		return new TreePath_Default(newCanonicalPath);
 	}
 	
+	@Override
+	public boolean equals(Object obj) {
+		if(obj instanceof TreePath_Default) {
+			final TreePath_Default other = (TreePath_Default) obj;
+			return Arrays.equals(canonicalPath, other.canonicalPath);
+		}
+		return false;
+	}
+	
+	@Override
+	public int hashCode() {
+		return canonicalPath.hashCode();
+	}
+
+	@Override
+	public TreePath getParentIfAny() {
+		if(isRoot()) {
+			return null;
+		}
+		final int[] newCanonicalPath = new int[canonicalPath.length-1];
+		System.arraycopy(canonicalPath, 0, newCanonicalPath, 0, canonicalPath.length-1);
+		return new TreePath_Default(newCanonicalPath);
+	}
+
+	@Override
+	public boolean isRoot() {
+		return canonicalPath.length==1;
+	}
+	
 }
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 102a12a..164481d 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -5,6 +5,7 @@ import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.concurrent.atomic.LongAdder;
 import java.util.stream.Stream;
 
 import javax.resource.spi.IllegalStateException;
@@ -12,6 +13,7 @@ import javax.resource.spi.IllegalStateException;
 import org.apache.isis.applib.internal.collections._Lists;
 import org.apache.isis.applib.tree.TreeAdapter;
 import org.apache.isis.applib.tree.TreeNode;
+import org.apache.isis.applib.tree.TreePath;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.runtime.system.context.IsisContext;
@@ -47,11 +49,11 @@ class IsisToWicketTreeAdapter {
 	/**
 	 * Wicket's Tree Component implemented for Isis
 	 */
-	private static class EntityTree extends NestedTree<EntityModel> {
+	private static class EntityTree extends NestedTree<TreeModel> {
 
 		private static final long serialVersionUID = 1L;
 
-		public EntityTree(String id, ITreeProvider<EntityModel> provider) {
+		public EntityTree(String id, ITreeProvider<TreeModel> provider) {
 			super(id, provider);
 			add(new WindowsTheme()); // TODO not required if Isis provides it's own css styles for tree-nodes
 		}
@@ -60,9 +62,9 @@ class IsisToWicketTreeAdapter {
 		 * To use a custom component for the representation of a node's content we override this method.
 		 */
 		@Override
-		protected Component newContentComponent(String id, IModel<EntityModel> node) {
-			final EntityModel entityModel = node.getObject();
-			final Component entityIconAndTitle = new EntityIconAndTitlePanel(id, entityModel);
+		protected Component newContentComponent(String id, IModel<TreeModel> node) {
+			final TreeModel treeModel = node.getObject();
+			final Component entityIconAndTitle = new EntityIconAndTitlePanel(id, treeModel);
 			return entityIconAndTitle;
 		}
 		
@@ -70,20 +72,20 @@ class IsisToWicketTreeAdapter {
 		 * To hardcode Node's <pre>AjaxFallbackLink.isEnabledInHierarchy()->true</pre> we override this method.
 		 */
 		@Override
-		public Component newNodeComponent(String id, IModel<EntityModel> model) {
+		public Component newNodeComponent(String id, IModel<TreeModel> model) {
 			
-			final Node<EntityModel> node =  new Node<EntityModel>(id, this, model) {
+			final Node<TreeModel> node =  new Node<TreeModel>(id, this, model) {
 				private static final long serialVersionUID = 1L;
 				
 				@Override
-				protected Component createContent(String id, IModel<EntityModel> model) {
+				protected Component createContent(String id, IModel<TreeModel> model) {
 					return EntityTree.this.newContentComponent(id, model);
 				}
 				
 				@Override
 				protected MarkupContainer createJunctionComponent(String id) {
 					
-					final Node<EntityModel> node = this;
+					final Node<TreeModel> node = this;
 					final Runnable toggleExpandCollapse = (Runnable & Serializable) this::toggle;
 					
 					return new AjaxFallbackLink<Void>(id) {
@@ -118,15 +120,34 @@ class IsisToWicketTreeAdapter {
 	}
 	
 	// -- HELPER
+	
+	/**
+	 * Extending the EntityModel to also provide a TreePath.
+	 */
+	public static class TreeModel extends EntityModel {
+		private static final long serialVersionUID = 8916044984628849300L;
+		
+		private final TreePath treePath;
+
+		public TreeModel(ObjectAdapter adapter, TreePath treePath) {
+			super(adapter);
+			this.treePath = treePath;
+		}
+		
+		public TreePath getTreePath() {
+			return treePath;
+		}
+	}
+	
 
 	@SuppressWarnings({"rawtypes", "unchecked"})
-	private static class EntityModelTreeAdapter implements TreeAdapter<EntityModel>, Serializable {
+	private static class TreeModelTreeAdapter implements TreeAdapter<TreeModel>, Serializable {
 		private static final long serialVersionUID = 1L;
 		
 		private final Class<? extends TreeAdapter> treeAdapterClass;
 		private transient TreeAdapter wrappedTreeAdapter;
 		
-		private EntityModelTreeAdapter(Class<? extends TreeAdapter> treeAdapterClass) {
+		private TreeModelTreeAdapter(Class<? extends TreeAdapter> treeAdapterClass) {
 			this.treeAdapterClass = treeAdapterClass;
 		}
 		
@@ -142,37 +163,39 @@ class IsisToWicketTreeAdapter {
 		}
 
 		@Override
-		public Optional<EntityModel> parentOf(EntityModel entityModel) {
-			if(entityModel==null) {
+		public Optional<TreeModel> parentOf(TreeModel treeModel) {
+			if(treeModel==null) {
 				return Optional.empty();
 			}
-			return wrappedTreeAdapter().parentOf(unwrap(entityModel))
-					.map(this::wrap);
+			return wrappedTreeAdapter().parentOf(unwrap(treeModel))
+					.map(pojo->wrap(pojo, treeModel.getTreePath().getParentIfAny())); 
 		}
 
 		@Override
-		public int childCountOf(EntityModel entityModel) {
-			if(entityModel==null) {
+		public int childCountOf(TreeModel treeModel) {
+			if(treeModel==null) {
 				return 0;
 			}
-			return wrappedTreeAdapter().childCountOf(unwrap(entityModel));
+			return wrappedTreeAdapter().childCountOf(unwrap(treeModel));
 		}
 
 		@Override
-		public Stream<EntityModel> childrenOf(EntityModel entityModel) {
-			if(entityModel==null) {
+		public Stream<TreeModel> childrenOf(TreeModel treeModel) {
+			if(treeModel==null) {
 				return Stream.empty();
 			}
-			return wrappedTreeAdapter().childrenOf(unwrap(entityModel))
-					.map(this::wrap);
+			final LongAdder indexWithinSiblings = new LongAdder(); 
+			return wrappedTreeAdapter().childrenOf(unwrap(treeModel))
+					.map(pojo->wrap(pojo, treeModel.getTreePath().append(indexWithinSiblings.intValue()) ))
+					.peek(__->indexWithinSiblings.increment());
 		}
 		
-		private EntityModel wrap(Object pojo) {
+		private TreeModel wrap(Object pojo, TreePath treePath) {
 			Objects.requireNonNull(pojo);
-			return new EntityModel(persistenceSession().getAdapterFor(pojo));
+			return new TreeModel(persistenceSession().getAdapterFor(pojo), treePath);
 		}
 		
-		private Object unwrap(EntityModel model) {
+		private Object unwrap(TreeModel model) {
 			Objects.requireNonNull(model);
 			return model.getObject().getObject();
 		}
@@ -186,14 +209,17 @@ class IsisToWicketTreeAdapter {
 	/**
 	 * Wicket's ITreeProvider implemented for Isis
 	 */
-	private static class EntityModelTreeProvider implements ITreeProvider<EntityModel> {
+	private static class TreeModelTreeProvider implements ITreeProvider<TreeModel> {
 
 		private static final long serialVersionUID = 1L;
 		
-		private final EntityModel primaryValue;
-		private final EntityModelTreeAdapter treeAdapter;
+		/**
+		 * tree's root
+		 */
+		private final TreeModel primaryValue;
+		private final TreeModelTreeAdapter treeAdapter;
 
-		private EntityModelTreeProvider(EntityModel primaryValue, EntityModelTreeAdapter treeAdapter) {
+		private TreeModelTreeProvider(TreeModel primaryValue, TreeModelTreeAdapter treeAdapter) {
 			this.primaryValue = primaryValue;
 			this.treeAdapter = treeAdapter;
 		}
@@ -203,23 +229,23 @@ class IsisToWicketTreeAdapter {
 		}
 
 		@Override
-		public Iterator<? extends EntityModel> getRoots() {
+		public Iterator<? extends TreeModel> getRoots() {
 			return _Lists.singleton(primaryValue).iterator();
 		}
 
 		@Override
-		public boolean hasChildren(EntityModel node) {
+		public boolean hasChildren(TreeModel node) {
 			return treeAdapter.childCountOf(node)>0;
 		}
 
 		@Override
-		public Iterator<? extends EntityModel> getChildren(EntityModel node) {
+		public Iterator<? extends TreeModel> getChildren(TreeModel node) {
 			return treeAdapter.childrenOf(node).iterator();
 		}
 
 		@Override
-		public IModel<EntityModel> model(final EntityModel entityModel) {
-			return new LoadableDetachableEntityModel(entityModel);
+		public IModel<TreeModel> model(final TreeModel treeModel) {
+			return new LoadableDetachableEntityModel(treeModel);
 		}
 		
 	}
@@ -229,29 +255,34 @@ class IsisToWicketTreeAdapter {
 	 * @return Wicket's ITreeProvider
 	 */
 	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private static ITreeProvider<EntityModel> toITreeProvider(ModelAbstract<ObjectAdapter> model) {
-		
-		final TreeNode tree = (TreeNode) model.getObject().getObject();
-		final EntityModelTreeAdapter wrappingTreeAdapter = new EntityModelTreeAdapter(tree.getTreeAdapterClass());
+	private static ITreeProvider<TreeModel> toITreeProvider(ModelAbstract<ObjectAdapter> model) {
 		
-		return new EntityModelTreeProvider(wrappingTreeAdapter.wrap(tree.getValue()), wrappingTreeAdapter);		
+		final TreeNode treeNode = (TreeNode) model.getObject().getObject();
+		final TreeModelTreeAdapter wrappingTreeAdapter = new TreeModelTreeAdapter(treeNode.getTreeAdapterClass());
+		return new TreeModelTreeProvider(
+				wrappingTreeAdapter.wrap(treeNode.getValue(), treeNode.getPositionAsPath()), 
+				wrappingTreeAdapter);		
 	}
 	
-	private static class LoadableDetachableEntityModel extends LoadableDetachableModel<EntityModel> {
+	private static class LoadableDetachableEntityModel extends LoadableDetachableModel<TreeModel> {
 		private static final long serialVersionUID = 1L;
 
 		private final RootOid id;
+		private final TreePath treePath;
+		private final int hashCode;
 
-		public LoadableDetachableEntityModel(EntityModel eModel) {
-			super(eModel);
-			id = (RootOid) eModel.getObject().getOid();
+		public LoadableDetachableEntityModel(TreeModel tModel) {
+			super(tModel);
+			this.id = (RootOid) tModel.getObject().getOid();
+			this.treePath = tModel.getTreePath();
+			this.hashCode = Objects.hash(id.hashCode(), treePath.hashCode());
 		}
 
 		/*
 		 * loads EntityModel using Oid (id)
 		 */
 		@Override
-		protected EntityModel load() {
+		protected TreeModel load() {
 			
 			final PersistenceSession persistenceSession = IsisContext.getPersistenceSession()
 					.orElseThrow(()->new RuntimeException(new IllegalStateException(
@@ -271,7 +302,7 @@ class IsisToWicketTreeAdapter {
 						String.format("Tree creation: could not recreate Pojo from Oid: '%s'", id)); 
 			}
 			
-			return new EntityModel(objAdapter);
+			return new TreeModel(objAdapter, treePath);
 		}
 
 		/*
@@ -282,7 +313,7 @@ class IsisToWicketTreeAdapter {
 		public boolean equals(Object obj) {
 			if (obj instanceof LoadableDetachableEntityModel) {
 				final LoadableDetachableEntityModel other = (LoadableDetachableEntityModel) obj;
-				return id.equals(other.id);
+				return treePath.equals(other.treePath) && id.equals(other.id);
 			}
 			return false;
 		}
@@ -292,7 +323,7 @@ class IsisToWicketTreeAdapter {
 		 */
 		@Override
 		public int hashCode() {
-			return id.hashCode();
+			return hashCode;
 		}
 	}
 

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.

[isis] 03/03: ISIS-1943: Internal API: introduces _Functions

Posted by ah...@apache.org.
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

commit a8646c4e18a5e01e96934be96f802bda0168c6cd
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri May 4 17:19:16 2018 +0200

    ISIS-1943: Internal API: introduces _Functions
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1943
---
 .../isis/applib/internal/functions/_Functions.java | 53 ++++++++++++++++++++++
 .../_Functions_IndexAwareFunctionAdapter.java      | 44 ++++++++++++++++++
 .../applib/internal/functions/package-info.java    | 28 ++++++++++++
 .../components/tree/IsisToWicketTreeAdapter.java   | 15 +++---
 4 files changed, 134 insertions(+), 6 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions.java b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions.java
new file mode 100644
index 0000000..9a33621
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions.java
@@ -0,0 +1,53 @@
+/*
+ *  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.internal.functions;
+
+import java.util.function.Function;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * Common Function idioms.
+ * </p>
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/> 
+ * These may be changed or removed without notice!
+ * </p>
+ * 
+ * @since 2.0.0
+ */
+public class _Functions {
+
+	@FunctionalInterface
+	public interface IndexAwareFunction<T, R> {
+		public R apply(int index, T t);
+	}
+	
+	/**
+	 * Converts an IndexAwareFunction into a Function, having its index start at 0,
+	 * and incremented after each function call.
+	 * @param indexAwareFunction
+	 * @return 
+	 */
+	public static <T, R> Function<T, R> indexAwareFunctionToFunction(IndexAwareFunction<T, R> indexAwareFunction){
+		return new _Functions_IndexAwareFunctionAdapter<T, R>(indexAwareFunction);
+	}
+	
+	
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions_IndexAwareFunctionAdapter.java b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions_IndexAwareFunctionAdapter.java
new file mode 100644
index 0000000..883abe0
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/_Functions_IndexAwareFunctionAdapter.java
@@ -0,0 +1,44 @@
+/*
+ *  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.internal.functions;
+
+import java.util.function.Function;
+
+import org.apache.isis.applib.internal.functions._Functions.IndexAwareFunction;
+
+/**
+ * Package private mixin for _Functions. <br/>
+ * Extending a Function to keep track of an index, incremented with each function call.
+ */
+class _Functions_IndexAwareFunctionAdapter<T, R> implements Function<T, R> {
+
+
+	private int index=0;
+	private final IndexAwareFunction<T, R> indexAwareFunction;
+
+	_Functions_IndexAwareFunctionAdapter(IndexAwareFunction<T, R> indexAwareFunction) {
+		this.indexAwareFunction = indexAwareFunction;
+	}
+
+	@Override
+	public R apply(T t) {
+		return indexAwareFunction.apply(index++, t);
+	}
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/functions/package-info.java b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/package-info.java
new file mode 100644
index 0000000..a517ed7
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/functions/package-info.java
@@ -0,0 +1,28 @@
+/*
+ *  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.
+ */
+/**
+ * <h1>Internal API</h1>
+ * Internal classes, contributing to the internal proprietary API. 
+ * These may be changed or removed without notice!
+ * <p>
+ * <b>WARNING</b>: 
+ * Do NOT use any of the classes provided by this package!
+ * </p>
+ */
+package org.apache.isis.applib.internal.functions;
\ No newline at end of file
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 164481d..7aceaf2 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -5,12 +5,13 @@ import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.concurrent.atomic.LongAdder;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
 import javax.resource.spi.IllegalStateException;
 
 import org.apache.isis.applib.internal.collections._Lists;
+import org.apache.isis.applib.internal.functions._Functions;
 import org.apache.isis.applib.tree.TreeAdapter;
 import org.apache.isis.applib.tree.TreeNode;
 import org.apache.isis.applib.tree.TreePath;
@@ -124,7 +125,7 @@ class IsisToWicketTreeAdapter {
 	/**
 	 * Extending the EntityModel to also provide a TreePath.
 	 */
-	public static class TreeModel extends EntityModel {
+	private static class TreeModel extends EntityModel {
 		private static final long serialVersionUID = 8916044984628849300L;
 		
 		private final TreePath treePath;
@@ -139,7 +140,6 @@ class IsisToWicketTreeAdapter {
 		}
 	}
 	
-
 	@SuppressWarnings({"rawtypes", "unchecked"})
 	private static class TreeModelTreeAdapter implements TreeAdapter<TreeModel>, Serializable {
 		private static final long serialVersionUID = 1L;
@@ -184,10 +184,8 @@ class IsisToWicketTreeAdapter {
 			if(treeModel==null) {
 				return Stream.empty();
 			}
-			final LongAdder indexWithinSiblings = new LongAdder(); 
 			return wrappedTreeAdapter().childrenOf(unwrap(treeModel))
-					.map(pojo->wrap(pojo, treeModel.getTreePath().append(indexWithinSiblings.intValue()) ))
-					.peek(__->indexWithinSiblings.increment());
+					.map(newPojoToTreeModelMapper(treeModel));
 		}
 		
 		private TreeModel wrap(Object pojo, TreePath treePath) {
@@ -204,6 +202,11 @@ class IsisToWicketTreeAdapter {
 			return IsisContext.getPersistenceSession().orElse(null);
 		}
 		
+		private Function<Object, TreeModel> newPojoToTreeModelMapper(TreeModel parent) {
+			return _Functions.indexAwareFunctionToFunction((indexWithinSiblings, pojo)->
+				wrap(pojo, parent.getTreePath().append(indexWithinSiblings)));
+		}
+		
 	}
 
 	/**

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.

[isis] 01/03: ISIS-1943: extending the tree API: introduces TreePath

Posted by ah...@apache.org.
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

commit f485b1b06f0b99405b3712ea8bd5463d071e1e9f
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri May 4 15:43:23 2018 +0200

    ISIS-1943: extending the tree API: introduces TreePath
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1943
---
 .../org/apache/isis/applib/tree/LazyTreeNode.java  | 35 +++++++++++++++
 .../java/org/apache/isis/applib/tree/TreeNode.java |  4 ++
 .../java/org/apache/isis/applib/tree/TreePath.java | 50 ++++++++++++++++++++++
 .../apache/isis/applib/tree/TreePath_Default.java  | 47 ++++++++++++++++++++
 .../components/tree/IsisToWicketTreeAdapter.java   |  3 +-
 5 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/LazyTreeNode.java b/core/applib/src/main/java/org/apache/isis/applib/tree/LazyTreeNode.java
index 1d75d33..98ce49f 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/tree/LazyTreeNode.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/LazyTreeNode.java
@@ -19,10 +19,12 @@
 package org.apache.isis.applib.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.applib.internal.base._Lazy;
+import org.apache.isis.applib.internal.exceptions._Exceptions;
 
 @Value(semanticsProviderName="org.apache.isis.core.metamodel.facets.value.treenode.TreeNodeValueSemanticsProvider")
 public class LazyTreeNode<T> implements TreeNode<T> {
@@ -30,6 +32,7 @@ public class LazyTreeNode<T> implements TreeNode<T> {
 	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) {
 		return new LazyTreeNode<T>(value, treeAdapterClass);
@@ -73,6 +76,11 @@ public class LazyTreeNode<T> implements TreeNode<T> {
 		return treeAdapterClass;
 	}
 	
+	@Override
+	public TreePath getPositionAsPath() {
+		return treePath.get();
+	}
+	
 	// -- HELPER
 	
 	private TreeAdapter<T> newTreeAdapter() {
@@ -92,5 +100,32 @@ public class LazyTreeNode<T> implements TreeNode<T> {
 		return of(value, getTreeAdapterClass());
 	}
 
+	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(sibling->this.equals(sibling))
+		;
+		
+		if(!found) {
+			throw _Exceptions.unexpectedCodeReach();
+		}
+		
+		return indexOneBased.intValue()-1;
+	}
+
+
 	
 }
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java
index e387c0c..7ebb3ee 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java
@@ -51,6 +51,10 @@ public interface TreeNode<T> {
 	public default boolean isLeaf() {
 		return getChildCount() == 0;
 	}
+	
+	// -- PATH INFO
+	
+	public TreePath getPositionAsPath();
 
 	// -- CONSTRUCTION
 
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java
new file mode 100644
index 0000000..0e8c349
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath.java
@@ -0,0 +1,50 @@
+/*
+ *  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.tree;
+
+import java.io.Serializable;
+
+/**
+ * Provides an unambiguous way to address nodes by position within a tree-structure. Examples:
+ * <ul>
+ * <li>/0 ... the tree root</li>
+ * <li>/0/1 ... the second child of root</li>
+ * <li>/0/0/0 ... the first child of first child of root</li>
+ * </ul>
+ * @since 2.0.0
+ */
+public interface TreePath extends Serializable {
+
+	/**
+	 * @param indexWithinSiblings
+	 * @return a new TreePath instance composed of this with one canonical path entry added
+	 */
+	public TreePath append(int indexWithinSiblings);
+	
+	// -- CONSTRUCTION
+	
+	public static TreePath of(final int ... canonicalPath) {
+		return new TreePath_Default(canonicalPath);
+	}
+
+	public static TreePath root() {
+		return of(0);
+	}
+	
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java
new file mode 100644
index 0000000..ce30341
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreePath_Default.java
@@ -0,0 +1,47 @@
+/*
+ *  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.tree;
+
+import java.util.Objects;
+
+/**
+ * Package private mixin for TreePath.
+ */
+class TreePath_Default implements TreePath {
+
+	private static final long serialVersionUID = 530511373409525896L;
+	private final int[] canonicalPath;
+
+	TreePath_Default(int[] canonicalPath) {
+		Objects.requireNonNull(canonicalPath, "canonicalPath is required");
+		if(canonicalPath.length<1) {
+			throw new IllegalArgumentException("canonicalPath must not be empty");
+		}
+		this.canonicalPath = canonicalPath;
+	}
+
+	@Override
+	public TreePath append(int indexWithinSiblings) {
+		int[] newCanonicalPath = new int[canonicalPath.length+1];
+		System.arraycopy(canonicalPath, 0, newCanonicalPath, 0, canonicalPath.length);
+		newCanonicalPath[canonicalPath.length] = indexWithinSiblings;
+		return new TreePath_Default(newCanonicalPath);
+	}
+	
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 766fd68..102a12a 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -275,7 +275,8 @@ class IsisToWicketTreeAdapter {
 		}
 
 		/*
-		 * Important! Models must be identifiable by their contained object.
+		 * Important! Models must be identifiable by their contained object. Also IDs must be
+		 * unique within a tree structure.
 		 */
 		@Override
 		public boolean equals(Object obj) {

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.