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());