blob: 8c6ce4f42889cd68ca1a2583a4928d3d073adbd7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.flush;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
public class TestCascadingFlush extends SingleEMFTestCase {
boolean supportsNativeSequence = false;
@Override
public void setUp() {
setUp(Assignment.class, ClassPeriod.class, Course.class, SubTopic.class, Topic.class, CLEAR_TABLES);
try {
supportsNativeSequence = ((JDBCConfiguration) emf
.getConfiguration()).getDBDictionaryInstance()
.nextSequenceQuery != null;
} catch (Throwable t) {
supportsNativeSequence = false;
}
}
/**
* Verifies flushing a complex bidirectional domain model results in retrieval and population of all sequence-gen
* ID values.
*/
public void testCascadingFlushBasic() {
if (!supportsNativeSequence) {
return;
}
EntityManager em = emf.createEntityManager();
Long courseId = populate(em);
em.clear();
Course course = em.find(Course.class, courseId);
verifyCascadingFlush(em, course);
em.close();
}
/**
* Verifies flushing a complex bidirectional domain model results in retrieval and population of all sequence-gen
* ID values using an detached, then merged entity graph.
*/
public void testCascadingFlushDetach() {
if (!supportsNativeSequence) {
return;
}
EntityManager em = emf.createEntityManager();
Long courseId = populate(em);
em.clear();
Course tmpCourse = em.find(Course.class, courseId);
Course course = OpenJPAPersistence.cast(em).detachCopy(tmpCourse);
assertNotEquals(course, tmpCourse);
verifyCascadingFlush(em, course);
em.close();
}
/**
* Verifies flushing a complex bidirectional domain model results in retrieval of all sequence-gen ID values using
* an serialized (resulting in detach), then merged entity graph.
*/
public void testCascadingFlushSerialize() {
if (!supportsNativeSequence) {
return;
}
EntityManager em = emf.createEntityManager();
try {
Long courseId = populate(em);
em.clear();
Course tmpCourse = em.find(Course.class, courseId);
Course course = null;
try {
course = (Course)roundtrip(tmpCourse, false);
} catch (Throwable t) {
fail("Failed to serialize and deserialize persistent object.");
}
assertNotEquals(course, tmpCourse);
verifyCascadingFlush(em, course);
}
finally {
if (em != null) {
em.close();
}
}
}
private void verifyCascadingFlush(EntityManager em, Course course) {
try {
beginTx(em);
// Add a class period to the graph
addClassPeriod(course);
// Merge in the new entities
Course course2 = em.merge(course);
// Flush to the database. ID's should be assigned to all elements in
// the graph.
em.flush();
// Verify all id's are assigned
assertTrue(course2.getCourseId() > 0);
assertNotNull(course2.getClassPeriods());
Set<ClassPeriod> cps = course2.getClassPeriods();
assertTrue(cps.size() == 2);
for (ClassPeriod cp : cps) {
assertNotNull(cp);
assertTrue(cp.getClassPeriodId() > 0);
assertEquals(cp.getCourse(), course2);
Set<Topic> topics = cp.getTopics();
assertNotNull(topics);
assertTrue(topics.size() > 0);
for (Topic t : topics) {
assertNotNull(t);
assertTrue(t.getTopicId() > 0);
Set<Assignment> assignments = t.getAssignments();
assertNotNull(assignments);
assertTrue(assignments.size() == 1);
for (Assignment a : assignments) {
assertNotNull(a);
assertTrue(a.getAssignmentId() > 0);
}
Set<SubTopic> subTopics = t.getSubTopics();
assertNotNull(subTopics);
assertTrue(subTopics.size() == 1);
for (SubTopic s : subTopics) {
assertNotNull(s);
assertTrue(s.getSubtopicId() > 0);
}
}
}
commitTx(em);
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
fail();
}
}
public static Long populate(EntityManager em) {
beginTx(em);
Course course = createNewCourse();
em.persist(course);
em.flush();
commitTx(em);
return course.getCourseId();
}
public static Course createNewCourse() {
Course course = new Course();
course.setCourseText("Nuclear Physics");
Assignment assignment1 = new Assignment();
assignment1.setAssignmentText("Lab: Nuclear Fusion");
Set<Assignment> assignments = new HashSet<>();
assignments.add(assignment1);
SubTopic subtopic1 = new SubTopic();
subtopic1.setSubtopicText("Nuclear Fusion");
Set<SubTopic> subtopics = new HashSet<>();
subtopics.add(subtopic1);
Topic topic1 = new Topic();
topic1.setTopicText("Fundamentals of Nuclear Energy");
topic1.setAssignments(assignments);
topic1.setSubTopics(subtopics);
assignment1.setTopic(topic1);
subtopic1.setTopic(topic1);
Set<Topic> topics = new HashSet<>();
topics.add(topic1);
ClassPeriod cp1 = new ClassPeriod();
cp1.setClassPeriodText("8844: M,W,Th 8:00AM");
cp1.setTopics(topics);
cp1.setCourse(course);
topic1.setClassPeriod(cp1);
Set<ClassPeriod> cps = new HashSet<>();
cps.add(cp1);
course.setClassPeriods(cps);
return course;
}
public static void addClassPeriod(Course course) {
Assignment assignment = new Assignment();
assignment.setAssignmentText("Read pages 442-645");
Set<Assignment> assignments = new HashSet<>();
assignments.add(assignment);
SubTopic subTopic = new SubTopic();
subTopic.setSubtopicText("Newton");
Set<SubTopic> subTopics = new HashSet<>();
subTopics.add(subTopic);
Topic topic = new Topic();
topic.setTopicText("Gravity");
topic.setSubTopics(subTopics);
topic.setAssignments(assignments);
assignment.setTopic(topic);
subTopic.setTopic(topic);
Set<Topic> topics = new HashSet<>();
topics.add(topic);
// Add another topic
Assignment assignment2 = new Assignment();
assignment2.setAssignmentText("Read pages 645-785");
Set<Assignment> assignments2 = new HashSet<>();
assignments2.add(assignment2);
SubTopic subTopic2 = new SubTopic();
subTopic2.setSubtopicText("Forces");
Set<SubTopic> subTopics2 = new HashSet<>();
subTopics2.add(subTopic2);
Topic topic2 = new Topic();
topic2.setTopicText("Magnetism");
topic2.setSubTopics(subTopics2);
topic2.setAssignments(assignments2);
subTopic2.setTopic(topic);
subTopic2.setTopic(topic);
topics.add(topic2);
ClassPeriod cp2 = new ClassPeriod();
cp2.setClassPeriodText("8846: M,W,Th 11:00AM");
cp2.setTopics(topics);
cp2.setCourse(course);
topic.setClassPeriod(cp2);
topic2.setClassPeriod(cp2);
course.getClassPeriods().add(cp2);
}
private static void beginTx(EntityManager em) {
em.getTransaction().begin();
}
private static void commitTx(EntityManager em) {
em.getTransaction().commit();
}
public static Object roundtrip(Object orig, boolean validateEquality)
throws IOException, ClassNotFoundException {
assertNotNull(orig);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(orig);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object result = in.readObject();
if (validateEquality) {
assertEquals(orig.hashCode(), result.hashCode());
assertEquals(orig, result);
}
return result;
}
}