[jboss-cvs] jboss-seam/examples/wiki/src/test/org/jboss/seam/wiki/test/nestedset ...
Christian Bauer
christian at hibernate.org
Fri Aug 17 09:00:26 EDT 2007
User: cbauer
Date: 07/08/17 09:00:26
Added: examples/wiki/src/test/org/jboss/seam/wiki/test/nestedset
NestedSetTests.java Item.java ItemData.xml
Log:
Major refactoring of core data schema and some new features
Revision Changes Path
1.1 date: 2007/08/17 13:00:26; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/test/org/jboss/seam/wiki/test/nestedset/NestedSetTests.java
Index: NestedSetTests.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.test.nestedset;
import org.hibernate.Query;
import org.hibernate.StatelessSession;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.wiki.core.nestedset.NestedSetNodeWrapper;
import org.jboss.seam.wiki.core.nestedset.NestedSetResultTransformer;
import org.jboss.seam.wiki.test.util.DBUnitSeamTest;
import org.testng.annotations.Test;
import org.dbunit.operation.DatabaseOperation;
import javax.persistence.EntityManager;
import java.util.Comparator;
public class NestedSetTests extends DBUnitSeamTest {
private Log log = Logging.getLog(NestedSetTests.class);
protected void prepareDBUnitOperations() {
beforeTestOperations.add(
new DataSetOperation("org/jboss/seam/wiki/test/nestedset/ItemData.xml", DatabaseOperation.CLEAN_INSERT)
);
}
@Test
public void createTree() throws Exception {
new FacesRequest("/") {
protected void invokeApplication() throws Exception {
EntityManager em = (EntityManager)getValue("#{entityManager}");
/* Tree:
A
/ \
B C
/ \
D E
/\
F G
*/
Item a = new Item("A");
Item b = new Item("B");
Item c = new Item("C");
Item d = new Item("D");
Item e = new Item("E");
Item f = new Item("F");
Item g = new Item("G");
a.addChild(b);
a.addChild(c);
c.addChild(d);
c.addChild(e);
c.addChild(d);
d.addChild(f);
d.addChild(g);
// Cascading persist for children collection!
em.persist(a);
getUserTransaction().commit();
em.clear();
assert checkNestedSetNodeInMemory(a, a.getId(), 1, 14);
assert checkNestedSetChildNodeInMemory(a, b);
assert checkNestedSetChildNodeInMemory(a, c);
assert checkNestedSetChildNodeInMemory(c, d);
assert checkNestedSetChildNodeInMemory(c, e);
assert checkNestedSetChildNodeInMemory(d, f);
assert checkNestedSetChildNodeInMemory(d, g);
assert checkNestedSetNodeInDatabase("A", a.getId(), 1, 14);
assert checkNestedSetChildNodeInDatabase("A", "B");
assert checkNestedSetChildNodeInDatabase("A", "C");
assert checkNestedSetChildNodeInDatabase("C", "D");
assert checkNestedSetChildNodeInDatabase("C", "E");
assert checkNestedSetChildNodeInDatabase("D", "F");
assert checkNestedSetChildNodeInDatabase("D", "G");
displayNodeTree(getItemFromDatabase("A"));
}
}.run();
}
@Test
public void insertNode() throws Exception {
new FacesRequest("/") {
protected void invokeApplication() throws Exception {
EntityManager em = (EntityManager)getValue("#{entityManager}");
/* Tree:
A
/ \
B C
/ \
D E
/\
F G
*/
Item a = new Item("A");
Item b = new Item("B");
Item c = new Item("C");
Item d = new Item("D");
Item e = new Item("E");
Item f = new Item("F");
Item g = new Item("G");
a.addChild(b);
a.addChild(c);
c.addChild(d);
c.addChild(e);
c.addChild(d);
d.addChild(f);
d.addChild(g);
// Cascading persist for children collection!
em.persist(a);
getUserTransaction().commit();
getUserTransaction().begin();
em.joinTransaction();
/* Tree:
A
/ \
B C
/ \
D E
/\ |
F G H
*/
Item h = new Item("H");
e.addChild(h);
em.persist(h);
getUserTransaction().commit();
em.clear();
assert checkNestedSetNodeInMemory(a, a.getId(), 1, 16);
assert checkNestedSetChildNodeInMemory(a, b);
assert checkNestedSetChildNodeInMemory(a, c);
assert checkNestedSetChildNodeInMemory(c, d);
assert checkNestedSetChildNodeInMemory(c, e);
assert checkNestedSetChildNodeInMemory(d, f);
assert checkNestedSetChildNodeInMemory(d, g);
assert checkNestedSetChildNodeInMemory(e, h);
assert checkNestedSetNodeInDatabase("A", a.getId(), 1, 16);
assert checkNestedSetChildNodeInDatabase("A", "B");
assert checkNestedSetChildNodeInDatabase("A", "C");
assert checkNestedSetChildNodeInDatabase("C", "D");
assert checkNestedSetChildNodeInDatabase("C", "E");
assert checkNestedSetChildNodeInDatabase("D", "F");
assert checkNestedSetChildNodeInDatabase("D", "G");
assert checkNestedSetChildNodeInDatabase("E", "H");
displayNodeTree(getItemFromDatabase("A"));
}
}.run();
}
@Test
public void deleteNode() throws Exception {
new FacesRequest("/") {
protected void invokeApplication() throws Exception {
EntityManager em = (EntityManager)getValue("#{entityManager}");
/* Tree:
A
/ \
B C
/ \
D E
/\
F G
*/
Item a = new Item("A");
Item b = new Item("B");
Item c = new Item("C");
Item d = new Item("D");
Item e = new Item("E");
Item f = new Item("F");
Item g = new Item("G");
a.addChild(b);
a.addChild(c);
c.addChild(d);
c.addChild(e);
c.addChild(d);
d.addChild(f);
d.addChild(g);
// Cascading persist for children collection!
em.persist(a);
getUserTransaction().commit();
getUserTransaction().begin();
em.joinTransaction();
/* Tree:
A
/ \
B C
|
E
*/
c.removeChild(d);
em.remove(d);
getUserTransaction().commit();
em.clear();
assert checkNestedSetNodeInMemory(a, a.getId(), 1, 8);
assert checkNestedSetChildNodeInMemory(a, b);
assert checkNestedSetChildNodeInMemory(a, c);
assert checkNestedSetChildNodeInMemory(c, e);
assert checkNestedSetNodeInDatabase("A", a.getId(), 1, 8);
assert checkNestedSetChildNodeInDatabase("A", "B");
assert checkNestedSetChildNodeInDatabase("A", "C");
assert checkNestedSetChildNodeInDatabase("C", "E");
displayNodeTree(getItemFromDatabase("A"));
}
}.run();
}
@Test
public void deleteInsertNode() throws Exception {
new FacesRequest("/") {
protected void invokeApplication() throws Exception {
EntityManager em = (EntityManager)getValue("#{entityManager}");
/* Tree:
A
/ \
B C
/ \
D E
/\
F G
*/
Item a = new Item("A");
Item b = new Item("B");
Item c = new Item("C");
Item d = new Item("D");
Item e = new Item("E");
Item f = new Item("F");
Item g = new Item("G");
a.addChild(b);
a.addChild(c);
c.addChild(d);
c.addChild(e);
c.addChild(d);
d.addChild(f);
d.addChild(g);
// Cascading persist for children collection!
em.persist(a);
getUserTransaction().commit();
getUserTransaction().begin();
em.joinTransaction();
/* Tree:
A
/ \
B C
/ \
E H
*/
c.removeChild(d);
em.remove(d);
Item h = new Item("H");
c.addChild(h);
em.persist(h);
getUserTransaction().commit();
em.clear();
assert checkNestedSetNodeInMemory(a, a.getId(), 1, 10);
assert checkNestedSetChildNodeInMemory(a, b);
assert checkNestedSetChildNodeInMemory(a, c);
assert checkNestedSetChildNodeInMemory(c, e);
assert checkNestedSetChildNodeInMemory(c, h);
assert checkNestedSetNodeInDatabase("A", a.getId(), 1, 10);
assert checkNestedSetChildNodeInDatabase("A", "B");
assert checkNestedSetChildNodeInDatabase("A", "C");
assert checkNestedSetChildNodeInDatabase("C", "E");
assert checkNestedSetChildNodeInDatabase("C", "H");
displayNodeTree(getItemFromDatabase("A"));
}
}.run();
}
/* ############################################################################################################## */
private boolean checkNestedSetNodeInMemory(Item node, long thread, long left, long right) throws Exception {
return node.getNsThread() == thread && node.getNsLeft() == left && node.getNsRight() == right;
}
private boolean checkNestedSetChildNodeInMemory(Item parent, Item node) throws Exception {
return node.getNsThread().equals(parent.getNsThread()) && node.getNsLeft() > parent.getNsLeft() && node.getNsRight() < parent.getNsRight();
}
private boolean checkNestedSetNodeInDatabase(String itemName, long thread, long left, long right) throws Exception {
return checkNestedSetNodeInMemory( getItemFromDatabase(itemName), thread, left, right);
}
private boolean checkNestedSetChildNodeInDatabase(String parentName, String itemName) throws Exception {
return checkNestedSetChildNodeInMemory( getItemFromDatabase(parentName), getItemFromDatabase(itemName));
}
private StatelessSession getStatelessSession() throws Exception {
org.jboss.ejb3.entity.InjectedEntityManagerFactory jbossEMF =
(org.jboss.ejb3.entity.InjectedEntityManagerFactory) getInitialContext().lookup("java:/entityManagerFactories/wiki");
return ((HibernateEntityManagerFactory) jbossEMF.getDelegate()).getSessionFactory().openStatelessSession();
}
private Item getItemFromDatabase(String itemName) throws Exception {
StatelessSession ss = getStatelessSession();
// TODO: EAGER loading of parent doesn't work with StatelessSession, only if I do it in the query...
Item item = (Item) ss.createQuery("select i from Item i left join fetch i.parent where i.name = :name").setParameter("name", itemName).uniqueResult();
ss.close();
return item;
}
private void displayNodeTree(Item startNode) throws Exception {
if (log.isTraceEnabled()) {
StatelessSession session = getStatelessSession();
StringBuffer queryString = new StringBuffer();
queryString.append("select").append(" ");
queryString.append("count(n1.id) as nestedSetNodeLevel").append(", ");
queryString.append("n1 as nestedSetNode").append(" ");
queryString.append("from ").append(startNode.getTreeSuperclassEntityName()).append(" n1, ");
queryString.append(startNode.getTreeSuperclassEntityName()).append(" n2 ");
// TODO: EAGER loading of parent doesn't work with StatelessSession, only if I do it in the query...
queryString.append("left join fetch n1.parent").append(" ");
queryString.append("where n1.nsThread = :thread and n2.nsThread = :thread").append(" ");
queryString.append("and n1.nsLeft between n2.nsLeft and n2.nsRight").append(" ");
queryString.append("and n2.nsLeft > :startLeft and n2.nsRight < :startRight").append(" ");
queryString.append("group by").append(" ");
for (int i = 0; i < startNode.getTreeSuperclassPropertiesForGrouping().length; i++) {
queryString.append("n1.").append(startNode.getTreeSuperclassPropertiesForGrouping()[i]);
if (i != startNode.getTreeSuperclassPropertiesForGrouping().length-1) queryString.append(", ");
}
queryString.append(" ");
queryString.append("order by n1.nsLeft");
Query nestedSetQuery = session.createQuery(queryString.toString());
nestedSetQuery.setParameter("thread", startNode.getNsThread());
nestedSetQuery.setParameter("startLeft", startNode.getNsLeft());
nestedSetQuery.setParameter("startRight", startNode.getNsRight());
// This comparator sorts the Items by name!
Comparator<NestedSetNodeWrapper<Item>> comp =
new Comparator<NestedSetNodeWrapper<Item>>() {
public int compare(NestedSetNodeWrapper<Item> o, NestedSetNodeWrapper<Item> o2) {
return o.getWrappedNode().getName().compareTo(o2.getWrappedNode().getName());
}
};
NestedSetNodeWrapper<Item> startNodeWrapper = new NestedSetNodeWrapper<Item>(startNode, comp, 0l);
nestedSetQuery.setResultTransformer( new NestedSetResultTransformer<Item>(startNodeWrapper) );
nestedSetQuery.list(); // Append all children hierarchically to the startNodeWrapper
log.trace("######################################## TREE BEGIN #####################################################");
displayNodes(startNodeWrapper);
log.trace("######################################## TREE END #####################################################");
session.close();
}
}
private void displayNodes(NestedSetNodeWrapper<Item> startNode) {
StringBuffer levelMarkers = new StringBuffer();
for (int i = 1; i <= startNode.getLevel(); i++) {
levelMarkers.append("#");
}
log.trace(levelMarkers.toString() + " " + startNode);
for (NestedSetNodeWrapper<Item> next : startNode.getWrappedChildren()) {
displayNodes(next);
}
}
}
1.1 date: 2007/08/17 13:00:26; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/test/org/jboss/seam/wiki/test/nestedset/Item.java
Index: Item.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.test.nestedset;
import org.jboss.seam.wiki.core.nestedset.AbstractNestedSetNode;
import javax.persistence.*;
import java.util.Set;
import java.util.HashSet;
@Entity
@Table(name = "ITEM")
public class Item extends AbstractNestedSetNode<Item> {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "PARENT_ITEM_ID")
@org.hibernate.annotations.ForeignKey(name = "FK_ITEM_PARENT_ITEM_ID") // Just a name for the FK constraint
private Item parent;
// Cascade from the root node when you insert, otherwise you need to call persist(item) in the right order,
// in other words: You need to call persist(A) before you call persist(B) and persist(C) if B and C are
// children of A. The order in which B and C are inserted is undefined, this is a Set - it doesn't matter
// because we sort in-memory after loading the children of A.
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
// Foreign key constraint option in the database simplifies deletion of nodes and subnodes
@org.hibernate.annotations.OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
private Set<Item> children = new HashSet<Item>();
@Column(name = "ITEM_NAME", unique = true)
private String name;
public Item() {}
public Item(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public Item getParent() {
return parent;
}
public void setParent(Item parent) {
this.parent = parent;
}
public Set<Item> getChildren() {
return children;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// TODO: Yes, this needs to go away... http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615
public String[] getTreeSuperclassPropertiesForGrouping() {
return new String[] { "nsThread", "nsLeft", "nsRight", "id", "parent", "name"};
}
public String toString() {
return getName() + " (" + getId() + ") THREAD: " + getNsThread() + " " + getNsLeft() + "|" + getNsRight();
}
}
1.1 date: 2007/08/17 13:00:26; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/test/org/jboss/seam/wiki/test/nestedset/ItemData.xml
Index: ItemData.xml
===================================================================
<?xml version="1.0"?>
<dataset>
<ITEM/>
</dataset>
More information about the jboss-cvs-commits
mailing list