blob: 85ca174dfce0e950203db328247f34ae691ffb8b [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. 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:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.unitofwork;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Time;
import java.util.Date;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.IsolatedClientSession;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.testing.framework.TestErrorException;
import org.eclipse.persistence.testing.framework.TestWarningException;
import org.eclipse.persistence.testing.models.employee.domain.Employee;
import org.eclipse.persistence.testing.models.employee.domain.PhoneNumber;
/**
* This test checks on a previous problem TopLink had with merging clones and
* serialization. If an existing object was serialized and deserialized and another
* reference added to that object. Then the object was serialized and deserialized
* and deepMergeClone'd into a unit of work and committed.
* When the origional object was then serialized and deserialized and modified, then serialized
* and deserialized and deepMergeClone'd with another unit of work and committed the changes are
* not saved
*/
public class DeepMergeCloneSerializedTest extends org.eclipse.persistence.testing.framework.AutoVerifyTestCase {
public Employee origional;
public Employee mergedClone;
public Employee empObject;
//stuff changed
public String gender;
public Time endTime;
public PhoneNumber removedPhone;
public PhoneNumber addedPhone;
public Date endDate;
public DeepMergeCloneSerializedTest() {
setDescription("This test verifies that deepMergeClone works after a serialized transaction");
}
public DeepMergeCloneSerializedTest(Employee employee) {
this.empObject = employee;
setDescription("This test verifies that deepMergeClone works after a serialized transaction");
}
@Override
public void reset() {
if (getAbstractSession().isInTransaction()) {
getAbstractSession().rollbackTransaction();
getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
}
}
@Override
public void setup() {
if (getSession() instanceof org.eclipse.persistence.sessions.remote.RemoteSession) {
throw new TestWarningException("This test cannot be run through the remote.");
}
getAbstractSession().beginTransaction();
}
/*
* This test creates an object and registers it with a unit of work. It then serializes that
* object and deserializes it. Adds an object onto the origional then performs serialization
* sequence again. Then deepMergeClone is attempted and the results are compared to verify that
* the merge worked.
*/
@Override
public void test() {
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(byteStream);
//create the phoneNumber object
Employee empClone;
Session session = getSession();
org.eclipse.persistence.sessions.UnitOfWork uow = session.acquireUnitOfWork();
this.empObject =
(Employee)session.readObject(Employee.class, new org.eclipse.persistence.expressions.ExpressionBuilder().get("firstName").equal("Bob"));
ClassDescriptor descriptor = session.getDescriptor(this.empObject);
if (descriptor.isProtectedIsolation() && descriptor.shouldIsolateProtectedObjectsInUnitOfWork() && session instanceof IsolatedClientSession){
// this will have read a version of the protected Entity into the Isolated Cache even though the test wants to isolated to UOW
//replace with actual shared cache version
this.empObject = (Employee) ((AbstractSession)session).getParentIdentityMapSession(descriptor, false, true).getIdentityMapAccessor().getFromIdentityMap(this.empObject);
}
//force instantiations of value holders before serialization
this.empObject.getPhoneNumbers();
if (this.empObject.getManager() != null) {
this.empObject.getManager().getManagedEmployees();
}
this.empObject.getResponsibilitiesList();
//serialize object by writing to a stream
stream.writeObject(this.empObject);
stream.flush();
byte[] arr = byteStream.toByteArray();
ByteArrayInputStream inByteStream = new ByteArrayInputStream(arr);
ObjectInputStream inObjStream = new ObjectInputStream(inByteStream);
Employee deserialEmp;
//deserialize the object
try {
deserialEmp = (Employee)inObjStream.readObject();
} catch (ClassNotFoundException e) {
throw new TestErrorException("Could not deserialize object " + e.toString());
}
//add a new manager, test 1-m's
Employee newManager = new org.eclipse.persistence.testing.models.employee.domain.Employee();
if (deserialEmp.getManager() != null) {
deserialEmp.getManager().removeManagedEmployee(deserialEmp);
this.removedPhone = (PhoneNumber)deserialEmp.getPhoneNumbers().firstElement();
deserialEmp.getPhoneNumbers().removeElement(deserialEmp.getPhoneNumbers().firstElement());
}
newManager.addManagedEmployee(deserialEmp);
//add the PhoneNumber object to the origional clone, test 1-1
PhoneNumber phone = new org.eclipse.persistence.testing.models.employee.domain.PhoneNumber();
phone.setNumber("5555897");
phone.setType("Fax");
phone.setOwner(deserialEmp);
deserialEmp.addPhoneNumber(phone);
this.addedPhone = phone;
deserialEmp.setLastName("Willford");
this.gender = deserialEmp.getGender();
if (deserialEmp.getGender().equals("Female")) {
deserialEmp.setMale();
} else {
deserialEmp.setFemale();
}
this.endDate = deserialEmp.getPeriod().getEndDate();
deserialEmp.getPeriod().setEndDate(new java.sql.Date(System.currentTimeMillis() + 300000L));
this.endTime = deserialEmp.getEndTime();
deserialEmp.setEndTime(Helper.timeFromHourMinuteSecond(15, 2, 3));
deserialEmp.addResponsibility("A Very New Respons");
byteStream = new ByteArrayOutputStream();
stream = new ObjectOutputStream(byteStream);
//send the ammended object back through the serialization process
stream.writeObject(deserialEmp);
stream.flush();
arr = byteStream.toByteArray();
inByteStream = new ByteArrayInputStream(arr);
inObjStream = new ObjectInputStream(inByteStream);
try {
deserialEmp = (Employee)inObjStream.readObject();
} catch (ClassNotFoundException e) {
throw new TestErrorException("Could not deserialize object " + e.toString());
}
//merge the ammended clone with the unit of work
empClone = (Employee)uow.deepMergeClone(deserialEmp);
uow.commit();
uow = session.acquireUnitOfWork();
// do the serialization for the second time
byteStream = new ByteArrayOutputStream();
stream = new ObjectOutputStream(byteStream);
stream.writeObject(this.empObject);
stream.flush();
arr = byteStream.toByteArray();
inByteStream = new ByteArrayInputStream(arr);
inObjStream = new ObjectInputStream(inByteStream);
//attempt to deserialize the object
try {
deserialEmp = (Employee)inObjStream.readObject();
} catch (ClassNotFoundException e) {
throw new TestErrorException("Could not deserialize object " + e.toString());
}
deserialEmp.setFirstName("Danny");
this.origional = deserialEmp;
byteStream = new ByteArrayOutputStream();
stream = new ObjectOutputStream(byteStream);
//send the ammended object back through the serialization process
stream.writeObject(deserialEmp);
stream.flush();
arr = byteStream.toByteArray();
inByteStream = new ByteArrayInputStream(arr);
inObjStream = new ObjectInputStream(inByteStream);
try {
deserialEmp = (Employee)inObjStream.readObject();
} catch (ClassNotFoundException e) {
throw new TestErrorException("Could not deserialize object " + e.toString());
}
deserialEmp = (Employee)uow.deepMergeClone(deserialEmp);
uow.commit();
this.mergedClone = deserialEmp;
} catch (IOException e) {
throw new TestErrorException("Error running Test " + e.toString());
}
}
/**
* Checks to see that the names of the updated version and the origional are the same
*/
@Override
public void verify() {
if (this.mergedClone.getFirstName().equals(this.origional.getFirstName())) {
} else {
throw new TestErrorException("Clone did not merge properly");
}
Employee cachedEmp = (Employee)getSession().readObject(this.mergedClone);
if (cachedEmp.getPeriod().getEndDate().equals(this.endDate)) {
throw new TestErrorException("Failed to update the aggregate");
}
if (cachedEmp.getEndTime().equals(this.endTime)) {
throw new TestErrorException("Failed to update the Transformation mapping");
}
if (cachedEmp.getGender().equals(this.gender)) {
throw new TestErrorException("Failed to update the TypeConversionMapping");
}
if (!cachedEmp.getPhoneNumbers().contains(getSession().readObject(addedPhone))) {
throw new TestErrorException("Failed to update one to many addition");
}
if (!cachedEmp.getResponsibilitiesList().contains("A Very New Respons")) {
throw new TestErrorException("Failed to update Direct Collection mapping");
}
if (!cachedEmp.getLastName().equals("Willford")) {
throw new TestErrorException("Failed to update Direct To Field");
}
}
}