/******************************************************************************* * 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 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.io.IOException; import java.sql.Date; import javax.persistence.EntityManager; import javax.persistence.EntityNotFoundException; import javax.persistence.LockModeType; import javax.persistence.PersistenceException; import org.eclipse.persistence.testing.framework.wdf.AbstractBaseTest; import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment; import org.eclipse.persistence.testing.framework.wdf.ToBeInvestigated; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Account; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.CreditCardAccount; 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.models.wdf.jpa1.employee.Employee; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Patent; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.PatentId; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Review; import org.eclipse.persistence.testing.models.wdf.jpa1.node.CascadingNode; import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base; import org.junit.Test; public class TestGetReference extends JPA1Base { private final Department _dep = new Department(1, "eins"); private final Department _dep2 = new Department(2, "zwei"); private final Employee _emp = new Employee(7, "first", "last", _dep); private final Cubicle _cub = new Cubicle(new Integer(1), new Integer(2), "yellow", _emp); private final Patent _pat = new Patent("12345", 2007, "whatever", Date.valueOf("2007-01-01")); private final CreditCardAccount _ccacc = new CreditCardAccount(); @Override public void setup() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { _ccacc.setNumber(1); _ccacc.setOwner("me"); _ccacc.setCardNumber(123); env.beginTransaction(em); em.persist(_dep); em.persist(_dep2); em.persist(_emp); em.persist(_cub); em.persist(_pat); em.persist(_ccacc); em.flush(); env.commitTransactionAndClear(em); } catch (Exception ex) { throw new RuntimeException(ex); } finally { closeEntityManager(em); } } @Test public void testSimple() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Employee emp = em.getReference(Employee.class, new Integer(7)); verify(em.contains(emp), "Object not managed"); env.commitTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testPositivTx() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Employee emp = em.getReference(Employee.class, new Integer(7)); verify(em.contains(emp), "Object not managed"); verify(emp.getId() == 7, "wrong id"); verify(emp.getDepartment().getName().equals("eins"), "wrong department"); emp = em.getReference(Employee.class, new Integer(7)); verify(emp.getId() == 7, "wrong id"); Department dep = em.getReference(Department.class, new Integer(1)); verify(em.contains(dep), "Object not loaded"); verify(dep.getId() == 1, "wrong id"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testPositivNonTx() { final EntityManager em = getEnvironment().getEntityManager(); try { Employee emp = em.getReference(Employee.class, new Integer(7)); try { verify(emp.getId() == 7, "wrong id"); verify(emp.getDepartment().getName().equals("eins"), "wrong department"); emp = em.getReference(Employee.class, new Integer(7)); verify(emp.getId() == 7, "wrong id"); Department dep = em.getReference(Department.class, new Integer(1)); verify(dep.getId() == 1, "wrong id"); } catch (PersistenceException e) { if (getEnvironment().usesExtendedPC()) { throw e; } // transaction-scoped pc might throw exception while trying to // load hollow entity outside tx } } finally { closeEntityManager(em); } } @Test public void testPositivTxPropertyAccess() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Department dep = em.getReference(Department.class, Integer.valueOf(1)); verify(em.contains(dep), "Object not managed"); verify(dep.getId() == 1, "wrong id"); verify(dep.getName().equals("eins"), "wrong name"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testPositivNonTxPropertyAccess() { final EntityManager em = getEnvironment().getEntityManager(); try { Department dep = em.getReference(Department.class, Integer.valueOf(1)); verify(dep.getId() == 1, "wrong id"); try { verify(dep.getName().equals("eins"), "wrong name"); } catch (PersistenceException e) { if (getEnvironment().usesExtendedPC()) { throw e; } // transaction-scoped pc might throw exception while trying to // load hollow entity outside tx } } finally { closeEntityManager(em); } } @Test public void testNegativ() { /* * If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance * state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when * getReference is called.) */ final EntityManager em = getEnvironment().getEntityManager(); try { final JPAEnvironment env = getEnvironment(); Employee employee = null; boolean operationFailed = false; env.beginTransaction(em); try { employee = em.getReference(Employee.class, new Integer(17 + 4)); } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior operationFailed = true; } if (employee != null) { try { employee.getFirstName(); } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior operationFailed = true; } } env.rollbackTransactionAndClear(em); verify(operationFailed, "no EntityNotFoundException"); } finally { closeEntityManager(em); } } /* * IllegalArgumentException, if the first argument does not denote an entity type or the second argument is not a valid type * for that entity's primary key. */ @Test public void testIllegalArguments() { final EntityManager em = getEnvironment().getEntityManager(); try { try { em.getReference(String.class, new Integer(17 + 4)); flop("no IllegalArgumentException thrown"); } catch (IllegalArgumentException ex) { verify(true, ""); } try { em.getReference(Employee.class, "illegal key"); flop("no IllegalArgumentException thrown"); } catch (IllegalArgumentException ex) { verify(true, ""); } try { em.getReference(Employee.class, null); flop("no IllegalArgumentException thrown"); } catch (IllegalArgumentException ex) { verify(true, ""); } try { em.getReference(null, "illegal key"); flop("no IllegalArgumentException thrown"); } catch (IllegalArgumentException ex) { verify(true, ""); } } finally { closeEntityManager(em); } } @Test public void testFindWithCompositeKey() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Integer one = new Integer(1); Integer two = new Integer(2); CubiclePrimaryKeyClass cubKey = new CubiclePrimaryKeyClass(one, two); Cubicle cub = em.getReference(Cubicle.class, cubKey); verify(cub.getFloor().equals(one) && cub.getPlace().equals(two), "wrong cubicle"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testEmbeddedIdPropertyAccess() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); PatentId id = _pat.getId(); Patent pat = em.getReference(Patent.class, id); verify(pat.getId().equals(_pat.getId()), "wrong patent"); verify(pat.getDescription().equals(_pat.getDescription()), "wrong description"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } /* * Clarification with Mike Keith on this: > > 2) Ceck on flush -> another example > > On the DB: > > Employee(1) -> * Address(2); > Address(3) may or may not exist > > We perform the folloing operations: > > Employee emp = * em.find(Employee.class, 1); > Address newAddress = em.getReference(Address.class, 3); > // depending on the * implementation, newAddress may be "hollow" > emp.setAddress(newAddress); > em.flush(); > > In which state is newAddress * upon flush? Is the entity > manager required to assert the existence of newAddress upon > flush? Again, this would * pervert the idea of lazy loading. > > Should we specifiy that checks on flush should not apply to > "hollow" entities? * * * The getReference API comment states that the existence assertion is not expected until the state of the entity is first * accessed, so no assertion should be expected in this case. However, we might want to ensure it is in the spec text, not * just a comment, and we might also want to qualify that the assertion may only occur when accessing non-identifier state. */ public void testNonExistingEntityInRelation() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { Employee employee = null; Department nonExistingDepartment = null; env.beginTransaction(em); employee = em.find(Employee.class, Integer.valueOf(7)); try { nonExistingDepartment = em.getReference(Department.class, Integer.valueOf(999)); } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior return; // getReference checks -> fail fast } employee.setDepartment(nonExistingDepartment); em.flush(); // must succeed now if getReference did not fail fast } finally { env.rollbackTransactionAndClear(em); closeEntityManager(em); } } @Test public void testInheritance() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); CreditCardAccount acc = em.getReference(CreditCardAccount.class, Long.valueOf(1)); // verify method declared by superclass verify("me".equals(acc.getOwner()), "wrong owner"); env.rollbackTransactionAndClear(em); env.beginTransaction(em); acc = (CreditCardAccount) em.getReference(Account.class, Long.valueOf(1)); // verify method declared by subclass of Account verify(Long.valueOf(123).equals(acc.getCardNumber()), "wrong card number"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testNegativInheritance() { /* * If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance * state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when * getReference is called.) */ final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { CreditCardAccount account = null; boolean operationFailed = false; env.beginTransaction(em); try { account = em.getReference(CreditCardAccount.class, Long.valueOf(999)); // does not exist } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior operationFailed = true; } if (account != null) { try { account.getOwner(); } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior operationFailed = true; } } env.rollbackTransactionAndClear(em); verify(operationFailed, "no EntityNotFoundException"); } finally { closeEntityManager(em); } } @Test public void testPersist() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { Employee emp = null; boolean operationFailed = false; env.beginTransaction(em); try { emp = em.getReference(Employee.class, Integer.valueOf(99)); } catch (EntityNotFoundException e) { // $JL-EXC$ expected behavior operationFailed = true; } env.rollbackTransactionAndClear(em); if (emp != null) { env.beginTransaction(em); try { em.persist(emp); em.flush(); } catch (PersistenceException e) { // $JL-EXC$ expected behavior operationFailed = true; } env.rollbackTransactionAndClear(em); verify(operationFailed, "persisting a hollow entity succeeded (should fail)"); } } finally { closeEntityManager(em); } } @Test public void testRemove() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Employee emp = new Employee(11, "homer", "simpson", _dep); // field access, no versioning em.persist(emp); Department dep = new Department(11, "eleven"); // property access, versioning em.persist(dep); Review rev = new Review(11, Date.valueOf("2007-01-01"), "eleven"); // field access, versioning em.persist(rev); env.commitTransactionAndClear(em); // update to increase version counter env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(11)); dep.setName("updated"); rev = em.find(Review.class, Integer.valueOf(11)); rev.setReviewText("updated"); env.commitTransactionAndClear(em); env.beginTransaction(em); emp = em.getReference(Employee.class, Integer.valueOf(11)); em.remove(emp); em.flush(); env.commitTransactionAndClear(em); verify(em.find(Employee.class, Integer.valueOf(11)) == null, "employee not removed"); env.beginTransaction(em); dep = em.getReference(Department.class, Integer.valueOf(11)); em.remove(dep); em.flush(); env.commitTransactionAndClear(em); verify(em.find(Department.class, Integer.valueOf(11)) == null, "department not removed"); env.beginTransaction(em); rev = em.getReference(Review.class, Integer.valueOf(11)); em.remove(rev); em.flush(); env.commitTransactionAndClear(em); verify(em.find(Review.class, Integer.valueOf(11)) == null, "review not removed"); } finally { closeEntityManager(em); } } @Test public void testRemoveNonExisting() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); try { Employee emp = em.getReference(Employee.class, Integer.valueOf(99)); // versioning, entity does not exist em.remove(emp); em.flush(); flop("PersistenceException not thrown as expected"); } catch (PersistenceException e) { // $JL-EXC$ expected behavior } env.rollbackTransactionAndClear(em); env.beginTransaction(em); try { Department dep = em.getReference(Department.class, Integer.valueOf(99)); // versioning, entity does not exist em.remove(dep); em.flush(); flop("PersistenceException not thrown as expected"); } catch (PersistenceException e) { // $JL-EXC$ expected behavior } env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testMerge() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { Employee emp = null; // case 1: hollow entity is managed env.beginTransaction(em); emp = em.getReference(Employee.class, Integer.valueOf(7)); em.merge(emp); em.flush(); env.rollbackTransactionAndClear(em); // case 2: hollow entity is detached emp = em.getReference(Employee.class, Integer.valueOf(7)); boolean shouldFail = isHollow(emp); env.beginTransaction(em); try { em.clear(); verify(!em.contains(emp), "emp not detached"); em.merge(emp); em.flush(); if (shouldFail) { flop("merge of a detached hollow entity succeeded (should fail)"); } } catch (PersistenceException e) { if (!shouldFail) { throw e; } } catch (IllegalArgumentException e) { if (!shouldFail) { throw e; } } env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testMergeIntoHollow() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); int id = 20; try { env.beginTransaction(em); Employee emp = new Employee(id, "first", "last", _dep); em.persist(emp); env.commitTransactionAndClear(em); Employee empDetached = em.find(Employee.class, Integer.valueOf(id)); em.clear(); // detach entity empDetached.setFirstName("updated"); env.beginTransaction(em); emp = em.getReference(Employee.class, Integer.valueOf(id)); em.merge(empDetached); em.flush(); env.commitTransactionAndClear(em); emp = em.find(Employee.class, Integer.valueOf(id)); verify("updated".equals(emp.getFirstName()), "wrong first name: " + emp.getFirstName()); } finally { closeEntityManager(em); } } @Test public void testRefresh() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { Employee emp = null; env.beginTransaction(em); emp = em.getReference(Employee.class, Integer.valueOf(7)); em.refresh(emp); em.flush(); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testReadLock() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Department dep = em.getReference(Department.class, Integer.valueOf(1)); em.lock(dep, LockModeType.READ); em.flush(); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testWriteLock() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); Department dep = em.find(Department.class, Integer.valueOf(1)); int version = dep.getVersion(); env.rollbackTransactionAndClear(em); env.beginTransaction(em); dep = em.getReference(Department.class, Integer.valueOf(1)); em.lock(dep, LockModeType.WRITE); em.flush(); verify(dep.getVersion() > version, "version not incremented"); env.rollbackTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test @ToBeInvestigated public void testCascadeRemove() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); CascadingNode parent = new CascadingNode(1, null); CascadingNode child = new CascadingNode(2, parent); em.persist(parent); em.persist(child); env.commitTransactionAndClear(em); env.beginTransaction(em); parent = em.getReference(CascadingNode.class, Integer.valueOf(1)); em.remove(parent); em.flush(); env.commitTransactionAndClear(em); parent = em.find(CascadingNode.class, Integer.valueOf(1)); verify(parent == null, "parent not removed"); child = em.find(CascadingNode.class, Integer.valueOf(2)); verify(child == null, "child not removed"); } finally { closeEntityManager(em); } } @Test @ToBeInvestigated public void testCascadePersistOnFlush() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { env.beginTransaction(em); CascadingNode parent = new CascadingNode(11, null); CascadingNode child = new CascadingNode(12, parent); em.persist(parent); em.persist(child); env.commitTransactionAndClear(em); env.beginTransaction(em); em.getReference(CascadingNode.class, Integer.valueOf(11)); em.flush(); env.rollbackTransactionAndClear(em); env.beginTransaction(em); // cleanup in order -> FK em.merge(child); em.merge(parent); em.remove(child); em.remove(parent); env.commitTransactionAndClear(em); } finally { closeEntityManager(em); } } @Test public void testSerializeLoaded() throws IOException, ClassNotFoundException { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { // case 1: entity with standard serialization Employee emp = em.getReference(Employee.class, new Integer(7)); // load entity emp.getFirstName(); Employee resultEmp = AbstractBaseTest.serializeDeserialize(emp); verify(emp.getId() == resultEmp.getId(), "wrong id: " + resultEmp.getId()); verify(emp.getFirstName().equals(resultEmp.getFirstName()), "wrong first name: " + resultEmp.getFirstName()); em.clear(); // case 2: entity with writeReplace Department dep = em.getReference(Department.class, new Integer(1)); // load entity dep.getName(); Department resultDep = AbstractBaseTest.serializeDeserialize(dep); verify(dep.getId() == resultDep.getId(), "wrong id: " + resultDep.getId()); verify(Department.HUGO.equals(resultDep.getName()), "wrong name: " + resultDep.getName()); em.clear(); // case 3: related entities emp = em.getReference(Employee.class, new Integer(7)); emp.getFirstName(); dep = em.getReference(Department.class, new Integer(2)); dep.getName(); emp.setDepartment(dep); Cubicle cub = em.getReference(Cubicle.class, new CubiclePrimaryKeyClass(1, 2)); cub.getColor(); emp.setCubicle(cub); cub.setEmployee(emp); Cubicle resultCub = AbstractBaseTest.serializeDeserialize(cub); resultDep = resultCub.getEmployee().getDepartment(); verify(Department.HUGO.equals(resultDep.getName()), "wrong name: " + resultDep.getName()); em.clear(); } finally { closeEntityManager(em); } } @Test public void testSerializeHollow() throws IOException, ClassNotFoundException { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { // case 1: entity with standard serialization Employee emp = em.getReference(Employee.class, new Integer(7)); boolean shouldFail = isHollow(emp); try { Employee resultEmp = AbstractBaseTest.serializeDeserialize(emp); verify(emp.getId() == resultEmp.getId(), "wrong id: " + resultEmp.getId()); verify(emp.getFirstName().equals(resultEmp.getFirstName()), "wrong first name: " + resultEmp.getFirstName()); } catch (PersistenceException e) { if (!shouldFail) { throw e; } } em.clear(); // case 2: entity with writeReplace Department dep = em.getReference(Department.class, new Integer(1)); shouldFail = isHollow(dep); try { Department resultDep = AbstractBaseTest.serializeDeserialize(dep); verify(dep.getId() == resultDep.getId(), "wrong id: " + resultDep.getId()); verify(Department.HUGO.equals(resultDep.getName()), "wrong name: " + resultDep.getName()); } catch (PersistenceException e) { if (!shouldFail) { throw e; } } em.clear(); em.clear(); } finally { closeEntityManager(em); } } private boolean isHollow(Object entity) { return false; // TODO move to EclipseLink // return entity instanceof LazilyLoadable && ((LazilyLoadable) // entity)._isPending(); } }