[jboss-cvs] jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset ...
Christian Bauer
christian at hibernate.org
Sat Aug 25 13:59:20 EDT 2007
User: cbauer
Date: 07/08/25 13:59:20
Modified: examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset
AbstractNestedSetNode.java
NestedSetPostDeleteEventListener.java
NestedSetResultTransformer.java
NestedSetNodeWrapper.java
NestedSetPostInsertEventListener.java
NestedSetNode.java
Added: examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset
NestedSetNodeDuplicator.java
Log:
Major refactoring of navigation
Revision Changes Path
1.2 +18 -0 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/AbstractNestedSetNode.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: AbstractNestedSetNode.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/AbstractNestedSetNode.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- AbstractNestedSetNode.java 17 Aug 2007 13:00:23 -0000 1.1
+++ AbstractNestedSetNode.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -39,6 +39,19 @@
@Column(name = "NS_RIGHT", nullable = false, updatable = false)
private Long nsRight = 0l;
+ protected AbstractNestedSetNode() {};
+
+ protected AbstractNestedSetNode(N original) {
+ if (original == null) return;
+ this.nsThread = original.getNsThread();
+ this.nsLeft = original.getNsLeft();
+ this.nsRight = original.getNsRight();
+ }
+
+ public boolean vetoNestedSetUpdate() {
+ return false;
+ }
+
public void addChild(N child) {
if (child.getParent() != null) {
child.getParent().getChildren().remove(child);
@@ -88,4 +101,9 @@
public String getTreeSuperclassEntityName() {
return getClass().getSimpleName();
}
+
+ public String toString() {
+ return "(ID: " + getId() + " THREAD: " + getNsThread() + " LEFT: " + getNsLeft() + " RIGHT: " + getNsRight() +")";
+ }
+
}
1.2 +3 -5 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostDeleteEventListener.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: NestedSetPostDeleteEventListener.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostDeleteEventListener.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- NestedSetPostDeleteEventListener.java 17 Aug 2007 13:00:23 -0000 1.1
+++ NestedSetPostDeleteEventListener.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -23,12 +23,10 @@
public void onPostDelete(PostDeleteEvent event) {
super.onPostDelete(event);
- if (event.getEntity() instanceof NestedSetNode) {
- if (event.getEntity() instanceof NestedSetNode) {
+ if ( event.getEntity() instanceof NestedSetNode && !((NestedSetNode)event.getEntity()).vetoNestedSetUpdate() ) {
log.debug("executing nested set delete operation, recalculating the tree");
new DeleteNestedSetOperation( (NestedSetNode)event.getEntity() ).execute(event.getSession());
}
}
- }
}
1.2 +45 -11 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetResultTransformer.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: NestedSetResultTransformer.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetResultTransformer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- NestedSetResultTransformer.java 17 Aug 2007 13:00:23 -0000 1.1
+++ NestedSetResultTransformer.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -62,6 +62,13 @@
* deeper than 3 levels. This is useful for certain kinds of tree display.
* </p>
* <p>
+ * This transformer accepts a <tt>NestedSetNodeDuplicator</tt> instance which will be used, if not null, to
+ * copy every <tt>nestedSetNode</tt> returned by the query. This is useful if you do not want or require the
+ * original <tt>nestedSetNode</tt> instances wrapped, for example, if changes on these instances should not
+ * be reflected by the wrapped instances. You can effectively generate a stable copy of the tree, e.g. for
+ * display purposes.
+ * </p>
+ * <p>
* A note about restrictions: If the only restriction condition in your query is the one shown above, limiting
* the returned tuples to the nodes of the subtree, you will have a whole and complete subtree, hence, you will
* not have any gaps in the in-memory tree of {@link NestedSetNodeWrapper}s returned by the transformer. However,
@@ -83,14 +90,22 @@
NestedSetNodeWrapper<N> rootWrapper;
NestedSetNodeWrapper<N> currentParent;
long flattenToLevel = 0;
+ Map<String, String> additionalProjections = new HashMap<String, String>();
+ NestedSetNodeDuplicator<N> nestedSetNodeDuplicator = null;
+
+ public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper) {
+ this(rootWrapper, 0l);
+ }
public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper, long flattenToLevel) {
- this(rootWrapper);
- this.flattenToLevel = flattenToLevel;
+ this(rootWrapper, flattenToLevel, new HashMap<String, String>());
}
- public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper) {
+ public NestedSetResultTransformer(NestedSetNodeWrapper<N> rootWrapper, long flattenToLevel, Map<String, String> additionalProjections) {
this.rootWrapper = rootWrapper;
+ this.flattenToLevel = flattenToLevel;
+ this.additionalProjections = additionalProjections;
+
this.comparator = rootWrapper.getComparator();
currentParent = rootWrapper;
}
@@ -99,23 +114,41 @@
return rootWrapper;
}
+ public Map<String, String> getAdditionalProjections() {
+ return additionalProjections;
+ }
+
+ public void setNestedSetNodeDuplicator(NestedSetNodeDuplicator<N> nestedSetNodeDuplicator) {
+ this.nestedSetNodeDuplicator = nestedSetNodeDuplicator;
+ }
+
public Object transformTuple(Object[] objects, String[] aliases) {
if (!"nestedSetNodeLevel".equals(aliases[0]))
throw new RuntimeException("Missing alias 'nestedSetNodeLevel' as the first projected value in the nested set query");
if (!"nestedSetNode".equals(aliases[1]))
throw new RuntimeException("Missing alias 'nestedSetNode' as the second projected value in the nested set query");
- if (objects.length != 2) {
- throw new RuntimeException("Nested set query needs to return two values, the level and the nested set node instance");
+ if (objects.length < 2) {
+ throw new RuntimeException("Nested set query needs to at least return two values, the level and the nested set node instance");
}
Long nestedSetNodeLevel = (Long)objects[0];
N nestedSetNode = (N)objects[1];
+ Long nestedSetNodeParentId = nestedSetNode.getParent().getId(); // Store the parent id before making a duplicate
+ if (nestedSetNodeDuplicator != null) nestedSetNode = nestedSetNodeDuplicator.duplicate(nestedSetNode);
+ if (nestedSetNode == null) return null; // Continue in loop if the duplicator didn't make a proper copy
+
+ Map<String, Object> additionalProjectionValues = new LinkedHashMap<String, Object>();
+ int i = 2;
+ for (Map.Entry<String, String> entry : additionalProjections.entrySet()) {
+ additionalProjectionValues.put(entry.getKey(), objects[i++]);
+ }
+
// Connect the tree hierarchically (child to parent, skip child if parent isn't present)
- NestedSetNodeWrapper<N> nodeWrapper = new NestedSetNodeWrapper<N>(nestedSetNode, comparator, nestedSetNodeLevel);
- if (!nodeWrapper.getWrappedNode().getParent().getId().equals(currentParent.getWrappedNode().getId())) {
- NestedSetNodeWrapper<N> foundParent = findParentInTree(nodeWrapper.getWrappedNode().getParent().getId(), currentParent);
+ NestedSetNodeWrapper<N> nodeWrapper = new NestedSetNodeWrapper<N>(nestedSetNode, comparator, nestedSetNodeLevel, additionalProjectionValues);
+ if (!nestedSetNodeParentId.equals(currentParent.getWrappedNode().getId())) {
+ NestedSetNodeWrapper<N> foundParent = findParentInTree(nestedSetNodeParentId, currentParent);
if (foundParent != null) {
currentParent = foundParent;
} else {
@@ -126,7 +159,7 @@
currentParent.getWrappedChildren().add(nodeWrapper);
currentParent = nodeWrapper;
- return rootWrapper; // Need to return something so that transformList() is called afterwards
+ return rootWrapper; // Return just something so that transformList() will be called when we are done
}
private NestedSetNodeWrapper<N> findParentInTree(Serializable parentId, NestedSetNodeWrapper<N> startNode) {
@@ -147,12 +180,13 @@
}
rootWrapper.setWrappedChildren(flatChildren);
}
- return new ArrayList();
+ return new ArrayList(); // Nothing is returned from this transformer
}
// Recursively flatten tree
private void flattenTree(List<NestedSetNodeWrapper<N>> flatChildren, long i, NestedSetNodeWrapper<N> wrapper) {
- NestedSetNodeWrapper<N> newWrapper = new NestedSetNodeWrapper<N>(wrapper.getWrappedNode(), comparator, i);
+ NestedSetNodeWrapper<N> newWrapper =
+ new NestedSetNodeWrapper<N>(wrapper.getWrappedNode(), comparator, i, wrapper.getAdditionalProjections());
flatChildren.add( newWrapper );
if (wrapper.getWrappedChildren().size() > 0 && wrapper.getLevel() < flattenToLevel) {
i++;
1.2 +10 -0 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeWrapper.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: NestedSetNodeWrapper.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeWrapper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- NestedSetNodeWrapper.java 17 Aug 2007 13:00:23 -0000 1.1
+++ NestedSetNodeWrapper.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -48,15 +48,21 @@
List<NestedSetNodeWrapper<N>> wrappedChildren = new ArrayList<NestedSetNodeWrapper<N>>();
Comparator<NestedSetNodeWrapper<N>> comparator;
Long level;
+ Map<String, Object> additionalProjections = new HashMap<String, Object>();
public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator) {
this(wrappedNode, comparator, 0l);
}
public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator, Long level) {
+ this(wrappedNode, comparator, level, new HashMap<String,Object>());
+ }
+
+ public NestedSetNodeWrapper(N wrappedNode, Comparator<NestedSetNodeWrapper<N>> comparator, Long level, Map<String,Object> additionalProjections) {
this.wrappedNode = wrappedNode;
this.comparator = comparator;
this.level = level;
+ this.additionalProjections = additionalProjections;
}
public N getWrappedNode() {
@@ -91,6 +97,10 @@
return level;
}
+ public Map<String, Object> getAdditionalProjections() {
+ return additionalProjections;
+ }
+
public SortedSet<NestedSetNodeWrapper<N>> getWrappedChildrenSorted() {
SortedSet<NestedSetNodeWrapper<N>> sortedSet = new TreeSet<NestedSetNodeWrapper<N>>(comparator);
sortedSet.addAll(getWrappedChildren());
1.2 +1 -1 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostInsertEventListener.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: NestedSetPostInsertEventListener.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetPostInsertEventListener.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- NestedSetPostInsertEventListener.java 17 Aug 2007 13:00:23 -0000 1.1
+++ NestedSetPostInsertEventListener.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -23,7 +23,7 @@
public void onPostInsert(PostInsertEvent event) {
super.onPostInsert(event);
- if (event.getEntity() instanceof NestedSetNode) {
+ if ( event.getEntity() instanceof NestedSetNode && !((NestedSetNode)event.getEntity()).vetoNestedSetUpdate() ) {
log.debug("executing nested set insert operation, recalculating the tree");
new InsertNestedSetOperation( (NestedSetNode)event.getEntity() ).execute(event.getSession());
}
1.2 +14 -0 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNode.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: NestedSetNode.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNode.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- NestedSetNode.java 17 Aug 2007 13:00:23 -0000 1.1
+++ NestedSetNode.java 25 Aug 2007 17:59:20 -0000 1.2
@@ -25,6 +25,19 @@
public Long getId();
/**
+ * A node can veto any nested set updates.
+ * <p>
+ * This is useful if a particular instance doesn't really belong into the tree but has
+ * the same type. For example, if you have <tt>FileSystemNode</tt> implements
+ * <tt>NestedSetNode</tt> and <tt>HistoricalFileSystemNode</tt> (for audit logging, saved
+ * to a completely different table than the tree) then <tt>HistoricalFileSystemNode</tt>
+ * can return a veto when it is saved, so that the main tree will not be updated.
+ *
+ * @return true if a particular instance should not trigger nested set tree updates
+ */
+ public boolean vetoNestedSetUpdate();
+
+ /**
* Nested set updates require that direct DML is executed by event listeners, this is
* the name of the entity that is used by the event listeners. You can in most cases
* return the simple class name of an instance, unless you customize your persistent
@@ -37,6 +50,7 @@
* @return the persistent entity name of the superclass that implements this interface
*/
public String getTreeSuperclassEntityName();
+ public Class getTreeSuperclass();
/**
* Utility method required until TODO: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615
1.1 date: 2007/08/25 17:59:20; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeDuplicator.java
Index: NestedSetNodeDuplicator.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.core.nestedset;
/**
* Generate a copy of a <tt>NestedSetNode</tt>.
*
* <p>
* Used by the <tt>NestedSetResultTransformer</tt> to duplicate nodes after retrieving them
* from the database. Useful if you need a copy of the tree for display purposes which is stable and
* does not reflect any changes to the underlying real persistent nodes. This copy should be not
* connected or hollow, that is, you should copy only the miminum properties you require for display
* and probably not any collections or to-one entity references.
* </p>
*
* @author Christian Bauer
*/
public interface NestedSetNodeDuplicator<N> {
/**
* Make a (probably hollow) copy of the given node.
* <p>
* You <b>have to</b> ensure that the copy holds the same identifier value as the original.
* </p>
* @param nestedSetNode the persistent node from the database
* @return null if a copy couln't be made, skipping the node in the tree result transformation
*/
public N duplicate(N nestedSetNode);
}
More information about the jboss-cvs-commits
mailing list