PageRenderTime 106ms CodeModel.GetById 19ms app.highlight 80ms RepoModel.GetById 2ms app.codeStats 0ms

/tests/com/google/appengine/datanucleus/jpa/JPASubclassTest.java

http://datanucleus-appengine.googlecode.com/
Java | 700 lines | 586 code | 87 blank | 27 comment | 10 complexity | c8362be0eee4d423b49feb8f4da6f0f0 MD5 | raw file
  1/**********************************************************************
  2Copyright (c) 2009 Google Inc.
  3
  4Licensed under the Apache License, Version 2.0 (the "License");
  5you may not use this file except in compliance with the License.
  6You may obtain a copy of the License at
  7
  8http://www.apache.org/licenses/LICENSE-2.0
  9
 10Unless required by applicable law or agreed to in writing, software
 11distributed under the License is distributed on an "AS IS" BASIS,
 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13See the License for the specific language governing permissions and
 14limitations under the License.
 15**********************************************************************/
 16package com.google.appengine.datanucleus.jpa;
 17
 18import com.google.appengine.api.datastore.Entity;
 19import com.google.appengine.api.datastore.EntityNotFoundException;
 20import com.google.appengine.api.datastore.Key;
 21import com.google.appengine.api.datastore.KeyFactory;
 22import com.google.appengine.datanucleus.DatastoreManager;
 23import com.google.appengine.datanucleus.test.jpa.IsEmbeddedWithEmbeddedSuperclass;
 24import com.google.appengine.datanucleus.test.jpa.IsEmbeddedWithEmbeddedSuperclass2;
 25import com.google.appengine.datanucleus.test.jpa.SubclassesJPA;
 26import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.Child;
 27import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.ChildEmbeddedInTablePerClass;
 28import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.DurableChild;
 29import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.Grandchild;
 30import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.Joined;
 31import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.JoinedChild;
 32import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.MappedSuperclassChild;
 33import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.MappedSuperclassParent;
 34import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.Parent;
 35import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.SingleTable;
 36import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.SingleTableChild;
 37import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.TablePerClass;
 38import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.TablePerClassChild;
 39import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.TablePerClassGrandchild;
 40import com.google.appengine.datanucleus.test.jpa.SubclassesJPA.TablePerClassParentWithEmbedded;
 41
 42import org.datanucleus.exceptions.NoPersistenceInformationException;
 43
 44import java.util.List;
 45
 46import javax.persistence.PersistenceException;
 47import javax.persistence.Query;
 48
 49/**
 50 * @author Max Ross <maxr@google.com>
 51 */
 52public class JPASubclassTest extends JPATestCase {
 53
 54  public void testUnsupportedStrategies_GAE() {
 55    assertUnsupportedByGAE(new JoinedChild());
 56  }
 57
 58  public void testGrandchildren() throws Exception {
 59    testGrandchild(new TablePerClassGrandchild());
 60  }
 61
 62  public void testChildren() throws Exception {
 63    testChild(new TablePerClassChild(), null);
 64    testChild(new MappedSuperclassChild(), null);
 65    testChild(new SingleTableChild(), SingleTableChild.class.getName());
 66  }
 67
 68  public void testParents() throws Exception {
 69    testParent(new TablePerClass(), null);
 70    testParent(new Joined(), null);
 71    testParent(new SingleTable(), SingleTable.class.getName());
 72  }
 73
 74  public void testInsertParent_MappedSuperclass() throws EntityNotFoundException {
 75    MappedSuperclassParent parent = new MappedSuperclassParent();
 76    parent.setAString("a");
 77    beginTxn();
 78    try {
 79      em.persist(parent);
 80      commitTxn();
 81      fail("expected pe");
 82    } catch (PersistenceException pe) {
 83      assertTrue(pe.getCause() instanceof NoPersistenceInformationException);
 84    }
 85  }
 86
 87  public void testAttributeOverride() throws EntityNotFoundException {
 88    MappedSuperclassChild child = new MappedSuperclassChild();
 89    child.setOverriddenString("overridden");
 90    beginTxn();
 91    em.persist(child);
 92    commitTxn();
 93    Entity e = ds.get(KeyFactory.createKey(kindForClass(child.getClass()), child.getId()));
 94    assertEquals("overridden", e.getProperty("overridden_string"));
 95    assertFalse(e.hasProperty("overriddenString"));
 96  }
 97
 98  public void testEmbedded_Child() throws Exception {
 99    ChildEmbeddedInTablePerClass child = new ChildEmbeddedInTablePerClass();
100    child.setAString("aString");
101    child.setBString("bString");
102    IsEmbeddedWithEmbeddedSuperclass embedded = new IsEmbeddedWithEmbeddedSuperclass();
103    embedded.setVal0("embedded val 0");
104    embedded.setVal1("embedded val 1");
105    child.setEmbedded(embedded);
106    SubclassesJPA.IsEmbeddedBase embeddedBase = new SubclassesJPA.IsEmbeddedBase();
107    embeddedBase.setVal0("embedded base val 0");
108    child.setEmbeddedBase(embeddedBase);
109    IsEmbeddedWithEmbeddedSuperclass2 embedded2 = new IsEmbeddedWithEmbeddedSuperclass2();
110    embedded2.setVal2("embedded val 2");
111    embedded2.setVal3("embedded val 3");
112    child.setEmbedded2(embedded2);
113    SubclassesJPA.IsEmbeddedBase2
114        embeddedBase2 = new SubclassesJPA.IsEmbeddedBase2();
115    embeddedBase2.setVal2("embedded base val 2");
116    child.setEmbeddedBase2(embeddedBase2);
117    beginTxn();
118    em.persist(child);
119    commitTxn();
120    Key key = KeyFactory.createKey(kindForClass(child.getClass()), child.getId());
121    Entity e = ds.get(key);
122    assertEquals("aString", e.getProperty("aString"));
123    assertEquals("bString", e.getProperty("bString"));
124    assertEquals("embedded val 0", e.getProperty("val0"));
125    assertEquals("embedded val 1", e.getProperty("val1"));
126    assertEquals("embedded base val 0", e.getProperty("VAL0"));
127    assertEquals("embedded val 2", e.getProperty("val2"));
128    assertEquals("embedded val 3", e.getProperty("val3"));
129    assertEquals("embedded base val 2", e.getProperty("VAL2"));
130    em.close();
131    em = emf.createEntityManager();
132    beginTxn();
133    child = em.find(child.getClass(), child.getId());
134    assertEmbeddedChildContents(child);
135    commitTxn();
136    em.close();
137    em = emf.createEntityManager();
138    beginTxn();
139    Query q = em.createQuery("select from " + child.getClass().getName() + " b where embedded.val1 = :p "
140      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
141      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
142    q.setParameter("p", "embedded val 1");
143    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
144    assertEmbeddedChildContents(child);
145
146    q = em.createQuery("select from " + child.getClass().getName() + " b where embedded.val0 = :p "
147      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
148      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
149    q.setParameter("p", "embedded val 0");
150    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
151    assertEmbeddedChildContents(child);
152
153    q = em.createQuery("select from " + child.getClass().getName() + " b where embeddedBase.val0 = :p "
154      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
155      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
156    q.setParameter("p", "embedded base val 0");
157    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
158    assertEmbeddedChildContents(child);
159
160    q = em.createQuery("select from " + child.getClass().getName() + " b where embedded2.val2 = :p "
161      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
162      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
163    q.setParameter("p", "embedded val 2");
164    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
165    assertEmbeddedChildContents(child);
166
167    q = em.createQuery("select from " + child.getClass().getName() + " b where embedded2.val3 = :p "
168      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
169      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
170    q.setParameter("p", "embedded val 3");
171    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
172    assertEmbeddedChildContents(child);
173
174    q = em.createQuery("select from " + child.getClass().getName() + " b where embeddedBase2.val2 = :p "
175      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
176      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
177    q.setParameter("p", "embedded base val 2");
178    child = (ChildEmbeddedInTablePerClass) q.getSingleResult();
179    assertEmbeddedChildContents(child);
180
181    q = em.createQuery("select embedded.val1, embedded.val0, embeddedBase.val0, embedded2.val2, embedded2.val3, embeddedBase2.val2 from " +
182                    child.getClass().getName() + " b where embeddedBase2.val2 = :p");
183    q.setParameter("p", "embedded base val 2");
184
185    Object[] result = (Object[]) q.getSingleResult();
186    assertEquals("embedded val 1", result[0]);
187    assertEquals("embedded val 0", result[1]);
188    assertEquals("embedded base val 0", result[2]);
189    assertEquals("embedded val 2", result[3]);
190    assertEquals("embedded val 3", result[4]);
191    assertEquals("embedded base val 2", result[5]);
192
193    em.remove(child);
194    commitTxn();
195    try {
196      ds.get(key);
197      fail("expected enfe");
198    } catch (EntityNotFoundException enfe) {
199      // good
200    }
201  }
202
203  public void testEmbedded_Parent() throws Exception {
204    TablePerClassParentWithEmbedded parent = new TablePerClassParentWithEmbedded();
205    parent.setAString("aString");
206    IsEmbeddedWithEmbeddedSuperclass embedded = new IsEmbeddedWithEmbeddedSuperclass();
207    embedded.setVal0("embedded val 0");
208    embedded.setVal1("embedded val 1");
209    parent.setEmbedded(embedded);
210    SubclassesJPA.IsEmbeddedBase
211        embeddedBase = new SubclassesJPA.IsEmbeddedBase();
212    embeddedBase.setVal0("embedded base val 0");
213    parent.setEmbeddedBase(embeddedBase);
214    beginTxn();
215    em.persist(parent);
216    commitTxn();
217    Key key = KeyFactory.createKey(kindForClass(parent.getClass()), parent.getId());
218    Entity e = ds.get(key);
219    assertEquals("aString", e.getProperty("aString"));
220    assertEquals("embedded val 0", e.getProperty("val0"));
221    assertEquals("embedded val 1", e.getProperty("val1"));
222    assertEquals("embedded base val 0", e.getProperty("VAL0"));
223    em.close();
224    em = emf.createEntityManager();
225    beginTxn();
226    parent = em.find(parent.getClass(), parent.getId());
227    assertEmbeddedParentContents(parent);
228    commitTxn();
229    em.close();
230    em = emf.createEntityManager();
231    beginTxn();
232    Query q = em.createQuery("select from " + parent.getClass().getName() + " b where embedded.val1 = :p "
233      + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
234    q.setParameter("p", "embedded val 1");
235    parent = (TablePerClassParentWithEmbedded) q.getSingleResult();
236    assertEmbeddedParentContents(parent);
237
238    q = em.createQuery("select from " + parent.getClass().getName() + " b where embedded.val0 = :p "
239      + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
240    q.setParameter("p", "embedded val 0");
241    parent = (TablePerClassParentWithEmbedded) q.getSingleResult();
242    assertEmbeddedParentContents(parent);
243
244    q = em.createQuery("select from " + parent.getClass().getName() + " b where embeddedBase.val0 = :p "
245      + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
246    q.setParameter("p", "embedded base val 0");
247    parent = (TablePerClassParentWithEmbedded) q.getSingleResult();
248    assertEmbeddedParentContents(parent);
249
250    q = em.createQuery("select embedded.val1, embedded.val0, embeddedBase.val0 from " +
251                    parent.getClass().getName() + " b where embeddedBase.val0 = :p "
252      + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
253    q.setParameter("p", "embedded base val 0");
254
255    Object[] result = (Object[]) q.getSingleResult();
256    assertEquals("embedded val 1", result[0]);
257    assertEquals("embedded val 0", result[1]);
258    assertEquals("embedded base val 0", result[2]);
259
260    em.remove(parent);
261    commitTxn();
262    try {
263      ds.get(key);
264      fail("expected enfe");
265    } catch (EntityNotFoundException enfe) {
266      // good
267    }
268  }
269
270  public void testNondurableParent() {
271    DurableChild dc = new DurableChild();
272    dc.setStr("yar");
273    beginTxn();
274    em.persist(dc);
275    commitTxn();
276    beginTxn();
277    dc = em.find(DurableChild.class, dc.getId());
278    assertEquals("yar", dc.getStr());
279  }
280
281  // This is absurd, but if the signature of this method and the one below
282  // refers to the actual type we want the runtime enhancer gets totally
283  // confused.  
284  private void assertEmbeddedParentContents(Object obj) {
285    TablePerClassParentWithEmbedded parentWithEmbedded = (TablePerClassParentWithEmbedded) obj;
286    assertEquals("aString", parentWithEmbedded.getAString());
287    assertEquals("embedded val 0", parentWithEmbedded.getEmbedded().getVal0());
288    assertEquals("embedded val 1", parentWithEmbedded.getEmbedded().getVal1());
289    assertEquals("embedded base val 0", parentWithEmbedded.getEmbeddedBase().getVal0());
290  }
291
292  private void assertEmbeddedChildContents(Object obj) {
293    ChildEmbeddedInTablePerClass child = (ChildEmbeddedInTablePerClass) obj;
294    assertEquals("bString", child.getBString());
295    assertEquals("embedded val 2", child.getEmbedded2().getVal2());
296    assertEquals("embedded val 3", child.getEmbedded2().getVal3());
297    assertEquals("embedded base val 2", child.getEmbeddedBase2().getVal2());
298    assertEmbeddedParentContents(child);
299  }
300
301  private void assertUnsupportedByGAE(Object obj) {
302    switchDatasource(EntityManagerFactoryName.transactional_ds_non_transactional_ops_not_allowed);
303    beginTxn();
304    em.persist(obj);
305    try {
306      commitTxn();
307      fail("expected exception");
308    } catch (PersistenceException e) {
309      // good
310      assertTrue(e.getCause() instanceof DatastoreManager.UnsupportedInheritanceStrategyException);
311    }
312    rollbackTxn();
313  }
314
315  private void testInsertParent(Parent parent) throws Exception {
316    parent.setAString("a");
317    beginTxn();
318    em.persist(parent);
319    commitTxn();
320
321    Entity e = ds.get(KeyFactory.createKey(kindForClass(parent.getClass()), parent.getId()));
322    assertEquals("a", e.getProperty("aString"));
323  }
324
325  private void testInsertChild(Child child) throws Exception {
326    child.setAString("a");
327    child.setBString("b");
328    beginTxn();
329    em.persist(child);
330    commitTxn();
331
332    Entity e = ds.get(KeyFactory.createKey(kindForClass(child.getClass()), child.getId()));
333    assertEquals("a", e.getProperty("aString"));
334    assertEquals("b", e.getProperty("bString"));
335  }
336
337  private void testInsertGrandchild(Grandchild grandchild) throws Exception {
338    grandchild.setAString("a");
339    grandchild.setBString("b");
340    grandchild.setCString("c");
341    beginTxn();
342    em.persist(grandchild);
343    commitTxn();
344
345    Entity e = ds.get(KeyFactory.createKey(kindForClass(grandchild.getClass()), grandchild.getId()));
346    assertEquals("a", e.getProperty("aString"));
347    assertEquals("b", e.getProperty("bString"));
348    assertEquals("c", e.getProperty("cString"));
349  }
350
351  private void testFetchParent(Class<? extends Parent> parentClass) {
352    Entity e = new Entity(kindForClass(parentClass));
353    e.setProperty("aString", "a");
354    ds.put(e);
355
356    beginTxn();
357    Parent parent = em.find(parentClass, e.getKey());
358    assertEquals(parentClass, parent.getClass());
359    assertEquals("a", parent.getAString());
360    commitTxn();
361  }
362
363  private void testFetchChild(Class<? extends Child> childClass) {
364    Entity e = new Entity(kindForClass(childClass));
365    e.setProperty("aString", "a");
366    e.setProperty("bString", "b");
367    ds.put(e);
368
369    beginTxn();
370    Child child = em.find(childClass, e.getKey());
371    assertEquals(childClass, child.getClass());
372    assertEquals("a", child.getAString());
373    assertEquals("b", child.getBString());
374    commitTxn();
375  }
376
377  private void testFetchGrandchild(Class<? extends Grandchild> grandchildClass) {
378    Entity e = new Entity(kindForClass(grandchildClass));
379    e.setProperty("aString", "a");
380    e.setProperty("bString", "b");
381    e.setProperty("cString", "c");
382    ds.put(e);
383
384    beginTxn();
385    Grandchild grandchild = em.find(grandchildClass, e.getKey());
386    assertEquals(grandchildClass, grandchild.getClass());
387    assertEquals("a", grandchild.getAString());
388    assertEquals("b", grandchild.getBString());
389    assertEquals("c", grandchild.getCString());
390    commitTxn();
391  }
392
393  private void testQueryParent(Class<? extends Parent> parentClass, String discriminator) {
394    Entity e = new Entity(kindForClass(parentClass));
395    if (discriminator != null) {
396      e.setProperty("TYPE", discriminator);
397    }
398    e.setProperty("aString", "z8");
399    ds.put(e);
400
401    e = new Entity(kindForClass(parentClass));
402    if (discriminator != null) {
403      e.setProperty("TYPE", discriminator);
404    }
405    e.setProperty("aString", "z9");
406    ds.put(e);
407
408    beginTxn();
409    Query q = em.createQuery("select from " + parentClass.getName() + " b where aString = :p");
410    q.setParameter("p", "z8");
411    Parent parent = (Parent) q.getSingleResult();
412    assertEquals(parentClass, parent.getClass());
413    assertEquals("z8", parent.getAString());
414
415    q = em.createQuery("select from " + parentClass.getName() + " b where aString >= :p order by aString desc");
416    q.setParameter("p", "z8");
417    List<Parent> parents = q.getResultList();
418    assertEquals("z9", parents.get(0).getAString());
419    assertEquals("z8", parents.get(1).getAString());
420
421    q = em.createQuery("select aString from " + parentClass.getName() + " b where aString = :p");
422    q.setParameter("p", "z8");
423    String result = (String) q.getSingleResult();
424    assertEquals("z8", result);
425
426    commitTxn();
427
428  }
429
430  private void testQueryChild(Class<? extends Child> childClass, String discriminator) {
431    Entity e1 = new Entity(kindForClass(childClass));
432    if (discriminator != null) {
433      e1.setProperty("TYPE", discriminator);
434    }
435    e1.setProperty("aString", "a2");
436    e1.setProperty("bString", "b2");
437    ds.put(e1);
438
439    Entity e2 = new Entity(kindForClass(childClass));
440    if (discriminator != null) {
441      e2.setProperty("TYPE", discriminator);
442    }
443    e2.setProperty("aString", "a2");
444    e2.setProperty("bString", "b3");
445    ds.put(e2);
446
447    Entity e3 = new Entity(kindForClass(childClass));
448    if (discriminator != null) {
449      e3.setProperty("TYPE", discriminator);
450    }
451    e3.setProperty("aString", "a2");
452    e3.setProperty("bString", "b3");
453    ds.put(e3);
454
455    beginTxn();
456    Query q = em.createQuery("select from " + childClass.getName() + " b where aString = :p");
457    q.setParameter("p", "a2");
458    Child child = (Child) q.getResultList().get(0);
459    assertEquals(childClass, child.getClass());
460    assertEquals("a2", child.getAString());
461    assertEquals("b2", child.getBString());
462
463    q = em.createQuery("select from " + childClass.getName() + " b where bString = :p");
464    q.setParameter("p", "b2");
465    child = (Child) q.getSingleResult();
466    assertEquals(childClass, child.getClass());
467    assertEquals("a2", child.getAString());
468    assertEquals("b2", child.getBString());
469
470    List<Child> kids = ((List<Child>) em.createQuery(
471        "select from " + childClass.getName() + " b where aString = 'a2' order by bString desc").getResultList());
472    assertEquals(3, kids.size());
473    assertEquals(e2.getKey().getId(), kids.get(0).getId().longValue());
474    assertEquals(e3.getKey().getId(), kids.get(1).getId().longValue());
475    assertEquals(e1.getKey().getId(), kids.get(2).getId().longValue());
476
477    kids = ((List<Child>) em.createQuery(
478        "select from " + childClass.getName() + " b where aString = 'a2' order by aString desc").getResultList());
479    assertEquals(3, kids.size());
480    assertEquals(e1.getKey().getId(), kids.get(0).getId().longValue());
481    assertEquals(e2.getKey().getId(), kids.get(1).getId().longValue());
482    assertEquals(e3.getKey().getId(), kids.get(2).getId().longValue());
483
484    q = em.createQuery("select bString, aString from " + childClass.getName() + " b where bString = :p");
485    q.setParameter("p", "b2");
486    Object[] result = (Object[]) q.getSingleResult();
487    assertEquals(2, result.length);
488    assertEquals("b2", result[0]);
489    assertEquals("a2", result[1]);
490
491    commitTxn();
492  }
493
494  private void testQueryGrandchild(Class<? extends Grandchild> grandchildClass) {
495    Entity e1 = new Entity(kindForClass(grandchildClass));
496    e1.setProperty("aString", "a2");
497    e1.setProperty("bString", "b1");
498    e1.setProperty("cString", "c2");
499    ds.put(e1);
500
501    Entity e2 = new Entity(kindForClass(grandchildClass));
502    e2.setProperty("aString", "a2");
503    e2.setProperty("bString", "b3");
504    e2.setProperty("cString", "c3");
505    ds.put(e2);
506
507    Entity e3 = new Entity(kindForClass(grandchildClass));
508    e3.setProperty("aString", "a2");
509    e3.setProperty("bString", "b2");
510    e3.setProperty("cString", "c3");
511    ds.put(e3);
512
513    beginTxn();
514    Query q = em.createQuery(
515        "select from " + grandchildClass.getName() + " b where aString = :p");
516    q.setParameter("p", "a2");
517    Grandchild grandchild = (Grandchild) q.getResultList().get(0);
518
519    assertEquals(grandchildClass, grandchild.getClass());
520    assertEquals("a2", grandchild.getAString());
521    assertEquals("b1", grandchild.getBString());
522    assertEquals("c2", grandchild.getCString());
523
524    q = em.createQuery(
525        "select from " + grandchildClass.getName() + " b where bString = :p");
526    q.setParameter("p", "b2");
527    grandchild = (Grandchild) q.getSingleResult();
528
529    assertEquals(grandchildClass, grandchild.getClass());
530    assertEquals("a2", grandchild.getAString());
531    assertEquals("b2", grandchild.getBString());
532    assertEquals("c3", grandchild.getCString());
533
534    q = em.createQuery(
535        "select from " + grandchildClass.getName() + " b where cString = :p");
536    q.setParameter("p", "c2");
537    grandchild = (Grandchild) q.getSingleResult();
538
539    assertEquals(grandchildClass, grandchild.getClass());
540    assertEquals("a2", grandchild.getAString());
541    assertEquals("b1", grandchild.getBString());
542    assertEquals("c2", grandchild.getCString());
543
544    List<Grandchild> grandkids = ((List<Grandchild>) em.createQuery(
545        "select from " + grandchildClass.getName() + " b where aString = 'a2' order by bString desc").getResultList());
546    assertEquals(3, grandkids.size());
547    assertEquals(e2.getKey().getId(), grandkids.get(0).getId().longValue());
548    assertEquals(e3.getKey().getId(), grandkids.get(1).getId().longValue());
549    assertEquals(e1.getKey().getId(), grandkids.get(2).getId().longValue());
550
551    grandkids = ((List<Grandchild>) em.createQuery(
552        "select from " + grandchildClass.getName() + " b where aString = 'a2' order by aString desc").getResultList());
553    assertEquals(3, grandkids.size());
554    assertEquals(e1.getKey().getId(), grandkids.get(0).getId().longValue());
555    assertEquals(e2.getKey().getId(), grandkids.get(1).getId().longValue());
556    assertEquals(e3.getKey().getId(), grandkids.get(2).getId().longValue());
557
558    grandkids = ((List<Grandchild>) em.createQuery(
559        "select from " + grandchildClass.getName() + " b where aString = 'a2' order by cString desc").getResultList());
560    assertEquals(3, grandkids.size());
561    assertEquals(e2.getKey().getId(), grandkids.get(0).getId().longValue());
562    assertEquals(e3.getKey().getId(), grandkids.get(1).getId().longValue());
563    assertEquals(e1.getKey().getId(), grandkids.get(2).getId().longValue());
564
565    q = em.createQuery("select bString, aString, cString from " + grandchildClass.getName() + " b where cString = :p");
566    q.setParameter("p", "c2");
567    Object[] result = (Object[]) q.getSingleResult();
568    assertEquals(3, result.length);
569    assertEquals("b1", result[0]);
570    assertEquals("a2", result[1]);
571    assertEquals("c2", result[2]);
572
573    commitTxn();
574  }
575
576  private void testDeleteParent(Class<? extends Parent> parentClass) {
577    Entity e = new Entity(kindForClass(parentClass));
578    e.setProperty("aString", "a");
579    ds.put(e);
580
581    beginTxn();
582    Parent parent = em.find(parentClass, e.getKey());
583    em.remove(parent);
584    commitTxn();
585    try {
586      ds.get(e.getKey());
587      fail("expected exception");
588    } catch (EntityNotFoundException e1) {
589      // good
590    }
591  }
592
593  private void testDeleteChild(Class<? extends Child> childClass) {
594    Entity e = new Entity(kindForClass(childClass));
595    e.setProperty("aString", "a");
596    e.setProperty("bString", "b");
597    ds.put(e);
598
599    beginTxn();
600    Child child = em.find(childClass, e.getKey());
601    em.remove(child);
602    commitTxn();
603    try {
604      ds.get(e.getKey());
605      fail("expected exception");
606    } catch (EntityNotFoundException e1) {
607      // good
608    }
609  }
610
611  private void testDeleteGrandchild(Class<? extends Grandchild> grandchildClass) {
612    Entity e = new Entity(kindForClass(grandchildClass));
613    e.setProperty("aString", "a");
614    e.setProperty("bString", "b");
615    e.setProperty("cString", "c");
616    ds.put(e);
617
618    beginTxn();
619    Child child = em.find(grandchildClass, e.getKey());
620    em.remove(child);
621    commitTxn();
622    try {
623      ds.get(e.getKey());
624      fail("expected exception");
625    } catch (EntityNotFoundException e1) {
626      // good
627    }
628  }
629
630  private void testUpdateParent(Class<? extends Parent> parentClass) throws Exception {
631    Entity e = new Entity(kindForClass(parentClass));
632    e.setProperty("aString", "a");
633    ds.put(e);
634
635    beginTxn();
636    Parent parent = em.find(parentClass, e.getKey());
637    parent.setAString("not a");
638    commitTxn();
639    e = ds.get(e.getKey());
640    assertEquals("not a", e.getProperty("aString"));
641  }
642
643  private void testUpdateChild(Class<? extends Child> childClass) throws Exception {
644    Entity e = new Entity(kindForClass(childClass));
645    e.setProperty("aString", "a");
646    e.setProperty("bString", "b");
647    ds.put(e);
648
649    beginTxn();
650    Child child = em.find(childClass, e.getKey());
651    child.setAString("not a");
652    child.setBString("not b");
653    commitTxn();
654    e = ds.get(e.getKey());
655    assertEquals("not a", e.getProperty("aString"));
656    assertEquals("not b", e.getProperty("bString"));
657  }
658
659  private void testUpdateGrandchild(Class<? extends Grandchild> grandchildClass) throws Exception {
660    Entity e = new Entity(kindForClass(grandchildClass));
661    e.setProperty("aString", "a");
662    e.setProperty("bString", "b");
663    ds.put(e);
664
665    beginTxn();
666    Grandchild grandchild = em.find(grandchildClass, e.getKey());
667    grandchild.setAString("not a");
668    grandchild.setBString("not b");
669    grandchild.setCString("not c");
670    commitTxn();
671    e = ds.get(e.getKey());
672    assertEquals("not a", e.getProperty("aString"));
673    assertEquals("not b", e.getProperty("bString"));
674    assertEquals("not c", e.getProperty("cString"));
675  }
676
677  private void testGrandchild(Grandchild grandchild) throws Exception {
678    testInsertGrandchild(grandchild);
679    testUpdateGrandchild(grandchild.getClass());
680    testDeleteGrandchild(grandchild.getClass());
681    testFetchGrandchild(grandchild.getClass());
682    testQueryGrandchild(grandchild.getClass());
683  }
684
685  private void testChild(Child child, String discriminator) throws Exception {
686    testInsertChild(child);
687    testUpdateChild(child.getClass());
688    testDeleteChild(child.getClass());
689    testFetchChild(child.getClass());
690    testQueryChild(child.getClass(), discriminator);
691  }
692
693  private void testParent(Parent parent, String discriminator) throws Exception {
694    testInsertParent(parent);
695    testUpdateParent(parent.getClass());
696    testDeleteParent(parent.getClass());
697    testFetchParent(parent.getClass());
698    testQueryParent(parent.getClass(), discriminator);
699  }
700}