View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2008 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.tests.services.persistence.hibernate;
18  
19  import java.util.ArrayList;
20  import java.util.IdentityHashMap;
21  import java.util.LinkedList;
22  import java.util.List;
23  
24  import javax.persistence.Entity;
25  
26  import org.junit.Test;
27  
28  import ch.elca.el4j.services.persistence.generic.dao.AbstractIdentityFixer;
29  import ch.elca.el4j.services.persistence.generic.dao.IdentityFixerMergePolicy;
30  import ch.elca.el4j.services.persistence.generic.dto.AbstractIntKeyIntOptimisticLockingDto;
31  import ch.elca.el4j.services.persistence.hibernate.HibernatePrimaryKeyObjectIdentityFixer;
32  
33  import static junit.framework.Assert.assertEquals;
34  import static junit.framework.Assert.assertFalse;
35  import static junit.framework.Assert.assertTrue;
36  
37  /**
38   * Tests for identity fixer.
39   *
40   * @svnLink $Revision: 3875 $;$Date: 2009-08-04 14:35:53 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/hibernate/src/test/java/ch/elca/el4j/tests/services/persistence/hibernate/IdentityFixerTest.java $
41   *
42   * @author Stefan Wismer (SWI)
43   */
44  public class IdentityFixerTest {
45  	@Test
46  	public void testAdvancedUsage() {
47  		Example anchor = new Example("Anchor");
48  		Example anchorChild1 = new Example("Child 1");
49  		
50  		anchor.parent = anchor;
51  		
52  		ArrayList<Example> childrenList = new ArrayList<Example>();
53  		anchor.children = childrenList;
54  		anchor.children.add(anchorChild1);
55  		anchor.ints = new int[] {3, 9};
56  		
57  		anchorChild1.parent = anchor;
58  		
59  		Example updated = new Example("Anchor Updated");
60  		Example updatedChild1 = new Example("Child 1 Updated");
61  		updated.parent = updated;
62  		updated.children = new ArrayList<Example>();
63  		updated.children.add(updatedChild1);
64  		updated.ints = new int[] {3, 100};
65  		
66  		updatedChild1.parent = updated;
67  		
68  		updated.setKey(1);
69  		updatedChild1.setKey(2);
70  		
71  		IdentityHashMap<Object, Object> collectionEntryMapping = new IdentityHashMap<Object, Object>();
72  		collectionEntryMapping.put(updated, anchor);
73  		collectionEntryMapping.put(updatedChild1, anchorChild1);
74  		
75  		List<Object> objectsToUpdate = new ArrayList<Object>();
76  		objectsToUpdate.add(anchor);
77  		// do NOT update anchorChild1
78  		AbstractIdentityFixer idFixer = new HibernatePrimaryKeyObjectIdentityFixer();
79  		Example merged = idFixer.merge(anchor, updated, 
80  			IdentityFixerMergePolicy.reloadObjectsPolicy(objectsToUpdate, collectionEntryMapping));
81  		
82  		assertEquals(merged, anchor);
83  		
84  		// anchor should have changed ...
85  		assertEquals(anchor.name, updated.name);
86  		assertEquals(anchor.parent, anchor);
87  		assertEquals(anchor.children, childrenList);
88  		assertEquals(anchor.children.get(0), anchorChild1);
89  		assertEquals(anchor.ints[0], 3);
90  		assertEquals(anchor.ints[1], 100);
91  		
92  		// ... but child should only have id-fixed reference to anchor 
93  		assertFalse(anchorChild1.name.equals(updatedChild1.name));
94  		assertEquals(anchorChild1.parent, anchor);
95  		
96  		// re-fix the updated, because the child list got modified
97  //		updated.children = new ArrayList<Example>();
98  //		updated.children.add(updatedChild1);
99  		
100 		// this time update all entities
101 		merged = idFixer.merge(anchor, updated, IdentityFixerMergePolicy.reloadAllPolicy(collectionEntryMapping));
102 		
103 		assertEquals(anchorChild1.name, updatedChild1.name);
104 		assertEquals(anchorChild1.parent, anchor);
105 		
106 		// add item to collection
107 		Example updatedChild2 = new Example("Child 2 Updated");
108 		updatedChild2.parent = updated;
109 		updated.children.add(updatedChild2);
110 		
111 		// inserted item should appear in anchor
112 		merged = idFixer.merge(anchor, updated);
113 		
114 		assertEquals(merged, anchor);
115 		
116 		assertEquals(anchor.children.size(), 2);
117 		assertEquals(anchor.children.get(1), updatedChild2);
118 		// inserted item should be id-fixed
119 		assertEquals(anchor.children.get(1).parent, anchor);
120 	}
121 	
122 	@Test
123 	public void testArraysAndCollections() {
124 		performArraysAndCollectionsTest(false);
125 		performArraysAndCollectionsTest(true);
126 		
127 		performCollectionMergeTest();
128 	}
129 
130 	public void performArraysAndCollectionsTest(boolean addAdditionalChild) {
131 		// Step 1: create anchor
132 		Example anchor = createExample("Anchor", false);
133 		
134 		// Step 2: create updated
135 		Example updated = createExample("Updated", true);
136 		
137 		Example updatedChild4 = new Example("Child 4 Updated");
138 		if (addAdditionalChild) {
139 			updated.children.add(updatedChild4);
140 			updatedChild4.setKey(5);
141 		}
142 		
143 		// help idFixer to correct collections
144 		IdentityHashMap<Object, Object> collectionEntryMapping = new IdentityHashMap<Object, Object>();
145 		collectionEntryMapping.put(updated, anchor);
146 		collectionEntryMapping.put(updated.children.get(0), anchor.children.get(0));
147 		collectionEntryMapping.put(updated.children.get(1), anchor.children.get(1));
148 		collectionEntryMapping.put(updated.children.get(2), anchor.children.get(2));
149 		
150 		
151 		// Step 3: fix identity
152 		AbstractIdentityFixer idFixer = new HibernatePrimaryKeyObjectIdentityFixer();
153 		Example merged = idFixer.merge(anchor, updated, 
154 			IdentityFixerMergePolicy.reloadAllPolicy(collectionEntryMapping));
155 		
156 		
157 		// Step 4: test results
158 		assertEquals(merged, anchor);
159 		
160 		// do not modify references
161 		assertTrue(anchor.children.get(0) != updated.children.get(0));
162 		assertTrue(anchor.children.get(1) != updated.children.get(1));
163 		assertTrue(anchor.children.get(2) != updated.children.get(2));
164 		
165 		assertEquals(anchor.children.get(0).name, updated.children.get(0).name);
166 		assertEquals(anchor.children.get(1).name, updated.children.get(1).name);
167 		assertEquals(anchor.children.get(2).name, updated.children.get(2).name);
168 		if (addAdditionalChild) {
169 			assertEquals(anchor.children.get(3).name, updatedChild4.name);
170 		}
171 		
172 		assertEquals(anchor.childrenArray[0].name, updated.children.get(0).name);
173 		assertEquals(anchor.childrenArray[1].name, updated.children.get(1).name);
174 		assertEquals(anchor.childrenArray[2].name, updated.children.get(2).name);
175 	}
176 	
177 	private void performCollectionMergeTest() {
178 		// test merging collections directly
179 		// Step 1: create anchor
180 		Example anchor = createExample("Anchor", false);
181 		anchor.children.get(0).childrenArray = new Example[] {anchor.children.get(1)};
182 		
183 		// Step 2: create updated
184 		Example updated = createExample("Updated", true);
185 		updated.children.get(0).childrenArray = new Example[] {updated.children.get(1)};
186 		
187 		// help idFixer to correct collections
188 		IdentityHashMap<Object, Object> collectionEntryMapping = new IdentityHashMap<Object, Object>();
189 		collectionEntryMapping.put(updated, anchor);
190 		collectionEntryMapping.put(updated.children.get(0), anchor.children.get(0));
191 		collectionEntryMapping.put(updated.children.get(1), anchor.children.get(1));
192 		collectionEntryMapping.put(updated.children.get(2), anchor.children.get(2));
193 		
194 		
195 		AbstractIdentityFixer idFixer = new HibernatePrimaryKeyObjectIdentityFixer();
196 		idFixer.merge(anchor.children, updated.children, 
197 			IdentityFixerMergePolicy.reloadAllPolicy(collectionEntryMapping));
198 	}
199 	
200 	@Test
201 	public void testCollectionReplacing() {
202 		Example anchor = new Example("Anchor");
203 		Example anchorChild1 = new Example("Child 1");
204 		
205 		anchor.parent = anchor;
206 		
207 		ArrayList<Example> childrenList = new ArrayList<Example>();
208 		anchor.children = childrenList;
209 		anchor.children.add(anchorChild1);
210 		anchor.ints = new int[] {3, 9};
211 		
212 		anchorChild1.parent = anchor;
213 		
214 		
215 		AbstractIdentityFixer idFixer = new HibernatePrimaryKeyObjectIdentityFixer();
216 		
217 		// insert the anchor into the idFixer representatives
218 		idFixer.merge(null, anchor);
219 		
220 		assertTrue("List of children not untouched!", anchor.children == childrenList);
221 		
222 		// simulate giving the anchor to hibernate
223 		idFixer.reverseMerge(anchor, true);
224 		
225 		// play hibernate and create an updated list
226 		LinkedList<Example> updatedList = new LinkedList<Example>();
227 		updatedList.add(anchorChild1);
228 		org.hibernate.collection.PersistentBag updatedHibernateList 
229 			= new org.hibernate.collection.PersistentBag(null, updatedList);
230 		
231 		anchor.children = updatedHibernateList;
232 		// "generate key"
233 		anchor.name = "Anchor(withKey)";
234 		
235 		// merge with the original object
236 		idFixer.merge(null, anchor);
237 		
238 		assertTrue("List of children not untouched!", anchor.children == childrenList);
239 		assertEquals("Name not updated", "Anchor(withKey)", anchor.name);
240 	}
241 	
242 	private Example createExample(String postfix, boolean setKeys) {
243 		Example root = new Example("Anchor " + postfix);
244 		Example child1 = new Example("Child 1 " + postfix);
245 		Example child2 = new Example("Child 2 " + postfix);
246 		Example child3 = new Example("Child 3 " + postfix);
247 		
248 		// build collection
249 		ArrayList<Example> childrenList = new ArrayList<Example>();
250 		childrenList.add(child1);
251 		childrenList.add(child2);
252 		childrenList.add(child3);
253 		root.children = childrenList;
254 		
255 		// build array
256 		root.ints = new int[] {1, 2, 3};
257 		root.childrenArray = new Example[] {child1, child2, child3};
258 		
259 		if (setKeys) {
260 			// set primary keys
261 			root.setKey(1);
262 			child1.setKey(2);
263 			child2.setKey(3);
264 			child3.setKey(4);
265 		}
266 		
267 		return root;
268 	}
269 	
270 	@Entity
271 	private class Example extends AbstractIntKeyIntOptimisticLockingDto {
272 		public Example() { }
273 		public Example(String name) {
274 			this.name = name;
275 		}
276 		// public field are enough for this test
277 		public String name;
278 		public int[] ints;
279 		public Example[] childrenArray;
280 		public List<Example> children;
281 		public Example parent;
282 		
283 		/** {@inheritDoc} */
284 		@Override
285 		public String toString() {
286 			return "Example [name: " + name + ", ints: " + (ints != null ? ints.toString() : "null") + "]";
287 		}
288 	}
289 }