diff --git a/.gitignore b/.gitignore index 496ee2c..1e2e0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.DS_Store \ No newline at end of file +.DS_Store +/.idea/ +.idea/ +JpaNestedSet.iml diff --git a/pom.xml b/pom.xml index 5537e96..dc60dd6 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,8 @@ maven-compiler-plugin 2.1 - 1.6 - 1.6 + 1.7 + 1.7 true true true @@ -47,46 +47,15 @@ org.hibernate.javax.persistence - hibernate-jpa-2.0-api - 1.0.1.Final + hibernate-jpa-2.1-api + 1.0.0.Final - - org.eclipse.persistence - eclipselink - 2.0.0 - test - - - hsqldb - hsqldb - 1.8.0.7 - test - - - mysql - mysql-connector-java - 5.1.18 - test - - - org.testng - testng - 5.10 - test - jdk15 - javax.inject javax.inject 1 provided - - org.eclipse.persistence - javax.persistence - 2.0.0 - test - net.jcip jcip-annotations @@ -95,14 +64,53 @@ org.slf4j slf4j-api - 1.5.10 + 1.7.21 + + + org.hibernate + hibernate-core + 4.3.11.Final + provided + + + + org.apache.geronimo.specs + geronimo-jms_1.1_spec + + - ch.qos.logback - logback-classic - 0.9.18 + org.hibernate + hibernate-entitymanager + 4.3.11.Final + provided + + + org.apache.geronimo.specs + geronimo-jms_1.1_spec + + + + + junit + junit + 4.12 test + + org.hsqldb + hsqldb + 2.2.9 + test + + diff --git a/src/main/java/org/code_factory/jpa/nestedset/JpaNestedSetManager.java b/src/main/java/org/code_factory/jpa/nestedset/JpaNestedSetManager.java index 42ac618..d32e9e5 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/JpaNestedSetManager.java +++ b/src/main/java/org/code_factory/jpa/nestedset/JpaNestedSetManager.java @@ -1,6 +1,6 @@ /** * LICENSE - * + *

* This source file is subject to the MIT license that is bundled * with this package in the file MIT.txt. * It is also available through the world-wide-web at this URL: @@ -22,15 +22,18 @@ import javax.inject.Inject; import javax.persistence.Entity; import javax.persistence.EntityManager; +import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; + import net.jcip.annotations.NotThreadSafe; import org.code_factory.jpa.nestedset.annotations.LeftColumn; import org.code_factory.jpa.nestedset.annotations.LevelColumn; import org.code_factory.jpa.nestedset.annotations.RightColumn; import org.code_factory.jpa.nestedset.annotations.RootColumn; +import org.hibernate.transform.AliasToEntityMapResultTransformer; /** * @author Roman Borschel @@ -41,6 +44,7 @@ public class JpaNestedSetManager implements NestedSetManager { private final EntityManager em; private final Map> nodes; private final Map, Configuration> configs; + private final Long defaultRootId = 1L; @Inject public JpaNestedSetManager(EntityManager em) { @@ -78,14 +82,14 @@ public Collection> getNodes() { */ @Override public List> fetchTreeAsList(Class clazz) { - return fetchTreeAsList(clazz, 0); + return fetchTreeAsList(clazz, defaultRootId); } /** * {@inheritDoc} */ @Override - public List> fetchTreeAsList(Class clazz, int rootId) { + public List> fetchTreeAsList(Class clazz, Long rootId) { Configuration config = getConfig(clazz); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(clazz); @@ -104,17 +108,54 @@ public List> fetchTreeAsList(Class clazz, int ro return tree; } + @Override + public List> fetchTreeAsAdjacencyList(Class clazz) { + return fetchTreeAsAdjacencyList(clazz, defaultRootId, 0); + } + + @Override + public List> fetchTreeAsAdjacencyList(Class clazz, Long rootId) { + return fetchTreeAsAdjacencyList(clazz, rootId, 0); + } + + @Override + public List> fetchTreeAsAdjacencyList(Class clazz, Long rootId, int maxLevel) { + Configuration config = getConfig(clazz); + + StringBuilder sb = new StringBuilder(); + sb.append("SELECT node.*,") + .append(" parent.id parent_id ") + .append(" FROM ").append(config.getEntityName()).append(" node ") + .append(" JOIN ").append(config.getEntityName()).append(" parent ") + .append(" ON node.").append(config.getLeftFieldName()) + .append(" BETWEEN parent.").append(config.getLeftFieldName()).append(" AND parent.").append(config.getRightFieldName()) + .append(" WHERE node.").append(config.getLevelFieldName()).append(" = parent.").append(config.getLevelFieldName()).append(" + 1") + .append(" AND node.").append(config.getRootIdFieldName()).append(" = ").append(rootId); + + if (maxLevel > 0) { + sb.append(" AND node.").append(config.getLevelFieldName()).append(" < ").append(maxLevel); + } + + Query query = em.createNativeQuery(sb.toString()); + + org.hibernate.Query hibernateQuery = ((org.hibernate.jpa.HibernateQuery) query) + .getHibernateQuery(); + hibernateQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE); + + return hibernateQuery.list(); + } + /** * {@inheritDoc} */ @Override - public Node fetchTree(Class clazz, int rootId) { + public Node fetchTree(Class clazz, Long rootId) { return fetchTreeAsList(clazz, rootId).get(0); } @Override public Node fetchTree(Class clazz) { - return fetchTree(clazz, 0); + return fetchTree(clazz, defaultRootId); } /** @@ -178,10 +219,13 @@ public Node createRoot(T root) { root.setLeftValue(maximumRight + 1); root.setRightValue(maximumRight + 2); root.setLevel(0); + if (root.getRootValue() == null) { + root.setRootValue(defaultRootId); + } em.persist(root); return getNode(root); } - + /** * {@inheritDoc} */ @@ -213,22 +257,19 @@ public Node getNode(T nodeInfo) { Configuration getConfig(Class clazz) { if (!this.configs.containsKey(clazz)) { Configuration config = new Configuration(); - + Entity entity = clazz.getAnnotation(Entity.class); - String name = entity.name(); - config.setEntityName( (name != null && name.length()>0) ? name : clazz.getSimpleName()); + String name = entity.name(); + config.setEntityName((name != null && name.length() > 0) ? name : clazz.getSimpleName()); for (Field field : clazz.getDeclaredFields()) { if (field.getAnnotation(LeftColumn.class) != null) { config.setLeftFieldName(field.getName()); - } - else if (field.getAnnotation(RightColumn.class) != null) { + } else if (field.getAnnotation(RightColumn.class) != null) { config.setRightFieldName(field.getName()); - } - else if (field.getAnnotation(LevelColumn.class) != null) { + } else if (field.getAnnotation(LevelColumn.class) != null) { config.setLevelFieldName(field.getName()); - } - else if (field.getAnnotation(RootColumn.class) != null) { + } else if (field.getAnnotation(RootColumn.class) != null) { config.setRootIdFieldName(field.getName()); } } @@ -238,18 +279,18 @@ else if (field.getAnnotation(RootColumn.class) != null) { return this.configs.get(clazz); } - + int getMaximumRight(Class clazz) { - Configuration config = getConfig(clazz); - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(clazz); + Configuration config = getConfig(clazz); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(clazz); Root queryRoot = cq.from(clazz); cq.orderBy(cb.desc(queryRoot.get(config.getRightFieldName()))); - ListhighestRows = em.createQuery(cq).setMaxResults(1).getResultList(); + List highestRows = em.createQuery(cq).setMaxResults(1).getResultList(); if (highestRows.isEmpty()) { - return 0; + return 0; } else { - return highestRows.get(0).getRightValue(); + return highestRows.get(0).getRightValue(); } } @@ -260,9 +301,9 @@ int getMaximumRight(Class clazz) { * @param cq * @param rootId */ - void applyRootId(Class clazz, CriteriaQuery cq, int rootId) { + void applyRootId(Class clazz, CriteriaQuery cq, Long rootId) { Configuration config = getConfig(clazz); - if (config.getRootIdFieldName() != null) { + if (config.getRootIdFieldName() != null && rootId != null) { Root root = cq.getRoots().iterator().next(); CriteriaBuilder cb = em.getCriteriaBuilder(); Predicate p = cq.getRestriction(); @@ -276,9 +317,9 @@ void applyRootId(Class clazz, CriteriaQuery cq, int rootId) { * * @param minLeft The lower bound (inclusive) of the left values to update. * @param maxLeft The upper bound (inclusive) of the left values to update. - * @param delta The delta to apply on the left values within the range. + * @param delta The delta to apply on the left values within the range. */ - void updateLeftValues(int minLeft, int maxLeft, int delta, int rootId) { + void updateLeftValues(int minLeft, int maxLeft, int delta, Long rootId) { for (Node node : this.nodes.values()) { if (node.getRootValue() == rootId) { if (node.getLeftValue() >= minLeft && (maxLeft == 0 || node.getLeftValue() <= maxLeft)) { @@ -295,9 +336,9 @@ void updateLeftValues(int minLeft, int maxLeft, int delta, int rootId) { * * @param minRight The lower bound (inclusive) of the right values to update. * @param maxRight The upper bound (inclusive) of the right values to update. - * @param delta The delta to apply on the right values within the range. + * @param delta The delta to apply on the right values within the range. */ - void updateRightValues(int minRight, int maxRight, int delta, int rootId) { + void updateRightValues(int minRight, int maxRight, int delta, Long rootId) { for (Node node : this.nodes.values()) { if (node.getRootValue() == rootId) { if (node.getRightValue() >= minRight && (maxRight == 0 || node.getRightValue() <= maxRight)) { @@ -312,11 +353,11 @@ void updateRightValues(int minRight, int maxRight, int delta, int rootId) { * INTERNAL: * Updates the level values of all nodes currently known to the manager. * - * @param left The lower bound left value. + * @param left The lower bound left value. * @param right The upper bound right value. * @param delta The delta to apply on the level values of the nodes within the range. */ - void updateLevels(int left, int right, int delta, int rootId) { + void updateLevels(int left, int right, int delta, Long rootId) { for (Node node : this.nodes.values()) { if (node.getRootValue() == rootId) { if (node.getLeftValue() > left && node.getRightValue() < right) { @@ -327,7 +368,7 @@ void updateLevels(int left, int right, int delta, int rootId) { } } - void removeNodes(int left, int right, int rootId) { + void removeNodes(int left, int right, Long rootId) { Set removed = new HashSet(); for (Node node : this.nodes.values()) { if (node.getRootValue() == rootId) { @@ -341,7 +382,7 @@ void removeNodes(int left, int right, int rootId) { n.setLeftValue(0); n.setRightValue(0); n.setLevel(0); - n.setRootValue(0); + n.setRootValue(null); this.em.detach(n.unwrap()); } } diff --git a/src/main/java/org/code_factory/jpa/nestedset/JpaNode.java b/src/main/java/org/code_factory/jpa/nestedset/JpaNode.java index 345b1f1..1a3345c 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/JpaNode.java +++ b/src/main/java/org/code_factory/jpa/nestedset/JpaNode.java @@ -60,39 +60,39 @@ public JpaNode(T node, JpaNestedSetManager nsm) { this.type = (Class) node.getClass(); } - @Override public int getId() { + @Override public Long getId() { return this.node.getId(); } - @Override public int getLeftValue() { + @Override public Integer getLeftValue() { return this.node.getLeftValue(); } - @Override public int getRightValue() { + @Override public Integer getRightValue() { return this.node.getRightValue(); } - @Override public int getLevel() { + @Override public Integer getLevel() { return this.node.getLevel(); } - @Override public int getRootValue() { + @Override public Long getRootValue() { return this.node.getRootValue(); } - @Override public void setRootValue(int value) { + @Override public void setRootValue(Long value) { this.node.setRootValue(value); } - @Override public void setLeftValue(int value) { + @Override public void setLeftValue(Integer value) { this.node.setLeftValue(value); } - @Override public void setRightValue(int value) { + @Override public void setRightValue(Integer value) { this.node.setRightValue(value); } - @Override public void setLevel(int level) { + @Override public void setLevel(Integer level) { this.node.setLevel(level); } @@ -294,9 +294,9 @@ public Node getParent() { throw new IllegalArgumentException("Cannot add node as child of itself."); } - int newLeft = getRightValue(); - int newRight = getRightValue() + 1; - int newRoot = getRootValue(); + Integer newLeft = getRightValue(); + Integer newRight = getRightValue() + 1; + Long newRoot = getRootValue(); shiftRLValues(newLeft, 0, 2, newRoot); child.setLevel(getLevel() + 1); @@ -318,9 +318,9 @@ private void insertAsPrevSiblingOf(Node dest) { throw new IllegalArgumentException("Cannot add node as child of itself."); } - int newLeft = dest.getLeftValue(); - int newRight = dest.getLeftValue() + 1; - int newRoot = dest.getRootValue(); + Integer newLeft = dest.getLeftValue(); + Integer newRight = dest.getLeftValue() + 1; + Long newRoot = dest.getRootValue(); shiftRLValues(newLeft, 0, 2, newRoot); setLevel(dest.getLevel()); @@ -340,9 +340,9 @@ private void insertAsNextSiblingOf(Node dest) { throw new IllegalArgumentException("Cannot add node as child of itself."); } - int newLeft = dest.getRightValue() + 1; - int newRight = dest.getRightValue() + 2; - int newRoot = dest.getRootValue(); + Integer newLeft = dest.getRightValue() + 1; + Integer newRight = dest.getRightValue() + 2; + Long newRoot = dest.getRootValue(); shiftRLValues(newLeft, 0, 2, newRoot); setLevel(dest.getLevel()); @@ -362,9 +362,9 @@ private void insertAsLastChildOf(Node dest) { throw new IllegalArgumentException("Cannot add node as child of itself."); } - int newLeft = dest.getRightValue(); - int newRight = dest.getRightValue() + 1; - int newRoot = dest.getRootValue(); + Integer newLeft = dest.getRightValue(); + Integer newRight = dest.getRightValue() + 1; + Long newRoot = dest.getRootValue(); shiftRLValues(newLeft, 0, 2, newRoot); setLevel(dest.getLevel() + 1); @@ -384,9 +384,9 @@ private void insertAsFirstChildOf(Node dest) { throw new IllegalArgumentException("Cannot add node as child of itself."); } - int newLeft = dest.getLeftValue() + 1; - int newRight = dest.getLeftValue() + 2; - int newRoot = dest.getRootValue(); + Integer newLeft = dest.getLeftValue() + 1; + Integer newRight = dest.getLeftValue() + 2; + Long newRoot = dest.getRootValue(); shiftRLValues(newLeft, 0, 2, newRoot); setLevel(dest.getLevel()); @@ -402,7 +402,7 @@ private void insertAsFirstChildOf(Node dest) { @Override public void delete() { //TODO: Remove deleted nodes that are in-memory from JpaNestedSetManager. - int oldRoot = getRootValue(); + Long oldRoot = getRootValue(); Configuration cfg = nsm.getConfig(this.type); String rootIdFieldName = cfg.getRootIdFieldName(); String leftFieldName = cfg.getLeftFieldName(); @@ -445,7 +445,7 @@ public void delete() { * @param delta The offset by which to shift the left/right values (can be negative). * @param rootId The root/tree ID of the nodes to shift. */ - private void shiftRLValues(int first, int last, int delta, int rootId) { + private void shiftRLValues(int first, int last, int delta, Long rootId) { Configuration cfg = nsm.getConfig(this.type); String rootIdFieldName = cfg.getRootIdFieldName(); String leftFieldName = cfg.getLeftFieldName(); @@ -462,7 +462,7 @@ private void shiftRLValues(int first, int last, int delta, int rootId) { sbLeft.append(" and n.").append(leftFieldName).append(" <= ?3"); } - if (rootIdFieldName != null) { + if (rootIdFieldName != null && rootId != null) { sbLeft.append(" and n.").append(rootIdFieldName).append(" = ?4"); } @@ -472,7 +472,7 @@ private void shiftRLValues(int first, int last, int delta, int rootId) { if (last > 0) { qLeft.setParameter(3, last); } - if (rootIdFieldName != null) { + if (rootIdFieldName != null && rootId != null) { qLeft.setParameter(4, rootId); } qLeft.executeUpdate(); @@ -488,7 +488,7 @@ private void shiftRLValues(int first, int last, int delta, int rootId) { sbRight.append(" and n.").append(rightFieldName).append(" <= ?3"); } - if (rootIdFieldName != null) { + if (rootIdFieldName != null && rootId != null) { sbRight.append(" and n.").append(rootIdFieldName).append(" = ?4"); } @@ -498,7 +498,7 @@ private void shiftRLValues(int first, int last, int delta, int rootId) { if (last > 0) { qRight.setParameter(3, last); } - if (rootIdFieldName != null) { + if (rootIdFieldName != null && rootId != null) { qRight.setParameter(4, rootId); } qRight.executeUpdate(); @@ -631,13 +631,13 @@ public void moveAsPrevSiblingOf(Node dest) { /** * move node's and its children to location 'destLeft' and update rest of tree. * - * @param int destLeft destination left value + * @param destLeft destLeft destination left value * @param levelDiff */ private void updateNode(int destLeft, int levelDiff) { - int left = getLeftValue(); - int right = getRightValue(); - int rootId = getRootValue(); + Integer left = getLeftValue(); + Integer right = getRightValue(); + Long rootId = getRootValue(); int treeSize = right - left + 1; // Make room in the new branch @@ -756,11 +756,11 @@ private void moveBetweenTrees(Node dest, int newLeftValue, int moveType) { String entityName = cfg.getEntityName(); // Move between trees: Detach from old tree & insert into new tree - int newRoot = dest.getRootValue(); - int oldRoot = getRootValue(); - int oldLft = getLeftValue(); - int oldRgt = getRightValue(); - int oldLevel = getLevel(); + Long newRoot = dest.getRootValue(); + Long oldRoot = getRootValue(); + Integer oldLft = getLeftValue(); + Integer oldRgt = getRightValue(); + Integer oldLevel = getLevel(); // Prepare target tree for insertion, make room shiftRLValues(newLeftValue, 0, oldRgt - oldLft - 1, newRoot); @@ -831,7 +831,7 @@ private void moveBetweenTrees(Node dest, int newLeftValue, int moveType) { * * @param newRootId */ - public void makeRoot(int newRootId) { + public void makeRoot(Long newRootId) { if (isRoot()) { return; } @@ -842,15 +842,15 @@ public void makeRoot(int newRootId) { String levelFieldName = cfg.getLevelFieldName(); String rootIdFieldName = cfg.getRootIdFieldName(); String entityName = cfg.getEntityName(); - - int oldRgt = getRightValue(); - int oldLft = getLeftValue(); - int oldRoot = getRootValue(); - int oldLevel = getLevel(); + + Integer oldRgt = getRightValue(); + Integer oldLft = getLeftValue(); + Long oldRoot = getRootValue(); + Integer oldLevel = getLevel(); // Update descendants lft/rgt/root/level values int diff = 1 - oldLft; - int newRoot = newRootId; + Long newRoot = newRootId; StringBuilder updateQuery = new StringBuilder(); updateQuery.append("update ").append(entityName).append(" n") diff --git a/src/main/java/org/code_factory/jpa/nestedset/Key.java b/src/main/java/org/code_factory/jpa/nestedset/Key.java index c32ceed..4f5cae3 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/Key.java +++ b/src/main/java/org/code_factory/jpa/nestedset/Key.java @@ -11,15 +11,17 @@ import net.jcip.annotations.Immutable; +import java.util.Objects; + /** * @author Roman Borschel */ @Immutable class Key { private final Class clazz; - private final int id; + private final Long id; - public Key(Class clazz, int id) { + public Key(Class clazz, Long id) { this.clazz = clazz; this.id = id; } @@ -27,7 +29,7 @@ public Key(Class clazz, int id) { @Override public int hashCode() { int hash = 7; hash = 23 * hash + (this.clazz != null ? this.clazz.hashCode() : 0); - hash = 23 * hash + this.id; + hash = 23 * hash + this.id.hashCode(); return hash; } @@ -42,7 +44,7 @@ public Key(Class clazz, int id) { Key otherKey = (Key) other; return this.clazz.equals(otherKey.clazz) - && this.id == otherKey.id; + && this.id.equals(otherKey.id); } @Override public String toString() { diff --git a/src/main/java/org/code_factory/jpa/nestedset/NestedSetManager.java b/src/main/java/org/code_factory/jpa/nestedset/NestedSetManager.java index 5689d76..fd534d9 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/NestedSetManager.java +++ b/src/main/java/org/code_factory/jpa/nestedset/NestedSetManager.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.List; +import java.util.Map; import javax.persistence.EntityManager; /** @@ -46,14 +47,13 @@ public interface NestedSetManager { * @param rootId * @return The root node of the tree. */ - Node fetchTree(Class clazz, int rootId); + Node fetchTree(Class clazz, Long rootId); /** * Fetches the complete tree, returning the root node of the tree. * * @param * @param clazz - * @param rootId * @return The root node of the tree. */ Node fetchTree(Class clazz); @@ -75,7 +75,17 @@ public interface NestedSetManager { * @param rootId * @return The tree in form of a list, starting with the root node. */ - List> fetchTreeAsList(Class clazz, int rootId); + List> fetchTreeAsList(Class clazz, Long rootId); + + /** + * + * @param clazz + * @param + * @return + */ + List> fetchTreeAsAdjacencyList(Class clazz); + List> fetchTreeAsAdjacencyList(Class clazz, Long rootId); + List> fetchTreeAsAdjacencyList(Class clazz, Long rootId, int maxLevel); /** * Gets the EntityManager used by this NestedSetManager. diff --git a/src/main/java/org/code_factory/jpa/nestedset/Node.java b/src/main/java/org/code_factory/jpa/nestedset/Node.java index 6f61c0e..cfc305f 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/Node.java +++ b/src/main/java/org/code_factory/jpa/nestedset/Node.java @@ -67,7 +67,6 @@ public interface Node extends NodeInfo { /** * Gets all ancestors of this node. * - * @param int depth The depth "upstairs". * @return The ancestors of the node. */ List> getAncestors(); diff --git a/src/main/java/org/code_factory/jpa/nestedset/NodeInfo.java b/src/main/java/org/code_factory/jpa/nestedset/NodeInfo.java index 664b326..bd28572 100644 --- a/src/main/java/org/code_factory/jpa/nestedset/NodeInfo.java +++ b/src/main/java/org/code_factory/jpa/nestedset/NodeInfo.java @@ -16,13 +16,13 @@ * @author Roman Borschel */ public interface NodeInfo { - int getId(); - int getLeftValue(); - int getRightValue(); - int getLevel(); - int getRootValue(); - void setLeftValue(int value); - void setRightValue(int value); - void setLevel(int level); - void setRootValue(int value); + Long getId(); + Integer getLeftValue(); + Integer getRightValue(); + Integer getLevel(); + Long getRootValue(); + void setLeftValue(Integer value); + void setRightValue(Integer value); + void setLevel(Integer level); + void setRootValue(Long value); } diff --git a/src/test/java/org/code_factory/jpa/nestedset/BasicTest.java b/src/test/java/org/code_factory/jpa/nestedset/BasicTest.java old mode 100644 new mode 100755 index 6f89613..559b78e --- a/src/test/java/org/code_factory/jpa/nestedset/BasicTest.java +++ b/src/test/java/org/code_factory/jpa/nestedset/BasicTest.java @@ -1,6 +1,6 @@ /** * LICENSE - * + *

* This source file is subject to the MIT license that is bundled * with this package in the file MIT.txt. * It is also available through the world-wide-web at this URL: @@ -9,12 +9,15 @@ package org.code_factory.jpa.nestedset; +import org.code_factory.jpa.nestedset.model.Category; +import org.junit.After; +import org.junit.Test; + import java.util.Iterator; import java.util.List; -import org.code_factory.jpa.nestedset.model.Category; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import java.util.Map; + +import static org.junit.Assert.*; /** * @author Roman Borschel @@ -24,8 +27,9 @@ public class BasicTest extends FunctionalNestedSetTest { private Category javaCat; private Category netCat; - @AfterMethod - @Override protected void closeEntityManager() { + @After + @Override + public void closeEntityManager() { super.closeEntityManager(); this.progCat = null; this.javaCat = null; @@ -59,15 +63,17 @@ private void createBasicTree() { nsm.clear(); } - @Test public void testCreateRoot() { + @Test + public void testCreateRoot() { Category cat = new Category(); cat.setName("Java"); + //cat.setId(1L); em.getTransaction().begin(); nsm.createRoot(cat); em.getTransaction().commit(); em.clear(); - + System.out.println(cat); Category cat2 = em.find(Category.class, cat.getId()); assert 1 == cat2.getLeftValue(); assert 2 == cat2.getRightValue(); @@ -76,7 +82,8 @@ private void createBasicTree() { assert true == nsm.getNode(cat2).isRoot(); } - @Test public void testFetchTree() { + @Test + public void testFetchTree() { this.createBasicTree(); List> tree = nsm.fetchTreeAsList(Category.class); @@ -97,14 +104,19 @@ private void createBasicTree() { assert 5 == node.getRightValue(); assert 1 == node.getLevel(); } + System.out.println(node); } + + List> list = nsm.fetchTreeAsAdjacencyList(Category.class); + System.out.println(list.toString()); } - @Test public void testBasicTreeNavigation() { + @Test + public void testBasicTreeNavigation() { this.createBasicTree(); Category progCat2 = em.find(Category.class, this.progCat.getId()); - + Node progCatNode = nsm.getNode(progCat2); assert 1 == progCatNode.getLeftValue(); @@ -123,13 +135,14 @@ private void createBasicTree() { assert false == child2.hasChildren(); assert 0 == child1.getChildren().size(); assert 0 == child2.getChildren().size(); - + assert progCat2 == child1.getParent().unwrap(); assert progCat2 == child2.getParent().unwrap(); } - @Test public void testAddingNodesToTree() { + @Test + public void testAddingNodesToTree() { this.createBasicTree(); assert 0 == this.nsm.getNodes().size(); @@ -177,11 +190,12 @@ private void createBasicTree() { /** * Tests creating new nodes and moving them around in a tree. */ - @Test public void testMovingNodes() { + @Test + public void testMovingNodes() { this.createBasicTree(); em.getTransaction().begin(); - + Node progNode = this.nsm.getNode(em.find(Category.class, this.progCat.getId())); // Create a new WPF category, placing it under "Programming" first. @@ -254,7 +268,7 @@ private void createBasicTree() { @Test public void testDeleteNode() { this.createBasicTree(); - + em.getTransaction().begin(); // fetch the tree Node progNode = nsm.fetchTree(Category.class, this.progCat.getRootValue()); @@ -266,7 +280,7 @@ public void testDeleteNode() { Category netCat2 = em.find(Category.class, this.netCat.getId()); Node netNode = nsm.getNode(netCat2); netNode.delete(); - + // check in-memory state of tree assert 1 == progNode.getLeftValue(); assert 4 == progNode.getRightValue(); @@ -276,7 +290,8 @@ public void testDeleteNode() { try { nsm.getNode(netCat2); fail("Retrieving node for deleted category should fail."); - } catch (IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { + } em.getTransaction().commit(); } diff --git a/src/test/java/org/code_factory/jpa/nestedset/FunctionalNestedSetTest.java b/src/test/java/org/code_factory/jpa/nestedset/FunctionalNestedSetTest.java old mode 100644 new mode 100755 index 33493f9..ea9aa12 --- a/src/test/java/org/code_factory/jpa/nestedset/FunctionalNestedSetTest.java +++ b/src/test/java/org/code_factory/jpa/nestedset/FunctionalNestedSetTest.java @@ -9,25 +9,26 @@ package org.code_factory.jpa.nestedset; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; /** * * @author robo */ public class FunctionalNestedSetTest { - protected EntityManagerFactory emFactory; + private static EntityManagerFactory emFactory; protected EntityManager em; protected NestedSetManager nsm; - @BeforeClass(alwaysRun=true) - protected void createEntityManagerFactory() { + @BeforeClass + public static void createEntityManagerFactory() { try { emFactory = Persistence.createEntityManagerFactory("TestPU"); } catch (Exception ex) { @@ -35,14 +36,14 @@ protected void createEntityManagerFactory() { } } - @BeforeMethod(alwaysRun=true) - protected void createEntityManager() { + @Before + public void createEntityManager() { em = emFactory.createEntityManager(); this.nsm = new JpaNestedSetManager(this.em); } - @AfterMethod - protected void closeEntityManager() { + @After + public void closeEntityManager() { if (em != null) { em.getTransaction().begin(); em.createQuery("delete from Category").executeUpdate(); @@ -53,7 +54,7 @@ protected void closeEntityManager() { } @AfterClass - protected void closeEntityManagerFactory() { + public static void closeEntityManagerFactory() { if (emFactory != null) { emFactory.close(); } diff --git a/src/test/java/org/code_factory/jpa/nestedset/MultiRootNodeTest.java b/src/test/java/org/code_factory/jpa/nestedset/MultiRootNodeTest.java old mode 100644 new mode 100755 index de37587..2767703 --- a/src/test/java/org/code_factory/jpa/nestedset/MultiRootNodeTest.java +++ b/src/test/java/org/code_factory/jpa/nestedset/MultiRootNodeTest.java @@ -10,7 +10,7 @@ package org.code_factory.jpa.nestedset; import org.code_factory.jpa.nestedset.model.Category; -import org.testng.annotations.Test; +import org.junit.Test; /** * @author Roman Borschel @@ -21,15 +21,15 @@ public class MultiRootNodeTest extends FunctionalNestedSetTest { public void testCreateTrees() { Category javaCat = new Category(); javaCat.setName("Java"); - javaCat.setRootValue(1); + javaCat.setRootValue(1L); Category netCat = new Category(); netCat.setName(".NET"); - netCat.setRootValue(2); + netCat.setRootValue(2L); Category phpCat = new Category(); phpCat.setName("PHP"); - phpCat.setRootValue(3); + phpCat.setRootValue(3L); em.getTransaction().begin(); nsm.createRoot(javaCat); diff --git a/src/test/java/org/code_factory/jpa/nestedset/model/Category.java b/src/test/java/org/code_factory/jpa/nestedset/model/Category.java old mode 100644 new mode 100755 index f4df51f..8e738fc --- a/src/test/java/org/code_factory/jpa/nestedset/model/Category.java +++ b/src/test/java/org/code_factory/jpa/nestedset/model/Category.java @@ -5,10 +5,8 @@ package org.code_factory.jpa.nestedset.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import javax.persistence.*; + import org.code_factory.jpa.nestedset.NodeInfo; import org.code_factory.jpa.nestedset.annotations.LeftColumn; import org.code_factory.jpa.nestedset.annotations.LevelColumn; @@ -20,26 +18,32 @@ */ @Entity public class Category implements NodeInfo { - @Id @GeneratedValue - private int id; + @Id + @GeneratedValue + private Long id; + private String name; @Column(updatable=false) @LeftColumn - private int lft; + private Integer lft; @RightColumn @Column(updatable=false) - private int rgt; + private Integer rgt; @LevelColumn @Column(updatable=false) - private int level; + private Integer level; @RootColumn - private int rootId; + private Long rootId; - @Override public int getId() { + @Override public Long getId() { return this.id; } + public void setId(Long id) { + this.id = id; + } + public String getName() { return this.name; } @@ -49,46 +53,73 @@ public void setName(String name) { } @Override - public int getLeftValue() { + public Integer getLeftValue() { return this.lft; } @Override - public int getRightValue() { + public Integer getRightValue() { return this.rgt; } @Override - public int getLevel() { + public Integer getLevel() { return this.level; } @Override - public void setLeftValue(int value) { + public void setLeftValue(Integer value) { this.lft = value; } @Override - public void setRightValue(int value) { + public void setRightValue(Integer value) { this.rgt = value; } @Override - public void setLevel(int level) { + public void setLevel(Integer level) { this.level = level; } @Override - public int getRootValue() { + public Long getRootValue() { return this.rootId; } @Override - public void setRootValue(int value) { + public void setRootValue(Long value) { this.rootId = value; } @Override public String toString() { return "[Category: id=" + this.id + ", name=" + this.name + "-" + super.toString() + "]"; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Category category = (Category) o; + + if (!id.equals(category.id)) return false; + if (!name.equals(category.name)) return false; + if (!lft.equals(category.lft)) return false; + if (!rgt.equals(category.rgt)) return false; + if (!level.equals(category.level)) return false; + return rootId != null ? rootId.equals(category.rootId) : category.rootId == null; + + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + name.hashCode(); + result = 31 * result + lft.hashCode(); + result = 31 * result + rgt.hashCode(); + result = 31 * result + level.hashCode(); + result = 31 * result + (rootId != null ? rootId.hashCode() : 0); + return result; + } } diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml index 9a7b92b..6270489 100644 --- a/src/test/resources/META-INF/persistence.xml +++ b/src/test/resources/META-INF/persistence.xml @@ -1,25 +1,29 @@ - org.eclipse.persistence.jpa.PersistenceProvider + org.hibernate.jpa.HibernatePersistenceProvider org.code_factory.jpa.nestedset.model.Category - - - - - - - + + + + + + + + + + + +