@Test
  public void testLazyListRetrievalPerformance() throws InterruptedException, ExecutionException {
    EntityManagerSimpleJPA em = (EntityManagerSimpleJPA) factory.createEntityManager();

    Query query;
    List<MyTestObject> obs;

    long start = System.currentTimeMillis();
    int numItems = 120;
    Future future = null;
    for (int i = 0; i < numItems; i++) {
      MyTestObject object = new MyTestObject();
      object.setName("Scooby doo");
      object.setAge(i);
      System.out.println("persisting " + i);
      future = em.persistAsync(object);
    }

    // let them save
    System.out.println("Waiting for all persists to complete.");
    future.get();
    long duration = System.currentTimeMillis() - start;
    printAndLog("duration of persists=" + duration);

    start = System.currentTimeMillis();
    System.out.println("querying for all objects...");
    query = em.createQuery("select o from MyTestObject o ");
    obs = query.getResultList();
    for (MyTestObject ob : obs) {
      System.out.println("ob=" + ob);
    }
    duration = System.currentTimeMillis() - start;
    printAndLog("duration of retreival and prints=" + duration);

    start = System.currentTimeMillis();
    System.out.println("querying for all objects...");
    query = em.createQuery("select o from MyTestObject o ");
    obs = query.getResultList();
    for (MyTestObject ob : obs) {
      System.out.println("ob=" + ob);
    }
    duration = System.currentTimeMillis() - start;
    printAndLog("duration of retreival and prints after first load=" + duration);

    em.close();
  }
  private static QueryImpl oneToManyQuery(
      EntityManagerSimpleJPA em,
      String attName,
      String foreignKeyFieldName,
      Object id,
      Class typeInList,
      List<PersistentProperty.OrderClause> orderBy) {
    if (foreignKeyFieldName == null || foreignKeyFieldName.length() == 0) {
      // use the class containing the OneToMany
      foreignKeyFieldName = attName;
    }
    AnnotationInfo ai = em.getFactory().getAnnotationManager().getAnnotationInfo(typeInList);
    Class refType = ai.getPersistentProperty(foreignKeyFieldName).getPropertyClass();
    AnnotationInfo refAi = em.getAnnotationManager().getAnnotationInfo(refType);
    String query = createOneToManyQuery(typeInList, foreignKeyFieldName, refAi, id, orderBy);

    logger.finer("OneToMany query=" + query);
    return new QueryImpl(em, query);
  }
  public static <T> T buildObject(
      EntityManagerSimpleJPA em, Class<T> tClass, Object id, List<Attribute> atts) {
    T newInstance;
    /*
    Why was this here?  Should we merge if it exists though?
    newInstance = em.cacheGet(tClass, id);
    if (newInstance != null) {
        return newInstance;
    }*/
    AnnotationInfo ai = em.getFactory().getAnnotationManager().getAnnotationInfo(tClass);
    try {
      //            newInstance = tClass.newInstance();
      // check for DTYPE to see if it's a subclass, must be a faster way to do this you'd think?
      for (Attribute att : atts) {
        if (att.getName().equals(EntityManagerFactoryImpl.DTYPE)) {
          logger.finest("dtype=" + att.getValue());
          ai =
              em.getFactory()
                  .getAnnotationManager()
                  .getAnnotationInfoByDiscriminator(att.getValue());
          if (ai == null) {
            throw new PersistenceException(
                new ClassNotFoundException(
                    "Could not build object with dtype = "
                        + att.getValue()
                        + ". Class not found or is not an @Entity."));
          }
          tClass = ai.getMainClass();
          // check cache again with new class
          newInstance = em.cacheGet(tClass, id);
          if (newInstance != null) return newInstance;
          break;
        }
      }
      ObjectWithInterceptor owi = newEnancedInstance(em, tClass);
      newInstance = (T) owi.getBean();
      for (PersistentProperty field : ai.getPersistentProperties()) {
        String attName = field.getFieldName();
        String columnName = field.getColumnName();
        if (field.isForeignKeyRelationship()) {
          // lazy it up
          Set<String> keys = getForeignKeys(em, field, columnName, atts);
          logger.finest("keys=" + keys);
          if (keys == null || keys.isEmpty()) {
            continue;
          }
          // todo: stick a cache in here and check the cache for the instance before creating the
          // lazy loader.
          logger.finest(
              "creating new lazy loading instance for field "
                  + field.getFieldName()
                  + " of class "
                  + tClass.getSimpleName()
                  + " with id "
                  + id);
          //                    Object toSet = newLazyLoadingInstance(retType, keys);
          owi.getInterceptor().putForeignKey(attName, keys);
        } else if (field.isInverseRelationship()) {
          Class typeInList = field.getPropertyClass();
          // todo: should this return null if there are no elements??
          //                    LazyList lazyList = new LazyList(this, newInstance,
          // annotation.mappedBy(), id, typeInList,
          // factory.getAnnotationManager().getAnnotationInfo(typeInList));

          List<PersistentProperty.OrderClause> orderBy = null;
          if (List.class.isAssignableFrom(field.getRawClass())) {
            orderBy = field.getOrderClauses();
          }

          LazyList lazyList =
              new LazyList(
                  em,
                  typeInList,
                  oneToManyQuery(em, attName, field.getMappedBy(), id, typeInList, orderBy));
          //                    Class retType = field.getReturnType();
          // todo: assuming List for now, handle other collection types
          field.setProperty(newInstance, lazyList);
        } else if (field.isLob() || field.isJsonLob()) {
          // handled in Proxy
          String lobKeyAttributeName = field.getColumnName();
          String lobKeyVal = getValueToSet(atts, lobKeyAttributeName, columnName);
          logger.finest(
              "lobkeyval to set on interceptor=" + lobKeyVal + " - fromatt=" + lobKeyAttributeName);
          // TODO add multivalue support for LOB keys
          if (lobKeyVal != null)
            owi.getInterceptor().putForeignKey(attName, Collections.singleton(lobKeyVal));
        } else if (field.getEnumType() != null) {
          String val = getValueToSet(atts, attName, columnName);
          if (val != null) {
            Object enumVal = getEnumValue(field, val);
            field.setProperty(newInstance, enumVal);
          }
        } else if (field.isId()) {
          field.setProperty(newInstance, id);
        } else {
          Collection<String> val = getValuesToSet(atts, attName, columnName);
          if (val != null && !val.isEmpty()) {
            em.setFieldValue(tClass, newInstance, field, val);
          }
        }
      }
    } catch (Exception e) {
      throw new PersistenceException(e);
    }
    em.cachePut(id, newInstance);
    return newInstance;
  }
  @Test
  public void testPutQueryDelete() throws ExecutionException, InterruptedException {
    int numItems = 1;
    String x;
    EntityManagerSimpleJPA em = (EntityManagerSimpleJPA) factory.createEntityManager();
    PerformanceTestObject o = new PerformanceTestObject();
    o.setS1("first to create domain");
    em.persist(o);
    StopWatch stopWatch = new StopWatch();

    String s1a = "attribute1";
    String s2a = "attribute2";
    Future<PerformanceTestObject> lastFuture = null;
    stopWatch.start();
    for (int i = 0; i < numItems; i++) {
      o = new PerformanceTestObject();
      o.setS1(s1a);
      o.setS2(s2a);
      lastFuture = em.persistAsync(o);
    }
    lastFuture.get(); // not 100% accurate, but good enough
    stopWatch.stop();
    System.out.println(
        "puts duration="
            + stopWatch.getTime()
            + ", "
            + em.getTotalOpStats().getPuts()
            + " items put.");

    Thread.sleep(5000);

    stopWatch.reset();
    stopWatch.start();
    Query query = em.createQuery("select o from PerformanceTestObject o");
    List<PerformanceTestObject> resultList = query.getResultList();
    System.out.println("iterating result list...");
    int i = 0;
    for (PerformanceTestObject performanceTestObject : resultList) {

      i++;
      if (i % 100 == 0) {
        System.out.println(i);
      }
    }
    stopWatch.stop();
    System.out.println(
        "query ALL duration="
            + stopWatch.getTime()
            + ", "
            + em.getTotalOpStats().getGets()
            + " items got.");

    stopWatch.reset();
    stopWatch.start();
    System.out.println("Deleting ALL...");
    for (PerformanceTestObject performanceTestObject : resultList) {
      lastFuture = em.removeAsync(o);
    }
    lastFuture.get();
    stopWatch.stop();
    System.out.println(
        "delete duration=" + stopWatch.getTime() + ", " + resultList.size() + " items deleted.");
    System.out.println("sleeping...");
    Thread.sleep(30000);

    em.close();
  }
  @Test
  public void testPuts() {
    EntityManagerSimpleJPA em = (EntityManagerSimpleJPA) factory.createEntityManager();

    MyTestObject object = new MyTestObject();
    object.setName("Scooby doo");
    object.setAge(100);
    Date now = new Date();
    object.setBirthday(now);
    em.persist(object);

    System.out.println(em.getTotalOpStats());
    Assert.assertEquals(1, em.getTotalOpStats().getPuts());

    object.setId(null);
    em.persist(object);
    Assert.assertEquals(2, em.getTotalOpStats().getPuts());

    em.close();

    // New EntityManager and same op
    em = (EntityManagerSimpleJPA) factory.createEntityManager();

    object = new MyTestObject();
    object.setName("Scooby doo");
    object.setAge(100);
    object.setBirthday(now);
    em.persist(object);

    System.out.println(em.getTotalOpStats());
    Assert.assertEquals(1, em.getTotalOpStats().getPuts());
    Assert.assertEquals(3, em.getGlobalOpStats().getPuts());

    em.close();
  }