[jboss-cvs] jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset ...
Christian Bauer
christian at hibernate.org
Tue Dec 18 23:29:19 EST 2007
User: cbauer
Date: 07/12/18 23:29:19
Modified: examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset
package.html NestedSetNode.java
Added: examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset
AbstractNestedSetDelegate.java
NestedSetNodeInfo.java NestedSetDelegateOwner.java
NestedSetDelegate.java
EmbeddableNestedSetDelegate.java
Removed: examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset
AbstractNestedSetNode.java
DeleteNestedSetOperation.java
NestedSetResultTransformer.java
NestedSetNodeWrapper.java
NestedSetPostInsertEventListener.java
NestedSetNodeWrapperEntityConverter.java
NestedSetNodeDuplicator.java
NestedSetPostDeleteEventListener.java
NestedSetOperation.java
InsertNestedSetOperation.java
Log:
Major rewrite of the most of the application
Revision Changes Path
1.3 +52 -48 jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/package.html
(In the diff below, changes in quantity of whitespace are not shown.)
Index: package.html
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/package.html,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- package.html 17 Oct 2007 15:07:54 -0000 1.2
+++ package.html 19 Dec 2007 04:29:19 -0000 1.3
@@ -181,7 +181,7 @@
<pre>
@Entity
- @Table("NODE")
+ @Table("ITEM")
class Item {
@Id @GeneratedValue
@@ -201,14 +201,15 @@
</pre>
<p>
- You can now overlay a nested set by either implementing the {@link NestedSetNode} interface or by extending
- the default implementation, {@link AbstractNestedSetNode}:
+ This implementation is based on mix-in and delegates. The <tt>ITEM</tt> table of the <tt>Item</tt> class will
+ does not carry the left, right, and thread values. This job is delegated to an additional
+ <tt>ItemNestedSetDelegate</tt> class:
</p>
<pre>
@Entity
- @Table("NODE")
- class Item extends AbstractNestedSetNode<Item> {
+ @Table("ITEM")
+ class Item implements NestedSetDelegateOwner {
@Id @GeneratedValue
@Column(name = "ID")
@@ -218,22 +219,37 @@
@JoinColumn(name = "PARENT")
private Item parent;
- @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
+ @OneToMany(mappedBy = "parent")
@org.hibernate.annotations.OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
private Set<Item> children;
+ @OneToOne(mappedBy="owner",
+ fetch = FetchType.EAGER,
+ cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
+ private ItemNestedSetDelegate nestedSetDelegate;
+
// Constructor, getters and setters
...
}
</pre>
<p>
- This is a mapped and persistent superclass, so additional columns are either created or required on the <tt>NODE</tt>
- table, their default names are <tt>NS_THREAD</tt> (identifies a particular tree), <tt>NS_LEFT</tt>, and
- <tt>NS_RIGHT</tt>. You can override using the JPA <tt>@AttributeOverrides</tt> annotation on the <tt>Item</tt> entity
- class.
+ The delegate class maintains the nested set information transparently and stores it in a separate table:
</p>
+<pre>
+ @Entity
+ @Table("ITEM_NESTED_SET")
+ class ItemNestedSetDelegate extends AbstractNestedSetDelegate<Item> {
+
+ protected ItemNestedSetDelegate() {}
+
+ public ItemNestedSetDelegate(Item owner) {
+ super(owner);
+ }
+ }
+</pre>
+
<p>
It is recommended that you enable <tt>ON DELETE CASCADE</tt> as a foreign key option on the join column of the
adjacency list. With this option, you can easily delete a node in the tree and have the guarantee that all its
@@ -241,22 +257,23 @@
persistence context after deletion or if you have the second-level cache enabled).
</p>
<p>
- Enabling cascading persistence on the collection of children is also recommended. If you do not enable it, you need to call
- <tt>entityManager.persist(item)</tt> in the right order, e.g.: You need to call persist(A) before you
+ You need to call <tt>entityManager.persist(item)</tt> in the right order, e.g.: You need to call persist(A) before you
call persist(B) and persist(C) if B and C are children of A. In any case, the order in which B and C are inserted is
undefined, this is a Set in the example - and it doesn't matter. However, parents need to be inserted before children.
</p>
<p>
The tree is manipulated through the <tt>parent</tt> property and <tt>children</tt> collection of each node. Remember
- to always set both references if you link a node to a parent, which is what the default implementations
- <tt>addChild()</tt> and <tt>removeChild()</tt> of {@link AbstractNestedSetNode} can do for you. If you want to
- save a new item, create it, link it to its parent with <tt>addChild()</tt>, persist it with the
+ to always set both references if you link a node to a parent. If you want to save a new item, create it, link it
+ to its parent with <tt>addChild()</tt>, persist it with the
<tt>EntityManager</tt> and flush the persistence context.
If you want to remove an item from the tree, unlink it with <tt>removeChild()</tt> from its parent, remove it
- with the <tt>EntityManager</tt>, then flush the persistence context. The nested set tree is automatically
- updated by the event listeners in this package, which you have to add to your Hibernate configuration, here
- for JPA with <tt>persistence.xml</tt>:
+ with the <tt>EntityManager</tt>, then flush the persistence context.
+</p>
+
+<p>
+ The nested set tree table is automatically updated by the event listeners in this package, which you have to add
+ to your Hibernate configuration, here for JPA with <tt>persistence.xml</tt>:
</p>
<pre>
@@ -279,46 +296,33 @@
</p>
<p>
- To query for a subtree, use the <tt>NestedSetNodeWrapper</tt> and <tt>NestedSetResultTransformer</tt>
+ To query for a subtree, use the <tt>NestedSetWrapper</tt> and <tt>NestedSetResultTransformer</tt>
convenience classes. An example, loading the whole subtree starting at <tt>startNode</tt> (which would
be an instance of <tt>Item</tt> you have already loaded):
</p>
<pre>
- select
- count(n1.id) as nestedSetNodeLevel,
- n1 as nestedSetNode
- from Item n1, Item n2
- where
- n1.nsThread = :thread and n2.nsThread = :thread
- and n1.nsLeft between n2.nsLeft and n2.nsRight
- and n2.nsLeft > :startLeft and n2.nsRight < :startRight
- group by [allPropertiesOfItem]
- order by n1.nsLeft
-
- // Now bind the thread, left, and right values of the startNode as query arguments to the parameters
-
-
- // This comparator sorts the Items by name!
- Comparator<NestedSetNodeWrapper<Item>> comp =
- new Comparator<NestedSetNodeWrapper<Item>>() {
- public int compare(NestedSetNodeWrapper<Item> o, NestedSetNodeWrapper<Item> o2) {
- // Sort nodes at the same level by name?
- // return o.getWrappedNode().getName().compareTo(o2.getWrappedNode().getName());
- }
- };
+NestedSetQueryBuilder nsQuery = new NestedSetQueryBuilder(startNode);
+Query nestedSetQuery = session.createQuery(nsQuery.getSimpleQuery());
+
+// Bind parameters
+nestedSetQuery.setParameter("nsThread", startNode.getNestedSetDelegate().getNsThread());
+nestedSetQuery.setParameter("nsLeft", startNode.getNestedSetDelegate().getNsLeft());
+nestedSetQuery.setParameter("nsRight", startNode.getNestedSetDelegate().getNsRight());
+
+// Apply transformer that marshalls flat table result into an in-memory tree
+NestedSetNodeWrapper<ItemNestedSetDelegate> startNodeWrapper = new NestedSetNodeWrapper<ItemNestedSetDelegate>(startNode);
+
+nestedSetQuery.setResultTransformer( new NestedSetResultTransformer<ItemNestedSetDelegate>(startNodeWrapper) );
- NestedSetNodeWrapper<Item> startNodeWrapper = new NestedSetNodeWrapper<Item>(startNode, comp);
- nestedSetQuery.setResultTransformer( new NestedSetResultTransformer<Item>(startNodeWrapper) );
- nestedSetQuery.list();
+nestedSetQuery.list();
</pre>
<p>
You can now traverse the tree by accessing <tt>startNodeWrapper.getWrappedParent()</tt>,
<tt>startNodeWrapper.getWrappedChildren()</tt>, <tt>startNodeWrapper.getLevel()</tt>, and
- <tt>startNodeWrapper.getWrappedNode()</tt>. All sub-children are initialized with this single query,
- and the <tt>startNodeWrapper.getWrappedChildrenSorted()</tt> collection is sorted with the
- supplied <tt>Comparator</tt>. Use this comparator for "in-level" sorting of nodes.
+ <tt>startNodeWrapper.getWrappedNode()</tt>. These wrappers wrap nested set delegates, so you get the real node by calling
+ <tt>getOwner()</tt> if necessary. All sub-children as well as their owners are initialized with this single query.
</p>
<p>
1.3 +7 -146 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.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- NestedSetNode.java 25 Aug 2007 17:59:20 -0000 1.2
+++ NestedSetNode.java 19 Dec 2007 04:29:19 -0000 1.3
@@ -1,159 +1,20 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
package org.jboss.seam.wiki.core.nestedset;
-import java.util.Collection;
-
-/**
- * Interface implemented by domain model classes that represent a node in a nested set.
- *
- * @author Christian Bauer
- */
public interface NestedSetNode<N extends NestedSetNode> {
- /**
- * Every node in a nested set needs a stable identifier, the primary key. This currently
- * is limited to numeric (long) values because the nested set model uses the identifier
- * of a root node (a node with no parent) to also identify a particular tree (the thread).
- *
- * @return the stable primary key of the nested set node
- */
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
- * entity identifiers or when inheritance is involved. If, for example, you have a
- * class named <tt>FileSystemNode</tt> that implements <tt>NestedSetNode</tt>, and this
- * class has subclasses <tt>RegularFile</tt> and <tt>Directory</tt>, all instances need
- * to return <tt>FileSystemNode</tt> so that all nodes in the tree can be reached when
- * the nested set manipulation occurs in event listeners.
- *
- * @return the persistent entity name of the superclass that implements this interface
- */
- public String getTreeSuperclassEntityName();
- public Class getTreeSuperclass();
+ public NestedSetNodeInfo<N> getNodeInfo();
+ public NestedSetNodeInfo<N> getParentNodeInfo();
/**
* Utility method required until TODO: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615
- * is implemented. If you query for nested set subtrees, you need to group by all properties of
- * the nested set node implementation class (in fact, the whole hierarchy). So for example,
- * this method would need to return all scalar property names and foreign key property names of
- * classes <tt>FileSystemNode</tt> and its potential subclasses <tt>RegularFile</tt> and
- * <tt>Directory</tt>. Yes, this is not not great.
+ * is implemented. If you query for nested set subtrees, you need to GROUP BY all properties of
+ * the implementor of this interface, including identifier, version, and foreign keys (many-to-one properties).
+ * Yes, this is not great.
*
* @return all property names of scalar and foreign key properties of the nested set class hierarchy
*/
- public abstract String[] getTreeSuperclassPropertiesForGrouping();
-
- /**
- * An implementation must return the parent instance of a node in the tree, this can be mapped
- * as a regular many-to-one. This property should be nullable, that is, the root node of a thread
- * (a thread represents a single tree) does not have a parent. Although not strictly required by
- * the nested set approach (children of a parent can be identified solely by their "left" and
- * "right" values), it simplifies regular navigation "up the tree".
- *
- * @return the parent of this nested set node
- */
- public N getParent();
- public void setParent(N parent);
-
- /**
- * An implementation must return the direct children (the sublevel) of a nested set node. This
- * can be mapped as a regular one-to-many collection, however, you are free to chose the type
- * of collection: lists, bags, and sets all work. This collection is the collection you need
- * to modify if you want to link a child node to a parent (by adding an element) or if you
- * delete a node (by removing an element).
- *
- * @return the immediate children of a nested set node
- */
- public Collection<N> getChildren();
-
- /**
- * Convenience method that should link a node into the tree by adding it to the <tt>children</tt>
- * collection and setting its <tt>parent</tt> to be <i>this</i>.
- *
- * @param child the child node to be added at this level in the tree
- */
- public void addChild(N child);
-
- /**
- * Convenience method that should remove a node from this level of the tree by removing it from
- * the <tt>children</tt> collection and setting its <tt>parent</tt> to null. Called before a
- * node is finally deleted in a persistent fashion, in your application.
- *
- * @param child the child node that is removed from the tree
- * @return the removed child node
- */
- public N removeChild(N child);
-
- /**
- * The root of a tree is a nested set node without a parent. Its identifier is also the thread
- * number of all nodes in that particular tree. So all children nodes (and their children, recursively)
- * need to have the same thread number. This should be mapped as a persistent property of the
- * implementor of this interface, not nullable and not updatable. Any updates that are required are
- * done transparently with event listeners.
- *
- * @return the non-nullable, persistent, and not updatable mapped persistent identifier for a particular tree
- */
- public Long getNsThread();
- public void setNsThread(Long nsThread);
-
- /**
- * In the nested set model, each node requires two additional attributes right visit and left visit. The tree is
- * then traversed in a modified pre-order: starting with the root node, each node is visited twice. Whenever
- * a node is entered or exited during the traversal, the sequence number of all visits is saved in
- * the current node's right visit and left visit. This is the job of the event listeners, not yours. You can
- * retrieve the current value with this method.
- *
- * @return the left value of a node
- */
- public Long getNsLeft();
- public void setNsLeft(Long nsLeft);
-
- /**
- * In the nested set model, each node requires two additional attributes right visit and left visit. The tree is
- * then traversed in a modified pre-order: starting with the root node, each node is visited twice. Whenever
- * a node is entered or exited during the traversal, the sequence number of all visits is saved in
- * the current node's right visit and left visit. This is the job of the event listeners, not yours. You can
- * retrieve the current value with this method.
- *
- * @return the left value of a node
- */
- public Long getNsRight();
- public void setNsRight(Long nsRight);
-
- /**
- * The number of children of this node, only one level deep.
- *
- * @return the number of children of this node, one level deep.
- */
- public int getDirectChildCount();
-
- /**
- * The number of child nodes of this node, total at all sub-levels. This can be calculated by taking
- * the left and right values: <tt>Math.floor((getNsRight() - getNsLeft()) / 2)</tt>
- *
- * @return the total number of children on all sub-levels
- */
- public int getTotalChildCount();
+ public String[] getPropertiesForGroupingInQueries();
+ public String[] getLazyPropertiesForGroupingInQueries();
}
1.1 date: 2007/12/19 04:29:19; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/AbstractNestedSetDelegate.java
Index: AbstractNestedSetDelegate.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;
import javax.persistence.*;
/**
* Utility class that implements the basic {@link NestedSetDelegate} interface.
* <p>
* Use this class if you already have an adjacency list model (parent/children
* relationship mapped with a regular many-to-one property and a one-to-many collection) based
* on a foreign key. You only need to add this superclass to a <tt>@OneToOne</tt> persistent delegate
* entity class and you will be able to execute nested set queries on your trees and have the event listeners
* update the nested set values of the tree (thread, left, right, of each node) if you add or
* remove nodes.
*
* @author Christian Bauer
*/
@MappedSuperclass
public abstract class AbstractNestedSetDelegate<N extends NestedSetDelegateOwner> implements NestedSetDelegate<N> {
@Id
@GeneratedValue(generator = "nestedSetOwnerGenerator")
@org.hibernate.annotations.GenericGenerator(
name = "nestedSetOwnerGenerator",
strategy = "foreign",
parameters = @org.hibernate.annotations.Parameter(name = "property", value = "owner")
)
@Column(name = "NESTED_SET_OWNER_ID")
private Long id;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "NESTED_SET_OWNER_ID", updatable = false, insertable = false, unique = true)
@org.hibernate.annotations.OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
private N owner;
@Column(name = "NS_THREAD", nullable = false, updatable = false)
private Long nsThread = 0l;
@Column(name = "NS_LEFT", nullable = false, updatable = false)
private Long nsLeft = 0l;
@Column(name = "NS_RIGHT", nullable = false, updatable = false)
private Long nsRight = 0l;
protected AbstractNestedSetDelegate() {}
public AbstractNestedSetDelegate(N owner) {
this.owner = owner;
}
public AbstractNestedSetDelegate(N owner, AbstractNestedSetDelegate<N> copyDelegate) {
this.owner = copyDelegate.getOwner();
this.nsLeft = copyDelegate.nsLeft;
this.nsRight = copyDelegate.nsRight;
this.nsThread = copyDelegate.nsThread;
}
public Long getId() {
return id;
}
public N getOwner() {
return owner;
}
public Long getNsThread() {
return nsThread;
}
public void setNsThread(Long nsThread) {
this.nsThread = nsThread;
}
public Long getNsLeft() {
return nsLeft;
}
public void setNsLeft(Long nsLeft) {
this.nsLeft = nsLeft;
}
public Long getNsRight() {
return nsRight;
}
public void setNsRight(Long nsRight) {
this.nsRight = nsRight;
}
}
1.1 date: 2007/12/19 04:29:19; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeInfo.java
Index: NestedSetNodeInfo.java
===================================================================
package org.jboss.seam.wiki.core.nestedset;
import org.hibernate.annotations.Parent;
import javax.persistence.Embeddable;
import javax.persistence.Column;
@Embeddable
public class NestedSetNodeInfo<N extends NestedSetNode> {
@Parent
private N owner;
@Column(name = "NS_THREAD", nullable = false, updatable = false)
private Long nsThread = 0l;
@Column(name = "NS_LEFT", nullable = false, updatable = false)
private Long nsLeft = 0l;
@Column(name = "NS_RIGHT", nullable = false, updatable = false)
private Long nsRight = 0l;
protected NestedSetNodeInfo() {}
public NestedSetNodeInfo(N owner) {
this.owner = owner;
}
public NestedSetNodeInfo(NestedSetNodeInfo<N> original) {
this.owner = original.owner;
this.nsLeft = original.nsLeft;
this.nsRight = original.nsRight;
this.nsThread = original.nsThread;
}
public N getOwner() {
return owner;
}
private void setOwner(N owner) {
this.owner = owner;
}
public Long getNsThread() {
return nsThread;
}
public void setNsThread(Long nsThread) {
this.nsThread = nsThread;
}
public Long getNsLeft() {
return nsLeft;
}
public void setNsLeft(Long nsLeft) {
this.nsLeft = nsLeft;
}
public Long getNsRight() {
return nsRight;
}
public void setNsRight(Long nsRight) {
this.nsRight = nsRight;
}
public String toString() {
return "NSInfo LEFT: " + getNsLeft() + " RIGHT: " + getNsRight() + " THREAD: " + getNsThread();
}
}
1.1 date: 2007/12/19 04:29:19; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetDelegateOwner.java
Index: NestedSetDelegateOwner.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;
/**
* Implemented by domain model classes if they support nested sets.
* <p>
* This is your starting point, add this interface to your domain model class and implement it.
* </p>
* <p>
* You also need to implement a {@link org.jboss.seam.wiki.core.nestedset.NestedSetDelegate} class
* for each domain model class that supports nested sets. You need to map a reference to this
* delegate as follows:
* </p>
* <pre>
* class MyDomainModelClass implements NestedSetDelegateOwner {
*
* // Adjacency list for parent/child
* ...
*
* @OneToOne(mappedBy="owner", fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
* private MyDomainModelClassNestedSetDelegate nestedSetDelegate;
* }
* </pre>
* <p>
* Make sure that every instance of your domain model class has an instance of the delegate,
* a <tt>@OneToOne</tt> to a persistent <tt>NestedSetDelegate</tt> instance (initialize it
* in the constructor). In addition, you need to return the parents delegate (if there is any,
* if not, then null) accordingly.
* </p>
*
* @author Christian Bauer
*/
public interface NestedSetDelegateOwner {
public Long getId();
public NestedSetDelegate getNestedSetDelegate();
public NestedSetDelegate getParentNestedSetDelegate();
/**
* Utility method required until TODO: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615
* is implemented. If you query for nested set subtrees, you need to GROUP BY all properties of
* the implementor of this interface, including identifier, version, and foreign keys (many-to-one properties).
* Yes, this is not great.
*
* @return all property names of scalar and foreign key properties of the nested set class hierarchy
*/
public String[] getPropertiesForGroupingInQueries();
}
1.1 date: 2007/12/19 04:29:19; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetDelegate.java
Index: NestedSetDelegate.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;
/**
* Interface implemented by domain model classes that represent a node in a nested set.
* Usually used as a delegate, that is, an existing class that already has a parent/children
* adjacency list adds a <tt>@OneToOne</tt> association to a delegate that implements this
* interface. This (more or less) transparently adds nested set information to each instance.
*
* @author Christian Bauer
*/
public interface NestedSetDelegate<N extends NestedSetDelegateOwner> {
/**
* Same as <tt>getOwner().getId()</tt> but it makes our life easier.
*
* @return Identifier of the nested set node, i.e. the owner of the delegate.
*/
public Long getId();
/**
* The domain model class that wishes to add nested set information should implement a
* delegate to this interface. The domain model class also has to implement
* <tt>NestedSetDelegateOwner</tt>. This method returns that owner.
*
* @return the owner of the <tt>NestedSetNodeDelegate</tt>, which implements <tt>NestedSetDelegateOwner</tt>
*/
public N getOwner();
/**
* The root of a tree is a nested set node without a parent. Its identifier is also the thread
* number of all nodes in that particular tree. So all children nodes (and their children, recursively)
* need to have the same thread number. This should be mapped as a persistent property of the
* implementor of this interface, not nullable and not updatable. Any updates that are required are
* done transparently with event listeners.
*
* @return the non-nullable, persistent, and not updatable mapped persistent identifier for a particular tree
*/
public Long getNsThread();
public void setNsThread(Long nsThread);
/**
* In the nested set model, each node requires two additional attributes right visit and left visit. The tree is
* then traversed in a modified pre-order: starting with the root node, each node is visited twice. Whenever
* a node is entered or exited during the traversal, the sequence number of all visits is saved in
* the current node's right visit and left visit. This is the job of the event listeners, not yours. You can
* retrieve the current value with this method.
*
* @return the left value of a node
*/
public Long getNsLeft();
public void setNsLeft(Long nsLeft);
/**
* In the nested set model, each node requires two additional attributes right visit and left visit. The tree is
* then traversed in a modified pre-order: starting with the root node, each node is visited twice. Whenever
* a node is entered or exited during the traversal, the sequence number of all visits is saved in
* the current node's right visit and left visit. This is the job of the event listeners, not yours. You can
* retrieve the current value with this method.
*
* @return the left value of a node
*/
public Long getNsRight();
public void setNsRight(Long nsRight);
}
1.1 date: 2007/12/19 04:29:19; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/EmbeddableNestedSetDelegate.java
Index: EmbeddableNestedSetDelegate.java
===================================================================
package org.jboss.seam.wiki.core.nestedset;
import org.hibernate.annotations.Parent;
import javax.persistence.Embeddable;
import javax.persistence.Column;
@Embeddable
public class EmbeddableNestedSetDelegate<N extends NestedSetDelegateOwner> implements NestedSetDelegate<N> {
@Parent
private N owner;
@Column(name = "NS_THREAD", nullable = false, updatable = false)
private Long nsThread = 0l;
@Column(name = "NS_LEFT", nullable = false, updatable = false)
private Long nsLeft = 0l;
@Column(name = "NS_RIGHT", nullable = false, updatable = false)
private Long nsRight = 0l;
protected EmbeddableNestedSetDelegate() {}
public EmbeddableNestedSetDelegate(N owner) {
this.owner = owner;
}
public EmbeddableNestedSetDelegate(N owner, EmbeddableNestedSetDelegate<N> copyDelegate) {
this.owner = copyDelegate.getOwner();
this.nsLeft = copyDelegate.nsLeft;
this.nsRight = copyDelegate.nsRight;
this.nsThread = copyDelegate.nsThread;
}
public Long getId() {
return getOwner().getId();
}
public N getOwner() {
return owner;
}
private void setOwner(N owner) {
this.owner = owner;
}
public Long getNsThread() {
return nsThread;
}
public void setNsThread(Long nsThread) {
this.nsThread = nsThread;
}
public Long getNsLeft() {
return nsLeft;
}
public void setNsLeft(Long nsLeft) {
this.nsLeft = nsLeft;
}
public Long getNsRight() {
return nsRight;
}
public void setNsRight(Long nsRight) {
this.nsRight = nsRight;
}
}
More information about the jboss-cvs-commits
mailing list