/******************************************************************************* | |
* 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.sql.Connection; | |
import java.sql.PreparedStatement; | |
import java.sql.ResultSet; | |
import java.sql.SQLException; | |
import javax.persistence.EntityManager; | |
import javax.persistence.PersistenceException; | |
import javax.persistence.TransactionRequiredException; | |
import org.eclipse.persistence.testing.framework.wdf.Bugzilla; | |
import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment; | |
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Cubicle; | |
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.CubiclePrimaryKeyClass; | |
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Department; | |
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base; | |
import org.junit.Ignore; | |
import org.junit.Test; | |
public class TestRemove extends JPA1Base { | |
private void verifyAbsenceOnDatabase(int departmentId) throws SQLException { | |
Connection conn = getEnvironment().getDataSource().getConnection(); | |
try { | |
PreparedStatement stmt = conn.prepareStatement("select ID, NAME from TMP_DEP where ID = ?"); | |
try { | |
stmt.setInt(1, departmentId); | |
ResultSet rs = stmt.executeQuery(); | |
try { | |
verify(!rs.next(), "department with id " + departmentId + " found using JDBC."); | |
} finally { | |
rs.close(); | |
} | |
} finally { | |
stmt.close(); | |
} | |
} finally { | |
conn.close(); | |
} | |
} | |
@Test | |
public void testRemoveNew() throws SQLException { | |
/* | |
* If X is a new entity, it is ignored by the remove operation. However, the remove operation is cascaded to entities | |
* referenced by X, if the relationships from X to these other entities is annotated with the cascade=REMOVE or | |
* cascade=ALL annotation element value. | |
*/ | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
env.evictAll(em); | |
try { | |
Department dep = new Department(1, "HUGO"); | |
env.beginTransaction(em); | |
em.remove(dep); | |
// TODO verify remove is ignored on this entity using lifecycle callbacks | |
// TODO verify | |
env.commitTransactionAndClear(em); | |
verifyAbsenceOnDatabase(1); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
private void verifyRemoveManaged(boolean flushBeforeRemove) throws SQLException { | |
/* | |
* If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to | |
* entities referenced by X, if the relationships from X to these other entities is annotated with the cascade=REMOVE or | |
* cascade=ALL annotation element value. | |
*/ | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
try { | |
// 1. managed and in state MANAGED | |
final int id1 = (flushBeforeRemove ? 100 : 0) + 11; | |
Department dep = new Department(id1, "OLD"); | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
// find a department in the state MANAGED | |
dep = em.find(Department.class, new Integer(id1)); | |
verify(dep != null, "department not found"); | |
dep.setName("NEW"); | |
if (flushBeforeRemove) { | |
em.flush(); | |
} | |
em.remove(dep); | |
env.commitTransactionAndClear(em); | |
verifyAbsenceOnDatabase(id1); | |
// 2. managed and in state NEW | |
final int id2 = (flushBeforeRemove ? 100 : 0) + 12; | |
dep = new Department(id2, "OLD"); | |
env.beginTransaction(em); | |
em.persist(dep); | |
dep.setName("NEW"); | |
if (flushBeforeRemove) { | |
em.flush(); | |
} | |
em.remove(dep); | |
env.commitTransactionAndClear(em); | |
verifyAbsenceOnDatabase(id2); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
public void testRemoveManaged() throws SQLException { | |
verifyRemoveManaged(false); | |
} | |
@Test | |
public void testRemoveManagedFlushed() throws SQLException { | |
verifyRemoveManaged(true); | |
} | |
private void verifyRemoveRemoved(boolean flushBeforePersist) throws SQLException { | |
/* | |
* If X is a removed entity, it is ignored by the remove operation. | |
*/ | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
env.evictAll(em); | |
try { | |
// 1. find an existing department, remove it and remove it again | |
final int id1 = (flushBeforePersist ? 100 : 0) + 21; | |
Department dep = new Department(id1, "REMOVE"); | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
dep = em.find(Department.class, new Integer(id1)); | |
em.remove(dep); | |
// no, the entity should be REMOVED | |
if (flushBeforePersist) { | |
em.flush(); | |
} | |
em.remove(dep); | |
env.commitTransactionAndClear(em); | |
// now, the entity should be managed again | |
verifyAbsenceOnDatabase(id1); | |
// 2. persist a new depatrment, remove it and call remove | |
env.beginTransaction(em); | |
final int id2 = (flushBeforePersist ? 100 : 0) + 22; | |
dep = new Department(id2, "REMOVE"); | |
em.persist(dep); | |
em.remove(dep); | |
if (flushBeforePersist) { | |
em.flush(); | |
} | |
em.remove(dep); | |
env.commitTransactionAndClear(em); | |
verifyAbsenceOnDatabase(id2); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
public void testRemoveRemoved() throws SQLException { | |
verifyRemoveRemoved(false); | |
} | |
@Test | |
public void testRemoveRemovedFlushed() throws SQLException { | |
verifyRemoveRemoved(true); | |
} | |
@Test | |
public void testRemoveDetached() { | |
/* | |
* If X is a detached entity, an IllegalArgumentException will be thrown by the remove operation (or the transaction | |
* commit will fail). | |
*/ | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
int id; | |
Department dep; | |
Department detachedDep; | |
try { | |
// case 1: detached because entity exists on db but is not known by persistence context | |
id = 31; | |
dep = new Department(id, "DETACHED"); | |
// firstly, we create a department on the database | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
// now the department is detached, we try to remove it | |
env.beginTransaction(em); | |
boolean failed = false; | |
try { | |
em.remove(dep); | |
} catch (IllegalArgumentException e) { | |
failed = true; | |
env.rollbackTransactionAndClear(em); | |
} | |
try { | |
if (env.isTransactionActive(em)) { | |
env.commitTransactionAndClear(em); | |
} | |
} catch (PersistenceException e) { | |
failed = true; | |
} | |
verify(failed, "remove succeeded on a detached instance."); | |
// case 2: detached because an object with same pk but different object identity is known by persistence context | |
// case 2a: state of known object: FOR_INSERT | |
id = 32; | |
dep = new Department(id, "MANAGED_NEW"); | |
detachedDep = new Department(id, "DETACHED"); | |
failed = false; | |
env.beginTransaction(em); | |
em.persist(dep); // object is now in state MANAGED_NEW | |
try { | |
em.remove(detachedDep); | |
} catch (IllegalArgumentException e) { | |
failed = true; | |
env.rollbackTransaction(em); | |
} | |
try { | |
if (env.isTransactionActive(em)) { | |
env.commitTransactionAndClear(em); | |
} | |
} catch (PersistenceException e) { | |
failed = true; | |
} | |
verify(failed, "remove succeeded on a detached instance."); | |
// case 2b: state of known object: FOR_UPDATE | |
id = 33; | |
dep = new Department(id, "MANAGED"); | |
detachedDep = new Department(id, "DETACHED"); | |
failed = false; | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
dep = em.find(Department.class, new Integer(id)); // object is now in state MANAGED | |
try { | |
em.remove(detachedDep); | |
} catch (IllegalArgumentException e) { | |
failed = true; | |
env.rollbackTransactionAndClear(em); | |
} | |
try { | |
if (env.isTransactionActive(em)) { | |
env.commitTransactionAndClear(em); | |
} | |
} catch (PersistenceException e) { | |
failed = true; | |
} | |
verify(failed, "remove succeeded on a detached instance."); | |
// case 2c: state of known object: FOR_DELETE | |
id = 34; | |
dep = new Department(id, "DELETED"); | |
detachedDep = new Department(id, "DETACHED"); | |
failed = false; | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
dep = em.find(Department.class, new Integer(id)); | |
em.remove(dep); // object is now in state DELETED | |
try { | |
em.remove(detachedDep); | |
} catch (IllegalArgumentException e) { | |
failed = true; | |
env.rollbackTransactionAndClear(em); | |
} | |
try { | |
if (env.isTransactionActive(em)) { | |
env.commitTransactionAndClear(em); | |
} | |
} catch (PersistenceException e) { | |
failed = true; | |
} | |
verify(failed, "remove succeeded on a detached instance."); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
@Bugzilla(bugid=309681) // INTERPRETATION: SAP JPA has special state DELETED_EXECUTED, which EclipseLink hasn't | |
public void testRemoveFlushRemoveAgain() { | |
/* | |
* If X is a detached entity, an IllegalArgumentException will be thrown by the remove operation (or the transaction | |
* commit will fail). | |
*/ | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
int id; | |
Department dep; | |
Department detachedDep; | |
try { | |
// case 2d: state of known object: DELETE_EXECUTED | |
id = 35; | |
dep = new Department(id, "DELETED"); | |
detachedDep = new Department(id, "DETACHED"); | |
boolean failed = false; | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
dep = em.find(Department.class, new Integer(id)); | |
em.remove(dep); | |
em.flush(); | |
try { | |
em.remove(detachedDep); | |
} catch (IllegalArgumentException e) { | |
failed = true; | |
env.rollbackTransactionAndClear(em); | |
} | |
try { | |
if (env.isTransactionActive(em)) { | |
env.commitTransactionAndClear(em); | |
} | |
} catch (PersistenceException e) { | |
failed = true; | |
} | |
verify(failed, "remove succeeded on a detached instance."); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
public void testNotAnEntity() { | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
try { | |
env.beginTransaction(em); | |
try { | |
em.remove("Hutzliputz"); | |
flop("no IllegalArgumentException "); | |
} catch (IllegalArgumentException e) { | |
verify(true, ""); | |
} finally { | |
env.rollbackTransactionAndClear(em); | |
} | |
env.beginTransaction(em); | |
try { | |
em.remove(null); | |
flop("no IllegalArgumentException "); | |
} catch (IllegalArgumentException e) { | |
verify(true, ""); | |
} finally { | |
env.rollbackTransactionAndClear(em); | |
} | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
public void testRemoveWithCompositeKey() { | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
try { | |
Cubicle cub = new Cubicle(new Integer(30), new Integer(31), "green", null /* employee */); | |
CubiclePrimaryKeyClass cubKey = new CubiclePrimaryKeyClass(new Integer(30), new Integer(31)); | |
env.beginTransaction(em); | |
em.persist(cub); | |
env.commitTransactionAndClear(em); | |
env.beginTransaction(em); | |
cub = em.find(Cubicle.class, cubKey); | |
em.remove(cub); | |
env.commitTransactionAndClear(em); | |
cub = em.find(Cubicle.class, cubKey); | |
verify(cub == null, "cubicle not removed"); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Ignore // @TestProperties(unsupportedEnvironments={JTANonSharedPCEnvironment.class, ResourceLocalEnvironment.class}) | |
public void testNoTransaction() { | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
Department dep = new Department(40, "dep40"); | |
try { | |
em.remove(dep); | |
flop("exception not thrown as expected"); | |
} catch (TransactionRequiredException e) { | |
// $JL-EXC$ expected behavior | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
@Test | |
public void testTransactionMarkedForRollback() { | |
final JPAEnvironment env = getEnvironment(); | |
final EntityManager em = env.getEntityManager(); | |
Department dep = new Department(41, "dep41"); | |
try { | |
env.beginTransaction(em); | |
em.persist(dep); | |
env.commitTransaction(em); | |
em.clear(); | |
env.beginTransaction(em); | |
dep = em.find(Department.class, Integer.valueOf(dep.getId())); | |
env.markTransactionForRollback(em); | |
em.remove(dep); | |
verify(!em.contains(dep), "entity still contained in persistence context"); | |
env.rollbackTransaction(em); | |
} finally { | |
closeEntityManager(em); | |
} | |
} | |
} |