blob: c27dc1afc8024810a0cf87393239d1de4086d2ee [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.proxy;
import java.util.LinkedHashSet;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
import org.apache.openjpa.util.ChangeTracker;
import org.apache.openjpa.util.ProxyCollection;
/**
* Tests proxying and change tracking of collection fields for modification in
* detached state.
*
* Originally reported in
* <A HREF="https://issues.apache.org/jira/browse/OPENJPA-628">OPENJPA-628</A>
*
* @author Pinaki Poddar
*
*/
public class TestProxyCollection extends SingleEMFTestCase {
@Override
public void setUp() {
super.setUp(CLEAR_TABLES, TreeNode.class, ConcreteEntity.class, AbstractEntity.class);
}
/**
* Tests that a uniform tree is created with expected fan outs at each
* level. This is not a persistent operation, just in-memory.
*/
public void testCreateTree() {
TreeNode root = new TreeNode();
root.setName("0");
int[] fanOuts = {1,2,3};
root.createTree(fanOuts);
assertArrayEquals(fanOuts, root.getFanOuts());
}
/**
* Tests that a uniform tree can be modified with different fan outs at each
* level. This is not a persistent operation, just in-memory.
*/
public void testModifyTree() {
int[] fanOuts = {1,2,2,4};
int[] newFanOuts = {1,3,1,2};
TreeNode root = new TreeNode();
root.createTree(fanOuts);
assertArrayEquals(fanOuts, root.getFanOuts());
root.modify(newFanOuts);
assertArrayEquals(newFanOuts, root.getFanOuts());
}
/**
* Tests that a uniform tree is persisted and later fetched back with same
* number of children at every level.
*/
public void testPersistTree() {
int[] fanOuts = {2,3,4};
verify(create(fanOuts), fanOuts);
}
public void testAddNodeAtLeaf() {
int[] original = {1,2,3};
int[] modifier = {1,2,4}; // add new child at Level 2
createModifyAndMerge(original, modifier);
}
public void testAddNewLevel() {
int[] original = {1,2,3};
int[] modifier = {1,2,3,2}; // add 2 new children at new Level
createModifyAndMerge(original, modifier);
}
public void testAddAndRemove() {
int[] original = {2,3,4};
int[] modifier = {4,3,2}; // add 1 at Level 1 + remove 1 at Level 3
createModifyAndMerge(original, modifier);
}
public void testAddAtAllLevel() {
int[] original = {2,3,4};
int[] modifier = {3,4,5}; // add 1 at each Level
createModifyAndMerge(original, modifier);
}
public void testRemoveAtAllLevel() {
int[] original = {2,3,4};
int[] modifier = {1,2,3}; // remove 1 from each Level
createModifyAndMerge(original, modifier);
}
public void testCreateCorrectType() {
ConcreteEntity ce = new ConcreteEntity();
ce.addItem(ce);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(ce);
em.getTransaction().commit();
em.clear();
ce = em.find(ConcreteEntity.class, ce.getId());
assertNotNull(ce);
Class<?> proxyCls = ce.getItems().getClass();
assertTrue(proxyCls + " is not assignableFrom " + LinkedHashSet.class,
LinkedHashSet.class.isAssignableFrom(proxyCls));
}
/**
* Create a uniform tree with original fanout.
* Persist.
* Verify in a separate persistence context that the tree is stored.
* Modify the tree by adding or deleting nodes according to the given
* modified fanouts outside a transaction.
* Merge the changes.
* Verify that the changes are merged by fetching the modified version.
*
* @param original
* @param modified
*/
void createModifyAndMerge(int[] original, int[] modifier) {
TreeNode root = create(original);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
TreeNode modified = em.find(TreeNode.class, root.getId());
modified.modify(modifier);
em.merge(modified);
em.getTransaction().commit();
em.clear();
assertProxyCollection(root.getNodes(), false);
verify(root, modifier);
}
/**
* Create a uniform tree with given fan out.
* Persist.
* Verify that the tree is stored by fetching it in a separate persistence
* context.
*/
TreeNode create(int[] original) {
TreeNode root = new TreeNode();
root.createTree(original);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(root);
em.getTransaction().commit();
em.clear();
return root;
}
void verify(TreeNode node, int[] fanOuts) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
TreeNode test = em.find(TreeNode.class, node.getId());
assertNotNull(test);
assertArrayEquals(fanOuts, test.getFanOuts());
}
/**
* Asserts the given arrays have exactly same elements at the same index.
*/
void assertArrayEquals(int[] a, int[] b) {
assertEquals(a.length, b.length);
for (int i = 0; i<a.length; i++)
assertEquals(a[i], b[i]);
}
/**
* Asserts that the given object is a proxy collection and whether it is
* tracking changes.
*/
void assertProxyCollection(Object o, boolean tracking) {
assertTrue(o instanceof ProxyCollection);
ChangeTracker tracker = ((ProxyCollection)o).getChangeTracker();
if (tracking) {
assertNotNull(tracker);
assertTrue(tracker.isTracking());
} else {
assertFalse(tracker.isTracking());
}
}
/**
* Asserts that the given object is NOT a proxy collection.
*/
void assertNotProxyCollection(Object o) {
assertFalse(o instanceof ProxyCollection);
}
}