blob: 4145e72e340392076e6fd6f8027021ce2bbc1a1f [file] [log] [blame]
/*
* Copyright (c) 2005, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2015 SAP. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// SAP - initial API and implementation
package org.eclipse.persistence.testing.tests.wdf.jpa1.entitymanager;
import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.Query;
import jakarta.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.Department;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Employee;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Review;
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base;
import org.junit.Ignore;
import org.junit.Test;
public class TestRefresh extends JPA1Base {
@Test
public void testRefreshNew() {
/*
* Refresh on an entity that is not under control of the entity manager
* should throw an IllegalArgumentException.
*/
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
try {
id = 1;
dep = new Department(id, "NEW");
env.beginTransaction(em);
try {
em.refresh(dep);
flop("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
verify(true, "");
}
env.rollbackTransactionAndClear(em);
} finally {
closeEntityManager(em);
}
}
@Test
@Bugzilla(bugid = 309681)
public void testRefreshManagedNew() throws SQLException {
/*
* Note: The specification doesn't state explicitly how to behave in
* this case, so we test our interpretation: - If the entity doesn't
* exist on the database, nothing is changed - If the entity exists on
* the database, the data is loaded and the state changes from
* FOR_INSERT to FOR_UPDATE (in order to avoid errors at flush time)
*/
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
try {
// case 2: state MANAGED_NEW, but exists on DB (inserted in
// different tx)
id = 12;
dep = new Department(id, "MANAGED_NEW");
Department depInserted = new Department(id, "INSERTED");
env.beginTransaction(em);
em.persist(dep);
insertDepartmentIntoDatabase(depInserted);
verifyExistenceOnDatabase(id);
// entity is now in state MANAGED_NEW, but record exists on db
em.refresh(dep);
checkDepartment(dep, id, "INSERTED"); // this should now be in state
// MANAGED
verify(em.contains(dep), "Department is not managed");
dep.setName("UPDATED");
env.commitTransactionAndClear(em);
// verify that updated name present on db
dep = em.find(Department.class, id);
checkDepartment(dep, id, "UPDATED");
} finally {
closeEntityManager(em);
}
}
@Test
@Bugzilla(bugid = 309681)
public void testRefreshManagedNewNotOnDB() throws SQLException {
/*
* Note: The specification doesn't state explicitly how to behave in
* this case, so we test our interpretation: - If the entity doesn't
* exist on the database, nothing is changed - If the entity exists on
* the database, the data is loaded and the state changes from
* FOR_INSERT to FOR_UPDATE (in order to avoid errors at flush time)
*/
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
try {
// case 1: state MANAGED_NEW and does not exist on DB
id = 11;
dep = new Department(id, "MANAGED_NEW");
env.beginTransaction(em);
em.persist(dep); // this is now in state MANAGED_NEW, but not on db
em.refresh(dep); // nothing should happen
verify(em.contains(dep), "Department is not managed");
env.commitTransactionAndClear(em);
verifyExistenceOnDatabase(id);
} finally {
closeEntityManager(em);
}
}
@Test
public void testRefreshManaged() throws SQLException {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
Department updatedDep;
try {
// case 1: undo own changes
id = 21;
dep = new Department(id, "MANAGED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id); // this is now in
// state MANAGED
dep.setName("UPDATED");
em.refresh(dep);
checkDepartment(dep, id, "MANAGED");
verify(em.contains(dep), "Department is not managed");
env.commitTransactionAndClear(em);
// verify that original name present on db
dep = em.find(Department.class, id);
checkDepartment(dep, id, "MANAGED");
// case 2: refresh with data changed on db in a different tx
id = 22;
dep = new Department(id, "MANAGED");
updatedDep = new Department(id, "UPDATED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id); // this is now in
// state MANAGED
updateDepartmentOnDatabase(updatedDep);
em.refresh(dep);
checkDepartment(dep, id, "UPDATED");
verify(em.contains(dep), "Department is not managed");
dep.setName("MANAGED");
env.commitTransactionAndClear(em);
// verify that original name present on db
dep = em.find(Department.class, id);
checkDepartment(dep, id, "MANAGED");
} finally {
closeEntityManager(em);
}
}
@Test
@Bugzilla(bugid = 309681)
public void testRefreshManagedCheckContains() throws SQLException {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
try {
// case 3: try to refresh, but record has been deleted on db in a
// different tx
/*
* We expect an EntityNotFoundException. However, the specification
* does not state explicitly in which state the managed entity
* should be after the exception. We are going to remove the entity
* from the persistence context, so it is detached afterwards.
*/
id = 23;
dep = new Department(id, "MANAGED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id); // this is now in
// state MANAGED
deleteDepartmentFromDatabase(id);
verifyAbsenceFromDatabase(em, id);
try {
em.refresh(dep);
flop("refresh did not throw EntityNotFoundException");
} catch (EntityNotFoundException e) {
verify(true, "");
}
verify(!em.contains(dep), "entity still managed after EntityNotFoundException");
env.rollbackTransactionAndClear(em);
} finally {
closeEntityManager(em);
}
}
private void doRefreshDeleted(int id, boolean flush) throws SQLException {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
try {
Department dep = new Department(id, "DELETED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id);
em.remove(dep);
if (flush) {
em.flush(); // this is now in state DELETE_EXECUTED
verifyAbsenceFromDatabase(em, id);
}
try {
em.refresh(dep);
fail("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
if (env.isTransactionActive(em)) {
env.rollbackTransactionAndClear(em);
}
} finally {
closeEntityManager(em);
}
}
/*
* Refreshing an entity in state "removed" should raise an
* IllegalArgumentException
*/
@Test
public void testRefreshDeleted() throws SQLException {
doRefreshDeleted(31, false);
doRefreshDeleted(32, true);
}
@Test
public void testRefreshDetached() {
/*
* Refresh on a detached entity should throw an
* IllegalArgumentException.
*/
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
Department detachedDep;
try {
// case 1: entity exists on DB, but not contained in persistence
// context
id = 41;
dep = new Department(id, "DETACHED");
// firstly, we create a department on the database
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
try {
em.refresh(dep);
flop("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
verify(true, "");
}
env.rollbackTransactionAndClear(em);
// case 2: entity is contained in persistence context, but object to
// be merged has different object identity
// case 2a: state of known object: MANAGED_NEW
id = 42;
dep = new Department(id, "MANAGED_NEW");
detachedDep = new Department(id, "DETACHED");
env.beginTransaction(em);
em.persist(dep); // this is now in state new
try {
em.refresh(detachedDep); // this object is detached
flop("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
verify(true, "");
}
env.rollbackTransactionAndClear(em);
// case 2b: state of known object: MANAGED
id = 43;
dep = new Department(id, "MANAGED");
detachedDep = new Department(id, "DETACHED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id); // this is now in
// state MANAGED
try {
em.refresh(detachedDep); // this object is detached
flop("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
verify(true, "");
}
env.rollbackTransactionAndClear(em);
// case 2c: state of known object: DELETED
id = 44;
dep = new Department(id, "DELETED");
detachedDep = new Department(id, "DETACHED");
env.beginTransaction(em);
em.persist(dep);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
dep = em.find(Department.class, id);
em.remove(dep); // this is now in state DELETED
try {
em.refresh(detachedDep); // this object is detached
flop("refresh did not throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
verify(true, "");
}
env.rollbackTransactionAndClear(em);
} finally {
closeEntityManager(em);
}
}
@Test
public void testNotAnEntity() {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
try {
env.beginTransaction(em);
try {
em.refresh("Hutzliputz");
flop("no IllegalArgumentException ");
} catch (IllegalArgumentException e) {
verify(true, "");
} finally {
env.rollbackTransactionAndClear(em);
}
env.beginTransaction(em);
try {
em.refresh(null);
flop("no IllegalArgumentException ");
} catch (IllegalArgumentException e) {
verify(true, "");
} finally {
env.rollbackTransactionAndClear(em);
}
} finally {
closeEntityManager(em);
}
}
@Ignore
// @TestProperties(unsupportedEnvironments = {
// JTANonSharedPCEnvironment.class, ResourceLocalEnvironment.class })
public void testNoTransaction() {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
int id;
Department dep;
try {
id = 61;
dep = new Department(id, "NO_TX");
verify(!env.isTransactionActive(em), "transaction is active, can't execute test");
try {
em.refresh(dep);
flop("refresh did not throw TransactionRequiredException");
} catch (TransactionRequiredException e) {
verify(true, "");
}
} finally {
closeEntityManager(em);
}
}
@Test
public void testRefreshManagedWithRelationships() {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
try {
// case 1: undo own changes
Department dep = new Department(101, "Evangelists");
Employee emp = new Employee(102, "First", "Last", dep);
Review rev1 = new Review(103, Date.valueOf("2006-02-03"), "Code inspection");
Review rev2 = new Review(104, Date.valueOf("2006-02-04"), "Design review");
emp.addReview(rev1);
emp.addReview(rev2);
env.beginTransaction(em);
em.persist(dep);
em.persist(emp);
em.persist(rev1);
em.persist(rev2);
env.commitTransactionAndClear(em);
env.beginTransaction(em);
emp = em.find(Employee.class, emp.getId());
rev1 = em.find(Review.class, rev1.getId());
Review rev3 = new Review(105, Date.valueOf("2006-02-05"), "Test coverage");
Set<Review> reviews = new HashSet<Review>();
reviews.add(rev1);
reviews.add(rev3);
emp.setReviews(reviews);
rev1.setReviewText("UPDATED");
em.refresh(emp);
verify(em.contains(emp), "Employee is not managed");
Set<Review> reviewsAfterRefresh = emp.getReviews();
verify(reviewsAfterRefresh.size() == 2, "Employee contains wrong number of reviews: " + reviewsAfterRefresh.size());
for (Review rev : reviewsAfterRefresh) {
int id = rev.getId();
verify(id == rev1.getId() || id == rev2.getId(), "Employee has wrong review: " + id);
verify(em.contains(rev), "Review " + id + " is not managed");
}
env.commitTransactionAndClear(em);
// verify that original name present on db
rev1 = em.find(Review.class, rev1.getId());
verify("UPDATED".equals(rev1.getReviewText()), "Rev1 has wrong text: " + rev1.getReviewText());
} finally {
closeEntityManager(em);
}
}
@Test
public void testTransactionMarkedForRollback() {
final JPAEnvironment env = getEnvironment();
final EntityManager em = env.getEntityManager();
Department dep = new Department(111, "dep111");
try {
env.beginTransaction(em);
em.persist(dep);
env.commitTransaction(em);
em.clear();
env.beginTransaction(em);
dep = em.find(Department.class, dep.getId());
dep.setName("updated");
env.markTransactionForRollback(em);
em.refresh(dep);
checkDepartment(dep, dep.getId(), "dep111");
verify(em.contains(dep), "entity not contained in persistence context");
env.rollbackTransaction(em);
} finally {
closeEntityManager(em);
}
}
private void verifyExistenceOnDatabase(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(), "no department with id " + departmentId + " found using JDBC.");
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
conn.close();
}
}
private void verifyAbsenceFromDatabase(EntityManager em, int id) {
Query query = em.createQuery("SELECT d.id from Department d where d.id = ?1");
query.setFlushMode(FlushModeType.COMMIT);
query.setParameter(1, id);
verify(query.getResultList().size() == 0, "wrong result list size");
}
private void deleteDepartmentFromDatabase(int departmentId) throws SQLException {
Connection conn = getEnvironment().getDataSource().getConnection();
try {
PreparedStatement stmt = conn.prepareStatement("delete from TMP_DEP where ID = ?");
try {
stmt.setInt(1, departmentId);
stmt.executeUpdate();
} finally {
stmt.close();
}
} finally {
conn.close();
}
}
private void insertDepartmentIntoDatabase(Department department) throws SQLException {
Connection conn = getEnvironment().getDataSource().getConnection();
try {
PreparedStatement stmt = conn.prepareStatement("insert into TMP_DEP (ID, NAME, VERSION) values (?, ?, ?)");
try {
stmt.setInt(1, department.getId());
stmt.setString(2, department.getName());
stmt.setShort(3, (short) 0);
stmt.executeUpdate();
} finally {
stmt.close();
}
} finally {
conn.close();
}
}
private void updateDepartmentOnDatabase(Department department) throws SQLException {
Connection conn = getEnvironment().getDataSource().getConnection();
try {
PreparedStatement stmt = conn.prepareStatement("update TMP_DEP set NAME = ? where ID = ?");
try {
stmt.setString(1, department.getName());
stmt.setInt(2, department.getId());
stmt.executeUpdate();
} finally {
stmt.close();
}
} finally {
conn.close();
}
}
private void checkDepartment(Department department, int id, String name) {
verify(department != null, "department is null");
verify(id == department.getId(), "department has wrong id: " + department.getId());
verify(name.equals(department.getName()), "department has wrong name: " + department.getName());
}
}