/tests/com/google/appengine/datanucleus/jpa/JPAAttachDetachTest.java
Java | 341 lines | 269 code | 29 blank | 43 comment | 0 complexity | 8bf325735944752ff2b5293bc6055b64 MD5 | raw file
1/* 2 * /********************************************************************** 3 * Copyright (c) 2009 Google Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * **********************************************************************/ 17package com.google.appengine.datanucleus.jpa; 18 19import com.google.appengine.api.datastore.Entity; 20import com.google.appengine.api.datastore.EntityNotFoundException; 21import com.google.appengine.api.datastore.KeyFactory; 22import com.google.appengine.datanucleus.Utils; 23import com.google.appengine.datanucleus.test.jdo.DetachableWithMultiValuePropsJDO; 24import com.google.appengine.datanucleus.test.jpa.BidirectionalChildListJPA; 25import com.google.appengine.datanucleus.test.jpa.Book; 26import com.google.appengine.datanucleus.test.jpa.DetachableJPA; 27import com.google.appengine.datanucleus.test.jpa.HasGrandchildJPA; 28import com.google.appengine.datanucleus.test.jpa.HasOneToManyListJPA; 29import com.google.appengine.datanucleus.test.jpa.HasOneToManySetJPA; 30 31 32import java.io.ByteArrayInputStream; 33import java.io.ByteArrayOutputStream; 34import java.io.IOException; 35import java.io.ObjectInputStream; 36import java.io.ObjectOutputStream; 37import java.io.Serializable; 38import java.util.Date; 39import java.util.List; 40 41import javax.jdo.JDOHelper; 42import javax.jdo.ObjectState; 43 44/** 45 * @author Max Ross <maxr@google.com> 46 */ 47public class JPAAttachDetachTest extends JPATestCase { 48 49 private <T extends Serializable> T toBytesAndBack(T obj) 50 throws IOException, ClassNotFoundException { 51 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 52 ObjectOutputStream oos = new ObjectOutputStream(baos); 53 oos.writeObject(obj); 54 55 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 56 ObjectInputStream ois = new ObjectInputStream(bais); 57 return (T) ois.readObject(); 58 } 59 60 public void testSimpleSerializeWithTxns() 61 throws IOException, ClassNotFoundException, EntityNotFoundException { 62 beginTxn(); 63 DetachableJPA pojo = new DetachableJPA(); 64 pojo.setVal("yar"); 65 Date now = new Date(); 66 pojo.setDate(now); 67 em.persist(pojo); 68 commitTxn(); 69 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 70 assertTrue(Date.class.isAssignableFrom(pojo.getDate().getClass())); 71 em.close(); // Detaches objects in L1 cache 72 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 73 em = emf.createEntityManager(); 74 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 75 76 pojo = toBytesAndBack(pojo); 77 78 assertEquals("yar", pojo.getVal()); 79 assertEquals(now, pojo.getDate()); 80 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 81 beginTxn(); 82 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 83 pojo.setVal("not yar"); 84 Date differentNow = new Date(now.getTime() + 1); 85 pojo.setDate(differentNow); 86 assertEquals(ObjectState.DETACHED_DIRTY, JDOHelper.getObjectState(pojo)); 87 pojo = em.merge(pojo); 88 assertEquals(ObjectState.PERSISTENT_DIRTY, JDOHelper.getObjectState(pojo)); 89 commitTxn(); 90 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 91 Entity e = ds.get(KeyFactory.createKey(DetachableJPA.class.getSimpleName(), pojo.getId())); 92 assertEquals("not yar", e.getProperty("val")); 93 assertEquals(differentNow, e.getProperty("date")); 94 } 95 96 public void testSimpleSerializeWithoutTxns() throws Exception { 97 switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed); 98 DetachableJPA pojo = new DetachableJPA(); 99 pojo.setVal("yar"); 100 Date now = new Date(); 101 pojo.setDate(now); 102 em.persist(pojo); 103 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 104 em.close(); // Detaches objects in L1 cache 105 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 106 assertEquals(Date.class, pojo.getDate().getClass()); 107 em = emf.createEntityManager(); 108 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 109 110 pojo = toBytesAndBack(pojo); 111 112 assertEquals("yar", pojo.getVal()); 113 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 114 pojo.setVal("not yar"); 115 Date differentNow = new Date(now.getTime() + 1); 116 pojo.setDate(differentNow); 117 assertEquals(ObjectState.DETACHED_DIRTY, JDOHelper.getObjectState(pojo)); 118 em.merge(pojo); 119 em.close(); // Detaches objects in L1 cache 120 Entity e = ds.get(KeyFactory.createKey(DetachableJPA.class.getSimpleName(), pojo.getId())); 121 assertEquals("not yar", e.getProperty("val")); 122 assertEquals(differentNow, e.getProperty("date")); 123 } 124 125 public void testMergeAfterFetch() throws Exception { 126 switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed); 127 DetachableJPA pojo = new DetachableJPA(); 128 pojo.setVal("yar"); 129 Date now = new Date(); 130 pojo.setDate(now); 131 em.persist(pojo); 132 em.close(); 133 em = emf.createEntityManager(); 134// beginTxn(); 135// pojo = em.find(DetachableJPA.class, pojo.getId()); 136 pojo = (DetachableJPA) em.createQuery("select from " + DetachableJPA.class.getName() + " b").getSingleResult(); 137// commitTxn(); 138 em.close(); 139 em = emf.createEntityManager(); 140 assertEquals("yar", pojo.getVal()); 141 pojo.setVal("not yar"); 142 em.merge(pojo); 143 em.close(); 144 Entity e = ds.get(KeyFactory.createKey(DetachableJPA.class.getSimpleName(), pojo.getId())); 145 assertEquals("not yar", e.getProperty("val")); 146 } 147 148 // TODO Should not be referring to DetachableWithMultiValuePropsJDO since is JDO!! 149 public void testSerializeWithMultiValueProps() throws Exception { 150 beginTxn(); 151 DetachableWithMultiValuePropsJDO pojo = new DetachableWithMultiValuePropsJDO(); 152 pojo.setStrList(Utils.newArrayList("c", "d")); 153 em.persist(pojo); 154 commitTxn(); 155 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 156 em.close(); // Detaches objects in L1 cache 157 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 158 em = emf.createEntityManager(); 159 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 160 161 pojo = toBytesAndBack(pojo); 162 163 assertEquals(Utils.newArrayList("c", "d"), pojo.getStrList()); 164 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 165 beginTxn(); 166 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 167 // reattach to the pm - this turns our regular list field into a managed 168 // list field 169 pojo = em.merge(pojo); 170 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 171 pojo.getStrList().add("e"); 172 commitTxn(); 173 Entity e = ds.get(KeyFactory.createKey(DetachableWithMultiValuePropsJDO.class.getSimpleName(), pojo.getId())); 174 assertEquals(3, ((List<String>)e.getProperty("strList")).size()); 175 assertEquals(Utils.newArrayList("c", "d", "e"), e.getProperty("strList")); 176 } 177 178 public void testSerializeWithOneToMany_AddChildToBidirectionalDetached() throws Exception { 179 beginTxn(); 180 HasOneToManyListJPA pojo = new HasOneToManyListJPA(); 181 pojo.setVal("yar"); 182 BidirectionalChildListJPA bidir = new BidirectionalChildListJPA(); 183 bidir.setChildVal("yar2"); 184 pojo.getBidirChildren().add(bidir); 185 em.persist(pojo); 186 commitTxn(); 187 em.close(); 188 em = emf.createEntityManager(); 189 190 pojo = toBytesAndBack(pojo); 191 assertEquals("yar", pojo.getVal()); 192 assertEquals(1, pojo.getBidirChildren().size()); 193 BidirectionalChildListJPA bidir2 = new BidirectionalChildListJPA(); 194 bidir.setChildVal("yar3"); 195 pojo.getBidirChildren().add(bidir2); 196 // Don't set the parent - this ref won't get updated when we call 197 // merge and we'll get an exception. 198// bidir2.setParent(pojo); 199 beginTxn(); 200 pojo = em.merge(pojo); 201 commitTxn(); 202 Entity e = ds.get(KeyFactory.stringToKey(bidir2.getId())); 203 assertEquals(KeyFactory.stringToKey(pojo.getId()), e.getKey().getParent()); 204 } 205 206 public void testSerializeWithOneToMany_AddChildToUnidirectionalDetached() throws Exception { 207 beginTxn(); 208 HasOneToManyListJPA pojo = new HasOneToManyListJPA(); 209 pojo.setVal("yar"); 210 Book b = new Book(); 211 b.setAuthor("harry"); 212 pojo.getBooks().add(b); 213 em.persist(pojo); 214 commitTxn(); 215 em.close(); 216 em = emf.createEntityManager(); 217 218 pojo = toBytesAndBack(pojo); 219 assertEquals("yar", pojo.getVal()); 220 assertEquals(1, pojo.getBooks().size()); 221 Book b2 = new Book(); 222 b2.setAuthor("yar3"); 223 pojo.getBooks().add(b2); 224 // Don't set the parent - this ref won't get updated when we call 225 // merge and we'll get an exception. 226// bidir2.setParent(pojo); 227 beginTxn(); 228 pojo = em.merge(pojo); 229 commitTxn(); 230 Entity e = ds.get(KeyFactory.stringToKey(b2.getId())); 231 assertEquals(KeyFactory.stringToKey(pojo.getId()), e.getKey().getParent()); 232 } 233 234 public void testSerializeWithOneToMany_AddGrandchildToUnidirectionalDetached() throws Exception { 235 beginTxn(); 236 HasGrandchildJPA hasGrandchild = new HasGrandchildJPA(); 237 HasOneToManySetJPA pojo = new HasOneToManySetJPA(); 238 hasGrandchild.getYar().add(pojo); 239 pojo.setVal("yar"); 240 Book b = new Book(); 241 b.setAuthor("harry"); 242 pojo.getBooks().add(b); 243 em.persist(hasGrandchild); 244 commitTxn(); 245 em.close(); 246 em = emf.createEntityManager(); 247 248 hasGrandchild = toBytesAndBack(hasGrandchild); 249 pojo = hasGrandchild.getYar().iterator().next(); 250 assertEquals("yar", pojo.getVal()); 251 assertEquals(1, pojo.getBooks().size()); 252 Book b2 = new Book(); 253 b2.setAuthor("yar3"); 254 pojo.getBooks().add(b2); 255 // Don't set the parent - this ref won't get updated when we call 256 // merge and we'll get an exception. 257// bidir2.setParent(pojo); 258 beginTxn(); 259 hasGrandchild = em.merge(hasGrandchild); 260 commitTxn(); 261 Entity e = ds.get(KeyFactory.stringToKey(b2.getId())); 262 assertEquals(KeyFactory.stringToKey(pojo.getId()), e.getKey().getParent()); 263 } 264 265 public void testSerializeWithOneToMany_AddChildToReattached() throws Exception { 266 beginTxn(); 267 HasOneToManyListJPA pojo = new HasOneToManyListJPA(); 268 pojo.setVal("yar"); 269 BidirectionalChildListJPA bidir = new BidirectionalChildListJPA(); 270 bidir.setChildVal("yar2"); 271 pojo.getBidirChildren().add(bidir); 272 em.persist(pojo); 273 commitTxn(); 274 em.close(); 275 em = emf.createEntityManager(); 276 277 pojo = toBytesAndBack(pojo); 278 assertEquals("yar", pojo.getVal()); 279 assertEquals(1, pojo.getBidirChildren().size()); 280 beginTxn(); 281 pojo = em.merge(pojo); 282 BidirectionalChildListJPA bidir2 = new BidirectionalChildListJPA(); 283 bidir.setChildVal("yar3"); 284 pojo.getBidirChildren().add(bidir2); 285 bidir2.setParent(pojo); 286 commitTxn(); 287 Entity e = ds.get(KeyFactory.stringToKey(bidir2.getId())); 288 assertEquals(KeyFactory.stringToKey(pojo.getId()), e.getKey().getParent()); 289 } 290 291 public void testDeleteDetachedObject_NoTxn() { 292 switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed); 293 DetachableJPA pojo = new DetachableJPA(); 294 pojo.setVal("yar"); 295 Date now = new Date(); 296 pojo.setDate(now); 297 em.persist(pojo); 298 em.close(); // Detaches objects in L1 cache 299 assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(pojo)); 300 em = emf.createEntityManager(); 301 pojo = em.find(pojo.getClass(), pojo.getId()); 302 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 303 em.close(); 304 em = emf.createEntityManager(); 305 pojo = em.merge(pojo); 306 // this is wrong and it will start to fail when we upgrade to DN 2.0 307 // We're tracking this with bug 308 // http://code.google.com/p/datanucleus-appengine/issues/detail?id=142 309 assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 310// assertEquals(ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL, JDOHelper.getObjectState(pojo)); 311// em.remove(pojo); 312// assertEquals(ObjectState.PERSISTENT_NEW_DELETED, JDOHelper.getObjectState(pojo)); 313// em.close(); 314// em = emf.createEntityManager(); 315// assertNull(em.find(pojo.getClass(), pojo.getId())); 316 } 317 318 public void testDeleteDetachedObject_Txn() { 319 beginTxn(); 320 DetachableJPA pojo = new DetachableJPA(); 321 pojo.setVal("yar"); 322 Date now = new Date(); 323 pojo.setDate(now); 324 em.persist(pojo); 325 commitTxn(); 326 Long id = pojo.getId(); 327 beginTxn(); 328 pojo = em.find(pojo.getClass(), pojo.getId()); 329 commitTxn(); 330 beginTxn(); 331 pojo = em.merge(pojo); 332 em.remove(pojo); 333 assertEquals(ObjectState.PERSISTENT_DELETED, JDOHelper.getObjectState(pojo)); 334 commitTxn(); 335 beginTxn(); 336 assertNull(em.find(pojo.getClass(), id)); 337 rollbackTxn(); 338 } 339 340 341}