/*******************************************************************************
 * Copyright (c) 2005, 2009 SAP. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     SAP - initial API and implementation
 ******************************************************************************/

package org.eclipse.persistence.testing.tests.wdf.jpa1.entitymanager;

import java.util.Set;

import javax.persistence.EntityManager;

import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment;
import org.eclipse.persistence.testing.framework.wdf.ToBeInvestigated;
import org.eclipse.persistence.testing.models.wdf.jpa1.node.CascadingNode;
import org.eclipse.persistence.testing.models.wdf.jpa1.node.CascadingNodeDescription;
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base;
import org.junit.Test;

public class TestCascadeMerge extends JPA1Base {

    @Test
    @ToBeInvestigated
    public void testCascadeNew() {
        /*
         * If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new
         * managed entity instance X'.
         * 
         * For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL,
         * Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed
         * then X is the same object as X'.)
         */
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            CascadingNode parent = new CascadingNode(1, null);
            CascadingNodeDescription parentDescription = new CascadingNodeDescription(2, null, "new parent");
            parent.setDescription(parentDescription);
            CascadingNode child = new CascadingNode(3, null);
            CascadingNodeDescription childDescription = new CascadingNodeDescription(4, null, "new child");
            child.setDescription(childDescription);
            CascadingNode grandchild = new CascadingNode(5, null);
            CascadingNodeDescription grandchildDescription = new CascadingNodeDescription(6, null, "new grandchild");
            grandchild.setDescription(grandchildDescription);
            parent.addChild(child);
            child.addChild(grandchild);
            env.beginTransaction(em);
            CascadingNode mergedNode = em.merge(parent);
            verify(mergedNode.getId() == parent.getId(), "merged entity has wrong id: expected " + parent.getId() + ", got "
                    + mergedNode.getId());
            verify(mergedNode != parent, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            CascadingNodeDescription mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == parentDescription.getId(), "merged entity has wrong id: expected "
                    + parentDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != parentDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            Set<CascadingNode> mergedChildren = mergedNode.getChildren();
            verify(mergedChildren.size() == 1, "Wrong number of children: expected 1, got " + mergedChildren.size());
            for (CascadingNode temp : mergedChildren) {
                mergedNode = temp;
                break;
            }
            verify(mergedNode.getId() == child.getId(), "merged entity has wrong id: expected " + child.getId() + ", got "
                    + mergedNode.getId());
            verify(mergedNode != child, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == childDescription.getId(), "merged entity has wrong id: expected "
                    + childDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != childDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            mergedChildren = mergedNode.getChildren();
            verify(mergedChildren.size() == 1, "Wrong number of children: expected 1, got " + mergedChildren.size());
            for (CascadingNode temp : mergedChildren) {
                mergedNode = temp;
                break;
            }
            verify(mergedNode.getId() == grandchild.getId(), "merged entity has wrong id: expected " + grandchild.getId()
                    + ", got " + mergedNode.getId());
            verify(mergedNode != grandchild, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == grandchildDescription.getId(), "merged entity has wrong id: expected "
                    + grandchildDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != grandchildDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            mergedChildren = mergedNode.getChildren();
            verify(mergedChildren == null, "merged entity has children");
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            verifyExistence(em, grandchild);
            verifyExistence(em, grandchildDescription);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    @ToBeInvestigated
    public void testCascadeDetached() {
        /*
         * If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same
         * identity or a new managed copy X' of X is created.
         * 
         * For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL,
         * Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed
         * then X is the same object as X'.)
         */
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            // types of being detached:
            // parent, parentDescription: not in persistence context but on db
            // child, childDescription: different object with same pk in persistence context, state FOR_UPDATE
            // grandchild, grandchildDescription: different object with same pk in persistence context, state FOR_INSERT
            CascadingNode parent = new CascadingNode(101, null);
            CascadingNodeDescription parentDescription = new CascadingNodeDescription(102, null, "new parent");
            parent.setDescription(parentDescription);
            CascadingNode child = new CascadingNode(103, null);
            CascadingNodeDescription childDescription = new CascadingNodeDescription(104, null, "new child");
            child.setDescription(childDescription);
            parent.addChild(child);
            env.beginTransaction(em);
            em.persist(parent);
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            env.beginTransaction(em);
            CascadingNode grandchild = new CascadingNode(105, null);
            CascadingNodeDescription grandchildDescription = new CascadingNodeDescription(106, null, "new grandchild");
            grandchild.setDescription(grandchildDescription);
            child.addChild(grandchild);
            CascadingNode managedChild = em.find(CascadingNode.class, new Integer(child.getId()));
            CascadingNodeDescription managedChildDescription = em.find(CascadingNodeDescription.class, new Integer(
                    childDescription.getId()));
            CascadingNode managedGrandchild = new CascadingNode(grandchild.getId(), null);
            CascadingNodeDescription managedGrandchildDescription = new CascadingNodeDescription(grandchildDescription.getId(),
                    null, "new grandchild");
            managedGrandchild.setDescription(managedGrandchildDescription);
            managedChild.addChild(managedGrandchild);
            em.persist(managedGrandchild);
            verify(!em.contains(parent), "parent is managed");
            verify(!em.contains(parentDescription), "parentDescription is managed");
            verify(!em.contains(child), "child is managed");
            verify(!em.contains(childDescription), "childDescription is managed");
            verify(!em.contains(grandchild), "grandchild is managed");
            verify(!em.contains(grandchildDescription), "grandchildDescription is managed");
            verify(em.contains(managedChild), "managedChild is not managed");
            verify(em.contains(managedChildDescription), "managedChildDescription is not managed");
            verify(em.contains(managedGrandchild), "managedGrandchild is not managed");
            verify(em.contains(managedGrandchildDescription), "managedGrandchildDescription is not managed");
            // setup complete
            CascadingNode mergedNode = em.merge(parent);
            verify(mergedNode.getId() == parent.getId(), "merged entity has wrong id: expected " + parent.getId() + ", got "
                    + mergedNode.getId());
            verify(mergedNode != parent, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            CascadingNodeDescription mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == parentDescription.getId(), "merged entity has wrong id: expected "
                    + parentDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != parentDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            Set<CascadingNode> mergedChildren = mergedNode.getChildren();
            verify(mergedChildren.size() == 1, "Wrong number of children: expected 1, got " + mergedChildren.size());
            for (CascadingNode temp : mergedChildren) {
                mergedNode = temp;
                break;
            }
            verify(mergedNode.getId() == child.getId(), "merged entity has wrong id: expected " + child.getId() + ", got "
                    + mergedNode.getId());
            verify(mergedNode != child, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == childDescription.getId(), "merged entity has wrong id: expected "
                    + childDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != childDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            mergedChildren = mergedNode.getChildren();
            verify(mergedChildren.size() == 1, "Wrong number of children: expected 1, got " + mergedChildren.size());
            for (CascadingNode temp : mergedChildren) {
                mergedNode = temp;
                break;
            }
            verify(mergedNode.getId() == grandchild.getId(), "merged entity has wrong id: expected " + grandchild.getId()
                    + ", got " + mergedNode.getId());
            verify(mergedNode != grandchild, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == grandchildDescription.getId(), "merged entity has wrong id: expected "
                    + grandchildDescription.getId() + ", got " + mergedDescription.getId());
            verify(mergedDescription != grandchildDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            mergedChildren = mergedNode.getChildren();
            verify(mergedChildren == null, "merged entity has children");
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            verifyExistence(em, grandchild);
            verifyExistence(em, grandchildDescription);
        } finally {
            closeEntityManager(em);
        }
    }

    /**
     * Scenario: Merge a detached entity in case an entity with the same primary key but different object identiy exists in the
     * persistence context <b>in state FOR_DELETE</b>. The specification does not state clearly how to behave in that case. We
     * decided to throw an IllegalArgumentException.
     */
    @Test
    public void testCascadeDetachedRemoved() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            // child, childDescription: different object with same pk in persistence context, state FOR_DELETE
            // others: detached (other types)
            CascadingNode parent = new CascadingNode(201, null);
            CascadingNodeDescription parentDescription = new CascadingNodeDescription(202, null, "new parent");
            parent.setDescription(parentDescription);
            CascadingNode child = new CascadingNode(203, null);
            CascadingNodeDescription childDescription = new CascadingNodeDescription(204, null, "new child");
            child.setDescription(childDescription);
            CascadingNode grandchild = new CascadingNode(205, null);
            CascadingNodeDescription grandchildDescription = new CascadingNodeDescription(206, null, "new grandchild");
            grandchild.setDescription(grandchildDescription);
            parent.addChild(child);
            child.addChild(grandchild);
            env.beginTransaction(em);
            em.persist(parent);
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            verifyExistence(em, grandchild);
            verifyExistence(em, grandchildDescription);
            env.beginTransaction(em);
            CascadingNode managedParent = em.find(CascadingNode.class, new Integer(parent.getId()));
            CascadingNodeDescription managedParentDescription = em.find(CascadingNodeDescription.class, new Integer(
                    parentDescription.getId()));
            CascadingNode managedChild = em.find(CascadingNode.class, new Integer(child.getId()));
            CascadingNodeDescription managedChildDescription = em.find(CascadingNodeDescription.class, new Integer(
                    childDescription.getId()));
            CascadingNode managedGrandchild = em.find(CascadingNode.class, new Integer(grandchild.getId()));
            CascadingNodeDescription managedGrandchildDescription = em.find(CascadingNodeDescription.class, new Integer(
                    grandchildDescription.getId()));
            managedParent.setChildren(null);
            em.remove(managedChild);
            em.persist(managedGrandchild);
            verify(!em.contains(parent), "parent is managed");
            verify(!em.contains(parentDescription), "parentDescription is managed");
            verify(!em.contains(child), "child is managed");
            verify(!em.contains(childDescription), "childDescription is managed");
            verify(!em.contains(grandchild), "grandchild is managed");
            verify(!em.contains(grandchildDescription), "grandchildDescription is managed");
            verify(em.contains(managedParent), "managedParent is not managed");
            verify(em.contains(managedParentDescription), "managedParentDescription is not managed");
            verify(!em.contains(managedChild), "managedChild is not in state FOR_DELETE");
            verify(!em.contains(managedChildDescription), "managedChildDescription is not in state FOR_DELETE");
            verify(em.contains(managedGrandchild), "managedGrandchild is not managed");
            verify(em.contains(managedGrandchildDescription), "managedGrandchildDescription is not managed");
            // setup complete
            boolean mergeFailed = false;
            try {
                em.merge(parent);
            } catch (IllegalArgumentException e) {
                // $JL-EXC$ this is expected behavior
                mergeFailed = true;
            }
            verify(mergeFailed, "Merge did not throw IllegalArgumentException");
            verify(em.contains(managedParent), "managedParent is not managed");
            verify(em.contains(managedParentDescription), "managedParentDescription is not managed");
            verify(managedParent.getDescription() == managedParentDescription, "managedParent has wrong description");
            Set<CascadingNode> children = managedParent.getChildren();
            verify(children == null || children.size() == 0, "parent has children");
            verify(!em.contains(managedChild), "managedChild is not in state FOR_DELETE");
            verify(!em.contains(managedChildDescription), "managedChildDescription is not in state FOR_DELETE");
            verify(em.contains(managedGrandchild), "managedGrandchild is not managed");
            verify(em.contains(managedGrandchildDescription), "managedGrandchildDescription is not managed");
            verify(managedGrandchild.getDescription() == managedGrandchildDescription,
                    "managedGrandchild has wrong description");
            env.rollbackTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            verifyExistence(em, grandchild);
            verifyExistence(em, grandchildDescription);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testCircularCascade() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            CascadingNode node1 = new CascadingNode(301, null);
            CascadingNode node2 = new CascadingNode(302, null);
            env.beginTransaction(em);
            em.persist(node1);
            em.persist(node2);
            env.commitTransactionAndClear(em);
            verifyExistence(em, node1);
            verifyExistence(em, node2);
            node1.addChild(node2);
            node2.addChild(node1);
            env.beginTransaction(em);
            CascadingNode mergedNode1 = em.merge(node1);
            verify(em.contains(mergedNode1), "mergedNode1 not managed");
            Set<CascadingNode> childrenOfNode1 = mergedNode1.getChildren();
            verify(childrenOfNode1.size() == 1, "Wrong number of children: expected 1, got " + childrenOfNode1.size());
            CascadingNode childOfNode1 = null;
            for (CascadingNode temp : childrenOfNode1) {
                childOfNode1 = temp;
                break;
            }
            verify(childOfNode1.getId() == node2.getId(), "childOfNode1 has wrong id: " + childOfNode1.getId());
            verify(em.contains(childOfNode1), "childOfNode1 not managed");
            Set<CascadingNode> childrenOfNode2 = childOfNode1.getChildren();
            verify(childrenOfNode2.size() == 1, "Wrong number of children: expected 1, got " + childrenOfNode2.size());
            CascadingNode childOfNode2 = null;
            for (CascadingNode temp : childrenOfNode2) {
                childOfNode2 = temp;
                break;
            }
            verify(childOfNode2 == mergedNode1, "mergedNode1 not child of childOfNode1");
            env.commitTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }

    /**
     * Tests a scenario where two nodes with the same primary key are related to each other, one is managed, the other detached.
     */
    @Test
    public void testCircularCascadeWithSamePks() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            CascadingNode managedNode = new CascadingNode(401, null);
            CascadingNode detachedNode = new CascadingNode(managedNode.getId(), null);
            env.beginTransaction(em);
            em.persist(managedNode);
            env.commitTransactionAndClear(em);
            verifyExistence(em, managedNode);
            env.beginTransaction(em);
            managedNode = em.find(CascadingNode.class, new Integer(managedNode.getId()));
            managedNode.addChild(detachedNode);
            detachedNode.addChild(managedNode);
            CascadingNode mergedNode = em.merge(detachedNode);
            verify(em.contains(mergedNode), "mergedNode not managed");
            verify(mergedNode == managedNode, "mergedNode not identical to managedNode");
            Set<CascadingNode> children = mergedNode.getChildren();
            verify(children.size() == 1, "Wrong number of children: expected 1, got " + children.size());
            CascadingNode child = null;
            for (CascadingNode temp : children) {
                child = temp;
                break;
            }
            verify(child == managedNode, "child is not identical to managedNode");
            env.commitTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testCascadeManaged() {
        /*
         * If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities
         * referenced by relationships from X if these relationships have been annotated with the cascade element value
         * cascade=MERGE or cascade=ALL annotation.
         * 
         * For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL,
         * Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed
         * then X is the same object as X'.)
         */
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            // states:
            // parent, parentDescription: managed
            // child, childDescription: new
            CascadingNode parent = new CascadingNode(501, null);
            CascadingNodeDescription parentDescription = new CascadingNodeDescription(502, null, "managed parent");
            parent.setDescription(parentDescription);
            CascadingNode child = new CascadingNode(503, null);
            CascadingNodeDescription childDescription = new CascadingNodeDescription(504, null, "new child");
            child.setDescription(childDescription);
            env.beginTransaction(em);
            em.persist(parent);
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyAbsence(em, child);
            verifyAbsence(em, childDescription);
            env.beginTransaction(em);
            parent = em.find(CascadingNode.class, new Integer(parent.getId()));
            parent.addChild(child);
            // setup complete
            CascadingNode mergedNode = em.merge(parent);
            verify(mergedNode == parent, "merge returned a copy of the managed entity");
            verify(em.contains(mergedNode), "merged entity not managed");
            CascadingNodeDescription mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == parentDescription.getId(), "merged entity has wrong id: expected "
                    + parentDescription.getId() + ", got " + mergedNode.getId());
            verify(mergedDescription != parentDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            Set<CascadingNode> mergedChildren = mergedNode.getChildren();
            verify(mergedChildren.size() == 1, "Wrong number of children: expected 1, got " + mergedChildren.size());
            for (CascadingNode temp : mergedChildren) {
                mergedNode = temp;
                break;
            }
            verify(mergedNode.getId() == child.getId(), "merged entity has wrong id: expected " + child.getId() + ", got "
                    + mergedNode.getId());
            verify(mergedNode != child, "merged entity not a copy");
            verify(em.contains(mergedNode), "merged entity not managed");
            mergedDescription = mergedNode.getDescription();
            verify(mergedDescription.getId() == childDescription.getId(), "merged entity has wrong id: expected "
                    + childDescription.getId() + ", got " + mergedNode.getId());
            verify(mergedDescription != childDescription, "merged entity not a copy");
            verify(em.contains(mergedDescription), "merged entity not managed");
            mergedChildren = mergedNode.getChildren();
            verify(mergedChildren == null || mergedChildren.size() == 0, "Node has children, expected none");
            env.commitTransactionAndClear(em);
            verifyExistence(em, parent);
            verifyExistence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testCascadeRemoved() {
        /*
         * If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the
         * transaction commit will fail).
         */
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            // states:
            // parent, parentDescription: new
            // child, childDescription: removed
            CascadingNode parent = new CascadingNode(601, null);
            CascadingNodeDescription parentDescription = new CascadingNodeDescription(602, null, "new parent");
            parent.setDescription(parentDescription);
            CascadingNode child = new CascadingNode(603, null);
            CascadingNodeDescription childDescription = new CascadingNodeDescription(604, null, "removed child");
            child.setDescription(childDescription);
            env.beginTransaction(em);
            em.persist(child);
            env.commitTransactionAndClear(em);
            verifyAbsence(em, parent);
            verifyAbsence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
            env.beginTransaction(em);
            child = em.find(CascadingNode.class, new Integer(child.getId()));
            em.remove(child);
            parent.addChild(child);
            verify(!em.contains(parent), "parent not new");
            verify(!em.contains(child), "child not removed");
            // setup complete
            boolean mergeFailed = false;
            boolean immediateException = false;
            try {
                em.merge(parent);
            } catch (IllegalArgumentException e) {
                mergeFailed = true;
                immediateException = true;
                verify(!em.contains(parent), "parent not new");
                verify(!em.contains(child), "child not removed");
            }
            if (!immediateException) {
                try {
                    env.commitTransactionAndClear(em);
                } catch (RuntimeException e) {
                    if (!checkForPersistenceException(e)) {
                        throw e;
                    }
                    mergeFailed = true;
                }
            } else {
                env.rollbackTransactionAndClear(em);
            }
            verify(mergeFailed, "merge succeeded on a removed entity");
            verifyAbsence(em, parent);
            verifyAbsence(em, parentDescription);
            verifyExistence(em, child);
            verifyExistence(em, childDescription);
        } finally {
            closeEntityManager(em);
        }
    }

    private void verifyExistence(EntityManager em, Object entity) {
        if (entity instanceof CascadingNode) {
            CascadingNode node = (CascadingNode) entity;
            CascadingNode found = em.find(CascadingNode.class, new Integer(node.getId()));
            verify(found != null, "cascading node with id " + node.getId() + " not found");
        } else if (entity instanceof CascadingNodeDescription) {
            CascadingNodeDescription desc = (CascadingNodeDescription) entity;
            CascadingNodeDescription found = em.find(CascadingNodeDescription.class, new Integer(desc.getId()));
            verify(found != null, "cascading node description with id " + desc.getId() + " not found");
        } else {
            throw new IllegalArgumentException("not supported");
        }
    }

    private void verifyAbsence(EntityManager em, Object entity) {
        if (entity instanceof CascadingNode) {
            CascadingNode node = (CascadingNode) entity;
            CascadingNode found = em.find(CascadingNode.class, new Integer(node.getId()));
            verify(found == null, "cascading node with id " + node.getId() + " found");
        } else if (entity instanceof CascadingNodeDescription) {
            CascadingNodeDescription desc = (CascadingNodeDescription) entity;
            CascadingNodeDescription found = em.find(CascadingNodeDescription.class, new Integer(desc.getId()));
            verify(found == null, "cascading node description with id " + desc.getId() + " found");
        } else {
            throw new IllegalArgumentException("not supported");
        }
    }
}
