| /* |
| * 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.util.Vector; |
| |
| import org.eclipse.persistence.expressions.Expression; |
| import org.eclipse.persistence.expressions.ExpressionBuilder; |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.queries.ReadObjectQuery; |
| import org.eclipse.persistence.sessions.remote.RemoteSession; |
| import org.eclipse.persistence.sessions.Session; |
| import org.eclipse.persistence.sessions.SessionEventListener; |
| import org.eclipse.persistence.sessions.UnitOfWork; |
| import org.eclipse.persistence.testing.tests.remote.RemoteModel; |
| import org.eclipse.persistence.testing.framework.AutoVerifyTestCase; |
| import org.eclipse.persistence.testing.framework.TestErrorException; |
| import org.eclipse.persistence.testing.framework.TestWarningException; |
| import org.eclipse.persistence.testing.models.employee.domain.Address; |
| import org.eclipse.persistence.testing.models.employee.domain.Employee; |
| import org.eclipse.persistence.testing.models.employee.domain.EmploymentPeriod; |
| import org.eclipse.persistence.testing.models.employee.domain.LargeProject; |
| import org.eclipse.persistence.testing.models.employee.domain.SmallProject; |
| |
| |
| public class ComplexMultipleUnitOfWorkTest extends AutoVerifyTestCase { |
| public Employee readInSession; |
| public Employee readInUow; |
| public Employee newEmployeeInUow; |
| public Employee readInFirstNestedUow; |
| public UnitOfWork firstUnitOfWork; |
| public UnitOfWork secondUnitOfWork; |
| public UnitOfWork thirdUnitOfWork; |
| // On some platforms (Sybase/Derby) if conn1 updates a row but hasn't yet committed transaction then |
| // reading the row through conn2 may hang. |
| // To avoid this problem the listener would decrement transaction isolation level, |
| // then reading through conn2 no longer hangs, however may result (results on Sybase) |
| // in reading of uncommitted data. |
| SessionEventListener listener; |
| |
| /** |
| * MultipleUnitOfWorkTestCase constructor comment. |
| */ |
| public ComplexMultipleUnitOfWorkTest() { |
| super(); |
| } |
| |
| public Address addressExample1() { |
| Address address = new org.eclipse.persistence.testing.models.employee.domain.Address(); |
| |
| address.setCity("Toronto"); |
| address.setPostalCode("L5J2B5"); |
| address.setProvince("ONT"); |
| address.setStreet("1450 Acme Cr., suite 4"); |
| address.setCountry("Canada"); |
| return address; |
| } |
| |
| public Address addressExample2() { |
| Address address = new org.eclipse.persistence.testing.models.employee.domain.Address(); |
| |
| address.setCity("Ottawa"); |
| address.setPostalCode("K5J2B5"); |
| address.setProvince("ONT"); |
| address.setStreet("1450 Acme Cr., suite 4"); |
| address.setCountry("Canada"); |
| return address; |
| } |
| |
| public Address addressExample3() { |
| Address address = new org.eclipse.persistence.testing.models.employee.domain.Address(); |
| |
| address.setCity("Sudbury"); |
| address.setPostalCode("L5J2B5"); |
| address.setProvince("ONT"); |
| address.setStreet("1450 Acme Cr., suite 4"); |
| address.setCountry("Canada"); |
| return address; |
| } |
| |
| public Address addressExample4() { |
| Address address = new org.eclipse.persistence.testing.models.employee.domain.Address(); |
| |
| address.setCity("Niagra"); |
| address.setPostalCode("L5J2B5"); |
| address.setProvince("ONT"); |
| address.setStreet("1450 Acme Cr., suite 4"); |
| address.setCountry("Canada"); |
| return address; |
| } |
| |
| protected void changeObject(Employee employee, UnitOfWork unitOfWork) { |
| // Transformation |
| employee.setNormalHours(new java.sql.Time[2]); |
| employee.setStartTime(Helper.timeFromHourMinuteSecond(1, 1, 1)); |
| employee.setEndTime(Helper.timeFromHourMinuteSecond(1, 1, 1)); |
| // Aggregate |
| employee.setPeriod(new EmploymentPeriod(Helper.dateFromYearMonthDate(1901, 1, 1), |
| Helper.dateFromYearMonthDate(1902, 2, 2))); |
| // One to many private |
| employee.setPhoneNumbers(new Vector()); |
| employee.addPhoneNumber(new org.eclipse.persistence.testing.models.employee.domain.PhoneNumber("home", "613", |
| "2263374")); |
| employee.addPhoneNumber(new org.eclipse.persistence.testing.models.employee.domain.PhoneNumber("office", "416", |
| "8224599")); |
| // Many to many |
| employee.setProjects(new Vector()); |
| employee.addProject((org.eclipse.persistence.testing.models.employee.domain.Project)unitOfWork.readObject(SmallProject.class)); |
| employee.addProject((org.eclipse.persistence.testing.models.employee.domain.Project)unitOfWork.readObject(LargeProject.class)); |
| // Direct collection |
| employee.setResponsibilitiesList(new Vector()); |
| employee.addResponsibility("make coffee"); |
| employee.addResponsibility("buy donuts"); |
| // One to one private/public |
| employee.setAddress(addressExample4()); |
| |
| ((Employee)unitOfWork.readObject(Employee.class, new ExpressionBuilder().get("firstName").equal("Marcus"))).addManagedEmployee(employee); |
| } |
| |
| public Employee createNewEmployeeObject() { |
| Employee employee = new org.eclipse.persistence.testing.models.employee.domain.Employee(); |
| |
| employee.setFirstName("Judy"); |
| employee.setLastName("Barney"); |
| employee.setMale(); |
| employee.setSalary(35000); |
| employee.setPeriod(employmentPeriodExample()); |
| employee.setAddress(addressExample1()); |
| employee.addResponsibility("Make the coffee."); |
| employee.addResponsibility("Clean the kitchen."); |
| employee.addPhoneNumber(new org.eclipse.persistence.testing.models.employee.domain.PhoneNumber("Work", "613", |
| "2258812")); |
| |
| employee.addProject(smallProjectExample()); |
| |
| return employee; |
| } |
| |
| public EmploymentPeriod employmentPeriodExample() { |
| EmploymentPeriod employmentPeriod = new org.eclipse.persistence.testing.models.employee.domain.EmploymentPeriod(); |
| |
| employmentPeriod.setEndDate(org.eclipse.persistence.internal.helper.Helper.dateFromYearMonthDate(1996, 0, 1)); |
| employmentPeriod.setStartDate(org.eclipse.persistence.internal.helper.Helper.dateFromYearMonthDate(1993, 0, 1)); |
| return employmentPeriod; |
| } |
| |
| public void processFirstUnitOfWork() throws Exception { |
| Expression firstNameExpression; |
| |
| // Read the object in the session |
| firstNameExpression = new ExpressionBuilder().get("firstName").equal("Bob"); |
| this.readInSession = (Employee)getSession().readObject(Employee.class, firstNameExpression); |
| |
| // Acquire unit of work |
| // Read first object in the uow |
| this.firstUnitOfWork = getSession().acquireUnitOfWork(); |
| firstNameExpression = new ExpressionBuilder().get("firstName").equal("John"); |
| this.readInUow = (Employee)this.firstUnitOfWork.readObject(Employee.class, firstNameExpression); |
| |
| Employee regDel = (Employee)this.firstUnitOfWork.registerObject(this.readInSession); |
| // Must remove references to deleted objects. |
| if (regDel.getManager() != null) { |
| regDel.getManager().removeManagedEmployee(regDel); |
| } |
| for (java.util.Enumeration mgdEnum = regDel.getManagedEmployees().elements(); mgdEnum.hasMoreElements(); |
| ) { |
| ((Employee)mgdEnum.nextElement()).setManager(null); |
| } |
| for (java.util.Enumeration mgdProjEnum = |
| (this.firstUnitOfWork.readAllObjects(org.eclipse.persistence.testing.models.employee.domain.Project.class)).elements(); |
| mgdProjEnum.hasMoreElements(); ) { |
| ((org.eclipse.persistence.testing.models.employee.domain.Project)mgdProjEnum.nextElement()).setTeamLeader(null); |
| } |
| |
| // Delete the object read in the session without registration. |
| this.firstUnitOfWork.deleteObject(this.readInSession); |
| |
| // Create object in uow and register it. |
| this.newEmployeeInUow = createNewEmployeeObject(); |
| Employee newEmployeeInFirstUow = (Employee)this.firstUnitOfWork.registerObject(this.newEmployeeInUow); |
| |
| // Must remove references to deleted objects. |
| if (this.readInUow.getManager() != null) { |
| this.readInUow.getManager().removeManagedEmployee(this.readInUow); |
| } |
| for (java.util.Enumeration mgdEnum = this.readInUow.getManagedEmployees().elements(); |
| mgdEnum.hasMoreElements(); ) { |
| ((Employee)mgdEnum.nextElement()).setManager(null); |
| } |
| |
| // Acquire first nested unit of work |
| // Delete read object in the unit of work without registering it. |
| // Read some object and change it. |
| UnitOfWork firstNestedUow = this.firstUnitOfWork.acquireUnitOfWork(); |
| firstNestedUow.deleteObject(this.readInUow); |
| |
| Employee workingCopyOfNewEmployeeInSecondNestedUow = |
| (Employee)firstNestedUow.registerObject(newEmployeeInFirstUow); |
| |
| workingCopyOfNewEmployeeInSecondNestedUow.setAddress(addressExample2()); |
| |
| firstNestedUow.commit(); |
| |
| // Acquire second nested unit of work |
| // Change the new object created in the parent. |
| UnitOfWork secondNestedUow = this.firstUnitOfWork.acquireUnitOfWork(); |
| |
| firstNameExpression = new ExpressionBuilder().get("firstName").equal("Marcus"); |
| this.readInFirstNestedUow = (Employee)secondNestedUow.readObject(Employee.class, firstNameExpression); |
| this.readInFirstNestedUow.setAddress(addressExample3()); |
| |
| secondNestedUow.commit(); |
| // Assign correct clone from root unit of work so compare verifies works correctly. |
| this.readInFirstNestedUow = (Employee)secondNestedUow.getOriginalVersionOfObject(readInFirstNestedUow); |
| this.firstUnitOfWork.commit(); |
| } |
| |
| public void processSecondUnitOfWork() { |
| this.secondUnitOfWork = getSession().acquireUnitOfWork(); |
| |
| ReadObjectQuery query = new ReadObjectQuery(); |
| query.setSelectionObject(this.newEmployeeInUow); |
| |
| Employee objectFromDatabase = (Employee)secondUnitOfWork.executeQuery(query); |
| |
| if (!(((AbstractSession)getSession()).compareObjects(this.newEmployeeInUow, objectFromDatabase))) { |
| throw new TestErrorException("The object read from the database, '" + this.newEmployeeInUow + |
| "' does not match the originial, '" + objectFromDatabase + "."); |
| } |
| |
| query = new ReadObjectQuery(); |
| query.setSelectionObject(this.readInFirstNestedUow); |
| |
| objectFromDatabase = (Employee)secondUnitOfWork.executeQuery(query); |
| |
| if (!(((AbstractSession)getSession()).compareObjects(this.readInFirstNestedUow, objectFromDatabase))) { |
| throw new TestErrorException("The object read from the database, '" + this.readInFirstNestedUow + |
| "' does not match the originial, '" + objectFromDatabase + "."); |
| } |
| |
| Employee workingCopy = (Employee)secondUnitOfWork.registerObject(this.newEmployeeInUow); |
| changeObject(workingCopy, this.secondUnitOfWork); |
| secondUnitOfWork.release(); |
| |
| // Use the original session for comparision |
| if (!((AbstractSession)getSession()).compareObjectsDontMatch(this.newEmployeeInUow, workingCopy)) { |
| throw new TestErrorException("The original object was changed through changing the clone."); |
| } |
| } |
| |
| public void processThirdUnitOfWork() { |
| this.thirdUnitOfWork = getSession().acquireUnitOfWork(); |
| |
| Employee workingCopy = (Employee)thirdUnitOfWork.registerObject(this.newEmployeeInUow); |
| changeObject(workingCopy, this.thirdUnitOfWork); |
| |
| if (!((AbstractSession)getSession()).compareObjectsDontMatch(this.newEmployeeInUow, workingCopy)) { |
| throw new TestErrorException("The original object was changed through changing the clone."); |
| } |
| |
| this.thirdUnitOfWork.commit(); |
| } |
| |
| @Override |
| public void reset() { |
| if(getAbstractSession().isInTransaction()) { |
| getAbstractSession().rollbackTransaction(); |
| } |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| if(listener != null) { |
| getAbstractSession().getParent().getEventManager().removeListener(listener); |
| listener = null; |
| } |
| } |
| |
| @Override |
| public void setup() { |
| if (getSession().isClientSession()) { |
| listener = checkTransactionIsolation(); |
| } |
| if (getSession().isRemoteSession() && getSession().getDatasourcePlatform().isDerby()) { |
| throw new TestWarningException("This test uses functionality that does not work over remote sessions in Apache Derby."); |
| } |
| getAbstractSession().beginTransaction(); |
| } |
| |
| public SmallProject smallProjectExample() { |
| SmallProject smallProject = new SmallProject(); |
| |
| smallProject.setName("Enterprise"); |
| smallProject.setDescription("A enterprise wide application using Visual J++ to report on the corporations Sybase and DB/2 database through TopLink."); |
| return smallProject; |
| } |
| |
| @Override |
| public void test() throws Exception { |
| processFirstUnitOfWork(); |
| processSecondUnitOfWork(); |
| processThirdUnitOfWork(); |
| } |
| |
| @Override |
| public void verify() { |
| getSession().getIdentityMapAccessor().initializeIdentityMaps(); |
| Session sessionToVerifyDelete; |
| |
| if (getSession() instanceof RemoteSession) { |
| sessionToVerifyDelete = RemoteModel.getServerSession(); |
| } else { |
| sessionToVerifyDelete = getSession(); |
| } |
| // Verify if object deleted in the uow was deleted |
| if (!(((AbstractSession)sessionToVerifyDelete).verifyDelete(this.readInSession))) { |
| throw new TestErrorException("The object '" + this.readInSession + |
| "'deleted in the uow was not completely deleted from the database."); |
| } |
| |
| // Verify if object deleted in the uow was deleted |
| if (!(((AbstractSession)sessionToVerifyDelete).verifyDelete(this.readInUow))) { |
| throw new TestErrorException("The object '" + this.readInUow + |
| "'deleted in the nested uow was not completely deleted from the database."); |
| } |
| |
| ReadObjectQuery query = new ReadObjectQuery(); |
| query.setSelectionObject(this.newEmployeeInUow); |
| |
| Employee objectFromDatabase = (Employee)getSession().executeQuery(query); |
| |
| if (!(((AbstractSession)getSession()).compareObjects(this.newEmployeeInUow, objectFromDatabase))) { |
| throw new TestErrorException("The object read from the database, '" + this.newEmployeeInUow + |
| "' does not match the originial, '" + objectFromDatabase + "."); |
| } |
| } |
| } |