Bug 489898 - RepeatableWriteUnitOfWork linked by QueryBasedValueHolder in shared cache in specific scenario
- (2.3 branch checkin, fix and test is the same)
Signed-off-by: David Minsky <david.minsky@oracle.com>
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/QueryBasedValueHolder.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/QueryBasedValueHolder.java
index d1c407d..ee6113a 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/QueryBasedValueHolder.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/QueryBasedValueHolder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -95,7 +95,10 @@
if (session == null) {
throw ValidationException.instantiatingValueholderWithNullSession();
}
- return session.executeQuery(getQuery(), getRow());
+ Object result = session.executeQuery(getQuery(), getRow());
+ // Bug 489898 - ensure that the query's session is dereferenced, post-execution
+ getQuery().setSession(null);
+ return result;
}
/**
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/AdvancedTableCreator.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/AdvancedTableCreator.java
index 029f410..151e5c4 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/AdvancedTableCreator.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/AdvancedTableCreator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -88,6 +88,10 @@
addTableDefinition(buildCMP3_DOORTable());
addTableDefinition(buildHOCKEY_RINKTable());
addTableDefinition(buildHOCKEY_PUCKTable());
+ addTableDefinition(buildBILLTable());
+ addTableDefinition(buildBILL_LINETable());
+ addTableDefinition(buildBILL_LINEITEMTable());
+ addTableDefinition(buildBILL_ACTIONTable());
}
public TableDefinition buildADDRESSTable() {
@@ -2576,4 +2580,172 @@
return table;
}
+ public TableDefinition buildBILLTable() {
+ TableDefinition table = new TableDefinition();
+ table.setName("JPA_BILL");
+
+ FieldDefinition fieldID = new FieldDefinition();
+ fieldID.setName("ID");
+ fieldID.setTypeName("NUMBER");
+ fieldID.setSize(19);
+ fieldID.setIsPrimaryKey(true);
+ fieldID.setIsIdentity(false);
+ fieldID.setUnique(false);
+ fieldID.setShouldAllowNull(false);
+ table.addField(fieldID);
+
+ FieldDefinition fieldORDERIDENTIFIER = new FieldDefinition();
+ fieldORDERIDENTIFIER.setName("ORDERIDENTIFIER");
+ fieldORDERIDENTIFIER.setTypeName("VARCHAR");
+ fieldORDERIDENTIFIER.setSize(64);
+ fieldORDERIDENTIFIER.setShouldAllowNull(true);
+ fieldORDERIDENTIFIER.setIsPrimaryKey(false);
+ fieldORDERIDENTIFIER.setUnique(false);
+ fieldORDERIDENTIFIER.setIsIdentity(false);
+ table.addField(fieldORDERIDENTIFIER);
+
+ FieldDefinition fieldSTATUS = new FieldDefinition();
+ fieldSTATUS.setName("STATUS");
+ fieldSTATUS.setTypeName("VARCHAR");
+ fieldSTATUS.setSize(64);
+ fieldSTATUS.setShouldAllowNull(true);
+ fieldSTATUS.setIsPrimaryKey(false);
+ fieldSTATUS.setUnique(false);
+ fieldSTATUS.setIsIdentity(false);
+ table.addField(fieldSTATUS);
+
+ return table;
+ }
+
+ public TableDefinition buildBILL_LINETable() {
+ TableDefinition table = new TableDefinition();
+ table.setName("JPA_BILL_LINE");
+
+ FieldDefinition fieldID = new FieldDefinition();
+ fieldID.setName("ID");
+ fieldID.setTypeName("NUMBER");
+ fieldID.setSize(19);
+ fieldID.setIsPrimaryKey(true);
+ fieldID.setIsIdentity(false);
+ fieldID.setUnique(false);
+ fieldID.setShouldAllowNull(false);
+ table.addField(fieldID);
+
+ FieldDefinition fieldQUANTITY = new FieldDefinition();
+ fieldQUANTITY.setName("QUANTITY");
+ fieldQUANTITY.setTypeName("NUMBER");
+ fieldQUANTITY.setSize(19);
+ fieldQUANTITY.setIsPrimaryKey(false);
+ fieldQUANTITY.setIsIdentity(false);
+ fieldQUANTITY.setUnique(false);
+ fieldQUANTITY.setShouldAllowNull(false);
+ table.addField(fieldQUANTITY);
+
+ FieldDefinition fieldBILLID = new FieldDefinition();
+ fieldBILLID.setName("BILL_ID");
+ fieldBILLID.setTypeName("NUMBER");
+ fieldBILLID.setSize(19);
+ fieldBILLID.setIsPrimaryKey(false);
+ fieldBILLID.setIsIdentity(false);
+ fieldBILLID.setUnique(false);
+ fieldBILLID.setShouldAllowNull(false);
+ table.addField(fieldBILLID);
+
+ ForeignKeyConstraint fk_JPA_BILL_LINE_BILL_ID = new ForeignKeyConstraint();
+ fk_JPA_BILL_LINE_BILL_ID.setName("FK_JPA_BILL_LINE_BILL_ID");
+ fk_JPA_BILL_LINE_BILL_ID.setTargetTable("JPA_BILL");
+ fk_JPA_BILL_LINE_BILL_ID.addSourceField("BILL_ID");
+ fk_JPA_BILL_LINE_BILL_ID.addTargetField("ID");
+ table.addForeignKeyConstraint(fk_JPA_BILL_LINE_BILL_ID);
+
+ return table;
+ }
+
+ public TableDefinition buildBILL_LINEITEMTable() {
+ TableDefinition table = new TableDefinition();
+ table.setName("JPA_BILL_LINEITEM");
+
+ FieldDefinition fieldID = new FieldDefinition();
+ fieldID.setName("ID");
+ fieldID.setTypeName("NUMBER");
+ fieldID.setSize(19);
+ fieldID.setIsPrimaryKey(true);
+ fieldID.setIsIdentity(false);
+ fieldID.setUnique(false);
+ fieldID.setShouldAllowNull(false);
+ table.addField(fieldID);
+
+ FieldDefinition fieldITEMNAME = new FieldDefinition();
+ fieldITEMNAME.setName("ITEMNAME");
+ fieldITEMNAME.setTypeName("VARCHAR");
+ fieldITEMNAME.setSize(255);
+ fieldITEMNAME.setIsPrimaryKey(false);
+ fieldITEMNAME.setIsIdentity(false);
+ fieldITEMNAME.setUnique(false);
+ fieldITEMNAME.setShouldAllowNull(false);
+ table.addField(fieldITEMNAME);
+
+ FieldDefinition fieldBILLLINE_ID = new FieldDefinition();
+ fieldBILLLINE_ID.setName("BILLLINE_ID");
+ fieldBILLLINE_ID.setTypeName("NUMBER");
+ fieldBILLLINE_ID.setSize(19);
+ fieldBILLLINE_ID.setIsPrimaryKey(false);
+ fieldBILLLINE_ID.setIsIdentity(false);
+ fieldBILLLINE_ID.setUnique(false);
+ fieldBILLLINE_ID.setShouldAllowNull(false);
+ table.addField(fieldBILLLINE_ID);
+
+ ForeignKeyConstraint fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID = new ForeignKeyConstraint();
+ fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID.setName("JPA_BILL_LINEITEM_BILLLINE_ID");
+ fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID.setTargetTable("JPA_BILL_LINE");
+ fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID.addSourceField("BILLLINE_ID");
+ fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID.addTargetField("ID");
+ table.addForeignKeyConstraint(fk_JPA_BILL_LINE_ITEM_BILL_LINE_ID);
+
+ return table;
+ }
+
+ public TableDefinition buildBILL_ACTIONTable() {
+ TableDefinition table = new TableDefinition();
+ table.setName("JPA_BILL_ACTION");
+
+ FieldDefinition fieldID = new FieldDefinition();
+ fieldID.setName("ID");
+ fieldID.setTypeName("NUMBER");
+ fieldID.setSize(19);
+ fieldID.setIsPrimaryKey(true);
+ fieldID.setIsIdentity(false);
+ fieldID.setUnique(false);
+ fieldID.setShouldAllowNull(false);
+ table.addField(fieldID);
+
+ FieldDefinition fieldPRIORITY = new FieldDefinition();
+ fieldPRIORITY.setName("PRIORITY");
+ fieldPRIORITY.setTypeName("NUMBER");
+ fieldPRIORITY.setSize(3);
+ fieldPRIORITY.setIsPrimaryKey(false);
+ fieldPRIORITY.setIsIdentity(false);
+ fieldPRIORITY.setUnique(false);
+ fieldPRIORITY.setShouldAllowNull(false);
+ table.addField(fieldPRIORITY);
+
+ FieldDefinition fieldBILLLINE_ID = new FieldDefinition();
+ fieldBILLLINE_ID.setName("BILLLINE_ID");
+ fieldBILLLINE_ID.setTypeName("NUMBER");
+ fieldBILLLINE_ID.setSize(19);
+ fieldBILLLINE_ID.setIsPrimaryKey(false);
+ fieldBILLLINE_ID.setIsIdentity(false);
+ fieldBILLLINE_ID.setUnique(false);
+ fieldBILLLINE_ID.setShouldAllowNull(false);
+ table.addField(fieldBILLLINE_ID);
+
+ ForeignKeyConstraint fk_FK_JPA_BILL_ACTION_BILLLINE_ID = new ForeignKeyConstraint();
+ fk_FK_JPA_BILL_ACTION_BILLLINE_ID.setName("FK_JPA_BILL_ACTION_BILLLINE_ID");
+ fk_FK_JPA_BILL_ACTION_BILLLINE_ID.setTargetTable("JPA_BILL_LINE");
+ fk_FK_JPA_BILL_ACTION_BILLLINE_ID.addSourceField("BILLLINE_ID");
+ fk_FK_JPA_BILL_ACTION_BILLLINE_ID.addTargetField("ID");
+ table.addForeignKeyConstraint(fk_FK_JPA_BILL_ACTION_BILLLINE_ID);
+
+ return table;
+ }
}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Bill.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Bill.java
new file mode 100644
index 0000000..3215c0c
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Bill.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2016 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 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:
+ * dminsky - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa.advanced;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "JPA_BILL")
+public class Bill {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @OneToMany(mappedBy="bill", cascade=CascadeType.ALL, orphanRemoval=true)
+ private List<BillLine> billLines;
+
+ private String orderIdentifier;
+ private String status = STATUS_NEW;
+
+ public static final String STATUS_NEW = "NEW";
+ public static final String STATUS_PROCESSING = "PROCESSING";
+
+ public Bill() {
+ super();
+ this.billLines = new ArrayList<BillLine>();
+ }
+
+ public void addBillLine(BillLine billLine) {
+ if (!this.billLines.contains(billLine)) {
+ this.billLines.add(billLine);
+ billLine.setBill(this);
+ }
+ }
+
+ public void removeBillLine(BillLine billLine) {
+ if (this.billLines.contains(billLine)) {
+ this.billLines.remove(billLine);
+ billLine.setBill(null);
+ }
+ }
+
+ public Long getId() {
+ return this.id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getOrderIdentifier() {
+ return this.orderIdentifier;
+ }
+
+ public void setOrderIdentifier(String orderIdentifier) {
+ this.orderIdentifier = orderIdentifier;
+ }
+
+ public List<BillLine> getBillLines() {
+ return billLines;
+ }
+
+ public void setBillLines(List<BillLine> billLines) {
+ this.billLines = billLines;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " id:[" + this.id + "] order id:[" + this.orderIdentifier + "] hashcode:[" + System.identityHashCode(this) + "]";
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillAction.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillAction.java
new file mode 100644
index 0000000..b983edc
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillAction.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2016 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 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:
+ * dminsky - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa.advanced;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="JPA_BILL_ACTION")
+public class BillAction {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @OneToOne
+ private BillLine billLine;
+
+ private int priority;
+
+ public BillAction() {
+ super();
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public BillLine getBillLine() {
+ return billLine;
+ }
+
+ public void setBillLine(BillLine billLine) {
+ this.billLine = billLine;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " id:[" + this.id + "] priority:[" + this.priority + "] hashcode:[" + System.identityHashCode(this) + "]";
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLine.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLine.java
new file mode 100644
index 0000000..f6d9777
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLine.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2016 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 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:
+ * dminsky - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa.advanced;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "JPA_BILL_LINE")
+public class BillLine {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @ManyToOne
+ private Bill bill;
+
+ @OneToMany(mappedBy="billLine", cascade=CascadeType.ALL, orphanRemoval=true)
+ private List<BillLineItem> billLineItems;
+
+ private int quantity;
+
+ public BillLine() {
+ super();
+ this.billLineItems = new ArrayList<BillLineItem>();
+ }
+
+ public Long getId() {
+ return this.id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Bill getBill() {
+ return this.bill;
+ }
+
+ public void setBill(Bill bill) {
+ this.bill = bill;
+ }
+
+ public int getQuantity() {
+ return this.quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ public List<BillLineItem> getBillLineItems() {
+ return billLineItems;
+ }
+
+ public void setBillLineItems(List<BillLineItem> billLineItems) {
+ this.billLineItems = billLineItems;
+ }
+
+ public void addBillLineItem(BillLineItem item) {
+ if (!getBillLineItems().contains(item)) {
+ getBillLineItems().add(item);
+ item.setBillLine(this);
+ }
+ }
+
+ public void removeBillLineItem(BillLineItem item) {
+ if (getBillLineItems().contains(item)) {
+ getBillLineItems().remove(item);
+ item.setBillLine(null);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " id:[" + this.id + "] quantity:[" + this.quantity + "] hashcode:[" + System.identityHashCode(this) + "]";
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLineItem.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLineItem.java
new file mode 100644
index 0000000..23553e4
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/BillLineItem.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2016 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 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:
+ * dminsky - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa.advanced;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="JPA_BILL_LINEITEM")
+public class BillLineItem {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @ManyToOne
+ private BillLine billLine;
+
+ private String itemName;
+
+ public BillLineItem() {
+ super();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public BillLine getBillLine() {
+ return billLine;
+ }
+
+ public void setBillLine(BillLine billLine) {
+ this.billLine = billLine;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public void setItemName(String itemName) {
+ this.itemName = itemName;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " id:[" + this.id + "] itemName:[" + this.itemName + "] hashcode:[" + System.identityHashCode(this) + "]";
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
index c05006a..984f8ad 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -64,12 +64,15 @@
import org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener;
import org.eclipse.persistence.descriptors.invalidation.CacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy;
+import org.eclipse.persistence.indirection.IndirectContainer;
+import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.indirection.IndirectCollection;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.indirection.DatabaseValueHolder;
+import org.eclipse.persistence.internal.indirection.QueryBasedValueHolder;
import org.eclipse.persistence.internal.jpa.EJBQueryImpl;
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate;
import org.eclipse.persistence.internal.jpa.EntityManagerImpl;
@@ -81,14 +84,20 @@
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.ManyToManyMapping;
+import org.eclipse.persistence.mappings.OneToManyMapping;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.mappings.UnidirectionalOneToManyMapping;
+import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.DoesExistQuery;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.testing.framework.JoinedAttributeTestHelper;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCaseHelper;
+import org.eclipse.persistence.testing.models.jpa.advanced.Bill;
+import org.eclipse.persistence.testing.models.jpa.advanced.BillLine;
+import org.eclipse.persistence.testing.models.jpa.advanced.BillLineItem;
+import org.eclipse.persistence.testing.models.jpa.advanced.BillAction;
import org.eclipse.persistence.testing.models.jpa.advanced.Address;
import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
import org.eclipse.persistence.testing.models.jpa.advanced.Bag;
@@ -221,6 +230,7 @@
suite.addTest(new AdvancedJPAJunitTest("testAttributeOverrideToMultipleSameDefaultColumnName"));
suite.addTest(new AdvancedJPAJunitTest("testTransparentIndirectionValueHolderSessionReset"));
+ suite.addTest(new AdvancedJPAJunitTest("testTransparentIndirectionQuerySessionReset"));
if (!isJPA10()) {
// These tests use JPA 2.0 entity manager API
@@ -2733,6 +2743,157 @@
}
}
+ /**
+ * Bug 489898 - RepeatableWriteUnitOfWork linked by QueryBasedValueHolder in shared cache in specific scenario
+ *
+ * Complex scenario: In a transaction, associate an existing object to a new object, refresh the existing object.
+ * In a second transaction, read the new object and traverse relationships to the existing object, and trigger
+ * an indirect relationship. The existing wrapped indirection query on the indirect relationship should
+ * ensure that the UnitOfWork (RepeatableWriteUnitOfWork) used for the query is unreferenced correctly, to
+ * avoid referencing it within the shared cache, via the existing referenced query.
+ */
+ public void testTransparentIndirectionQuerySessionReset() {
+ Bill bill = null;
+ BillLine billLine = null;
+ BillLineItem billLineItem = null;
+ BillAction billAction = null;
+
+ // setup
+ EntityManager em = createEntityManager();
+ try {
+ beginTransaction(em);
+
+ bill = new Bill();
+ bill.setOrderIdentifier("Test Bill");
+
+ billLine = new BillLine();
+ billLine.setQuantity(6);
+ bill.addBillLine(billLine);
+
+ billLineItem = new BillLineItem();
+ billLineItem.setItemName("Test Widget");
+ billLine.addBillLineItem(billLineItem);
+
+ em.persist(bill);
+ em.persist(billLine);
+ em.persist(billLineItem);
+
+ commitTransaction(em);
+
+ assertNotNull("bill should be non-null", bill);
+ assertNotNull("bill's id should be non-null", bill.getId());
+ assertNotNull("billLine should be non-null", billLine);
+ assertNotNull("billLine's id should be non-null", billLine.getId());
+ assertNotNull("billLineItem should be non-null", billLineItem);
+ assertNotNull("billLineItem's id should be non-null", billLineItem.getId());
+ } finally {
+ closeEntityManager(em);
+ clearCache(); // start test with an empty cache
+ }
+
+ try {
+ // test - txn #1 : read, modify, persist, refresh related Entity
+ em = createEntityManager();
+ try {
+ beginTransaction(em);
+
+ Bill billReRead = em.createQuery("SELECT b FROM Bill b where b.id=" + bill.getId(), Bill.class).getSingleResult();
+ assertNotNull(billReRead);
+ BillLine billLineReRead = billReRead.getBillLines().get(0);
+ assertNotNull(billLineReRead);
+
+ billAction = new BillAction();
+ billAction.setBillLine(billLineReRead);
+ billAction.setPriority(2);
+
+ em.persist(billAction);
+
+ em.refresh(billLineReRead); // refresh
+
+ commitTransaction(em);
+ } finally {
+ if (isTransactionActive(em)) {
+ rollbackTransaction(em);
+ }
+ closeEntityManager(em);
+ }
+
+ // test - txn #2 : read, modify and trigger relationship on related Entity
+ em = createEntityManager();
+ try {
+ beginTransaction(em);
+
+ Bill billReRead = em.createQuery("SELECT b FROM Bill b where b.id=" + bill.getId(), Bill.class).getSingleResult();
+ billReRead.setStatus(Bill.STATUS_PROCESSING); // DM: if there is no update to Order, issue doesn't occur
+
+ BillAction billActionReRead = em.createQuery("SELECT a FROM BillAction a where a.id=" + billAction.getId(), BillAction.class).getSingleResult();
+ assertNotNull(billActionReRead);
+
+ BillLine billLineReRead = billActionReRead.getBillLine();
+ assertNotNull(billLineReRead);
+
+ billLineReRead.getBillLineItems().size(); // Access & trigger BillLine -> BillLineItems list
+
+ commitTransaction(em);
+ } finally {
+ if (isTransactionActive(em)) {
+ rollbackTransaction(em);
+ }
+ closeEntityManager(em);
+ }
+
+ // verify
+ // Failure case: non-null session (a UnitOfWork/RepeatableWriteUnitOfWork) referenced in the wrapped ValueHolder's query.
+ ServerSession srv = getServerSession();
+ ClassDescriptor descriptor = srv.getDescriptor(billLine);
+ Long blId = billLine.getId();
+
+ BillLine cachedBillLine = (BillLine)srv.getIdentityMapAccessor().getFromIdentityMap(blId, BillLine.class);
+ assertNotNull("BillLine from shared cache is null with id: " + blId, cachedBillLine);
+
+ OneToManyMapping mapping = (OneToManyMapping)srv.getDescriptor(cachedBillLine).getMappingForAttributeName("billLineItems");
+ IndirectContainer billLineItemsVH = (IndirectContainer) mapping.getAttributeValueFromObject(cachedBillLine);
+ assertNotNull("BillLineItems ValueHolder should not be null", billLineItemsVH);
+
+ ValueHolderInterface wrappedVH = billLineItemsVH.getValueHolder();
+ assertNotNull("Wrapped ValueHolder should not be null", wrappedVH);
+
+ if (wrappedVH instanceof QueryBasedValueHolder) {
+ DatabaseQuery query = ((QueryBasedValueHolder)wrappedVH).getQuery();
+ if (query.getSession() != null && query.getSession().isUnitOfWork()) {
+ fail("UnitOfWork referenced in Query from wrapped QueryBasedValueHolder in shared cache");
+ }
+ }
+ } finally {
+ // reset
+ em = createEntityManager();
+ try {
+ beginTransaction(em);
+ bill = em.find(Bill.class, bill.getId());
+ if (bill != null) {
+ em.remove(bill);
+ }
+ billLine = em.find(BillLine.class, billLine.getId());
+ if (billLine != null) {
+ em.remove(billLine);
+ }
+ billLineItem = em.find(BillLineItem.class, billLineItem.getId());
+ if (billLineItem != null) {
+ em.remove(billLineItem);
+ }
+ if (billAction != null) {
+ billAction = em.find(BillAction.class, billAction.getId());
+ if (billAction != null) {
+ em.remove(billAction);
+ }
+ }
+ commitTransaction(em);
+ } finally {
+ closeEntityManager(em);
+ }
+ }
+ }
+
protected int getVersion(EntityManager em, Dealer dealer) {
Vector pk = new Vector(1);
pk.add(dealer.getId());