Bug 441546 - Foreign Key attribute when used in JoinColumn generates wrong DDL statement.

- Added unit test to ForeignKeyTestSuite.
- Reviewed By Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
index de12e0c..792b0c0 100644
--- a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
+++ b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
@@ -73,6 +73,8 @@
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Athlete</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach</class>
+        <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver</class>
+        <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AccomplishmentConverter</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AgeConverter</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.DateConverter</class>
diff --git a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
index f36593b..c194388 100644
--- a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
+++ b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
@@ -80,6 +80,8 @@
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Athlete</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach</class>
+        <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver</class>
+        <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AccomplishmentConverter</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AgeConverter</class>
         <class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.DateConverter</class>
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java
new file mode 100644
index 0000000..ae7cc0a
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ *     07/07/2017-2.7 Vikram Bhatia
+ *       - 441546: Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa21.advanced.ddl;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "JPA21_DDL_DRIVER")
+public class Driver {
+    @Id
+    @Column(name = "NAME")
+    private String name;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java
new file mode 100644
index 0000000..c5498ff
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ *     07/07/2017-2.7 Vikram Bhatia
+ *       - 441546: Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa21.advanced.ddl;
+
+import javax.persistence.Entity;
+import javax.persistence.ForeignKey;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="JPA21_DDL_VEHICLE")
+public class Vehicle {
+  
+  @Id
+  private String vnum;
+  
+  @ManyToOne
+  @JoinColumn(name="LAST",foreignKey=@ForeignKey(name="FKv2d"))
+  private Driver driver;
+  
+  public String getVnum() {
+    return vnum;
+  }
+  public void setVnum(String vnum) {
+    this.vnum = vnum;
+  }
+  public Driver getDriver() {
+    return driver;
+  }
+  public void setDriver(Driver driver) {
+    this.driver = driver;
+  }
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
index dcb2677..9e7697d 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
@@ -27,6 +27,7 @@
 import javax.persistence.EntityManager;
 
 import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.exceptions.DatabaseException;
 import org.eclipse.persistence.internal.helper.DatabaseTable;
 import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy;
 import org.eclipse.persistence.mappings.DirectCollectionMapping;
@@ -41,6 +42,7 @@
 import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
 
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach;
+import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver;
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Organizer;
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race;
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Responsibility;
@@ -49,7 +51,7 @@
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.RunnerStatus;
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Shoe;
 import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Sprinter;
-
+import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle;
 import org.eclipse.persistence.testing.models.jpa21.advanced.enums.Health;
 import org.eclipse.persistence.testing.models.jpa21.advanced.enums.Level;
 import org.eclipse.persistence.testing.models.jpa21.advanced.enums.RunningStatus;
@@ -95,6 +97,7 @@ public static Test suite() {
         suite.addTest(new ForeignKeyTestSuite("testElementCollectionForeignKeys"));
 
         suite.addTest(new ForeignKeyTestSuite("testReadAndWriteDDLObjects"));
+        suite.addTest(new ForeignKeyTestSuite("testBug441546"));
 
 
         return suite;
@@ -268,4 +271,63 @@ public void testReadAndWriteDDLObjects() {
             closeEntityManager(em);
         }
     }
+    
+    /**
+     * Tests a many to one foreign key setting with null foreign key definition.
+     */
+    public void testBug441546() {
+        EntityManager em = createEntityManager();
+
+        try {
+            beginTransaction(em);
+            
+            Driver driver = new Driver();
+            driver.setName("Bob");
+            
+            Vehicle vehicle = new Vehicle();
+            vehicle.setVnum("1A467");
+            vehicle.setDriver(driver);
+
+            em.persist(driver);
+            em.persist(vehicle);
+            commitTransaction(em);
+ 
+        } catch (RuntimeException e) {
+            if (isTransactionActive(em)){
+                rollbackTransaction(em);
+            }
+
+            throw e;
+        } finally {
+            closeEntityManager(em);
+        }
+        
+        em = createEntityManager();
+        try {
+            // Try Deleting Driver with constraint
+            beginTransaction(em);
+            
+            Driver d2 = em.find(Driver.class, "Bob");
+            em.remove(d2);
+            
+            commitTransaction(em);         
+            fail("Foreign Key constraint is not defined in database on table.");
+   
+        } catch (RuntimeException e) {
+            if (isTransactionActive(em)){
+                rollbackTransaction(em);
+            }
+            
+            Throwable cause = e.getCause();
+
+            if (cause instanceof DatabaseException) {
+                assertTrue("Error Deleting row with constraint with different error.", cause.getCause() instanceof java.sql.SQLIntegrityConstraintViolationException);
+            } else { 
+                throw e;
+            }
+
+        } finally {
+            closeEntityManager(em);
+        }
+    }
 }
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
index 1e20113..f9d2268 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
@@ -103,6 +103,7 @@
 import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_CONVERTS;
 import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_FETCH_EAGER;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -1886,7 +1887,10 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
         // join, or if we simply set the whole mapping as read-only
         boolean allReadOnly = true;
         Map<DatabaseField, DatabaseField> fields = new HashMap<DatabaseField, DatabaseField>();
-
+        List<String> sourceFields = new ArrayList<String>();
+        List<String> targetFields = new ArrayList<String>();
+        String targetTableName = null;
+        
         // Build our fk->pk associations.
         for (JoinColumnMetadata joinColumn : joinColumns) {
             // Look up the primary key field from the referenced column name.
@@ -1904,6 +1908,11 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
             }
 
             fields.put(fkField, pkField);
+            sourceFields.add(fkField.getName());
+            targetFields.add(pkField.getName());
+            if (targetTableName == null) {
+                targetTableName = pkField.getTableName();
+            }
             allReadOnly = allReadOnly && fkField.isReadOnly();
         }
 
@@ -1938,7 +1947,7 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
         // the spec case (on the source table) and our extended support when
         // the fk's are on the target table as well.
         if (foreignKey != null) {
-            foreignKey.process(foreignKeyTable);
+            foreignKey.process(foreignKeyTable, sourceFields, targetFields, targetTableName);
         }
     }
 
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
index cb47276..0df4770 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
@@ -17,6 +17,8 @@
  ******************************************************************************/
 package org.eclipse.persistence.internal.jpa.metadata.columns;
 
+import java.util.List;
+
 import org.eclipse.persistence.internal.helper.DatabaseTable;
 import org.eclipse.persistence.internal.jpa.metadata.MetadataConstants;
 import org.eclipse.persistence.internal.jpa.metadata.ORMetadata;
@@ -164,11 +166,34 @@ protected boolean isProviderDefaultConstraintMode() {
      * Process this JPA metadata into an EclipseLink ForeignKeyConstraint.
      */
     public void process(DatabaseTable table) {
+        process(table, null, null, null);
+    }
+ 
+    /**
+     * INTERNAL:
+     * Process this JPA metadata into an EclipseLink ForeignKeyConstraint.
+     */
+    public void process(DatabaseTable table, List<String> sourceFields, List<String> targetFields, String targetTableName) {
         if (! isProviderDefaultConstraintMode()) {
             ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint();
             foreignKeyConstraint.setName(getName());
             foreignKeyConstraint.setForeignKeyDefinition(getForeignKeyDefinition());
             foreignKeyConstraint.setDisableForeignKey(isNoConstraintMode());
+            // Bug 441546 - Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+            // If foreignKeyDefinition element is not specified, the provider will generate foreign 
+            // key constraints whose update and delete actions it determines most appropriate for 
+            // the join column(s) to which the foreign key annotation is applied.
+            if (getForeignKeyDefinition() == null) {
+                if (sourceFields != null) {
+                    foreignKeyConstraint.setSourceFields(sourceFields);
+                }
+                if (targetFields != null) {
+                    foreignKeyConstraint.setTargetFields(targetFields);
+                }
+                if (targetTableName != null) {
+                    foreignKeyConstraint.setTargetTable(targetTableName);
+                }
+            }
             table.addForeignKeyConstraint(foreignKeyConstraint);
         }
     }