Package com.google.appengine.datanucleus.jpa

Source Code of com.google.appengine.datanucleus.jpa.JPAVersionTest

/*
* Copyright (C) 2010 Google Inc
*
* Licensed 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 com.google.appengine.datanucleus.jpa;

import java.sql.Timestamp;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.datanucleus.test.jpa.BaseVersionSubclass;
import com.google.appengine.datanucleus.test.jpa.HasIntVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasIntegerVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasLongVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasPrimitiveLongVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasPrimitiveShortVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasShortVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasTimestampVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasVersionJPA;
import com.google.appengine.datanucleus.test.jpa.HasVersionMain;
import com.google.appengine.datanucleus.test.jpa.HasVersionSub;

import javax.jdo.JDOHelper;
import javax.persistence.EntityManager;
import javax.persistence.OptimisticLockException;
import javax.persistence.RollbackException;

import org.datanucleus.util.NucleusLogger;

import junit.framework.Assert;

/**
* @author Max Ross <max.ross@gmail.com>
*/
public class JPAVersionTest extends JPATestCase {
  private static final String DEFAULT_VERSION_PROPERTY_NAME = "VERSION";

  public void testVersionInsert() throws EntityNotFoundException {
    testVersionInsert(new HasLongVersionJPA());
    testVersionInsert(new HasPrimitiveLongVersionJPA());
    testVersionInsert(new HasIntVersionJPA());
    testVersionInsert(new HasIntegerVersionJPA());
    testVersionInsert(new HasShortVersionJPA());
    testVersionInsert(new HasPrimitiveShortVersionJPA());
  }

  private void testVersionInsert(HasVersionJPA hv) throws EntityNotFoundException {
    beginTxn();
    hv.setValue("yarg");
    em.persist(hv);
    commitTxn();
    assertEquals(1L, hv.getVersion().longValue());

    Entity entity = ds.get(
        KeyFactory.createKey(hv.getClass().getSimpleName(), hv.getId()));
    assertNotNull(entity);
    assertEquals(1L, entity.getProperty(DEFAULT_VERSION_PROPERTY_NAME));
  }

  public void testOptimisticLocking_DeleteAlreadyDeleted() {
    testOptimisticLocking_DeleteAlreadyDeleted(HasLongVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyDeleted(HasPrimitiveLongVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyDeleted(HasIntVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyDeleted(HasIntegerVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyDeleted(HasShortVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyDeleted(HasPrimitiveShortVersionJPA.class);
  }

  private void testOptimisticLocking_DeleteAlreadyDeleted(Class<? extends HasVersionJPA> clazz) {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed);
    Entity entity = new Entity(clazz.getSimpleName());
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 1L);
    Key key = ds.put(entity);

    String keyStr = KeyFactory.keyToString(key);
    beginTxn();
    HasVersionJPA hv = em.find(clazz, keyStr);

    // delete the entity in the datastore right before we commit
    ds.delete(key);
    em.remove(hv);
    try {
      commitTxn();
      fail("expected optimistic exception");
    } catch (RollbackException re) {
      // good
      assertTrue(re.getCause() instanceof OptimisticLockException);
    }
    // make sure the version didn't change on the model object
    assertEquals(1L, JDOHelper.getVersion(hv));
  }

  public void testOptimisticLocking_DeleteAlreadyUpdated() {
    testOptimisticLocking_DeleteAlreadyUpdated(HasLongVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyUpdated(HasPrimitiveLongVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyUpdated(HasIntVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyUpdated(HasIntegerVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyUpdated(HasShortVersionJPA.class);
    testOptimisticLocking_DeleteAlreadyUpdated(HasPrimitiveShortVersionJPA.class);
  }

  private void testOptimisticLocking_DeleteAlreadyUpdated(Class<? extends HasVersionJPA> clazz) {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed);
    Entity entity = new Entity(clazz.getSimpleName());
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 1L);
    Key key = ds.put(entity);

    String keyStr = KeyFactory.keyToString(key);
    beginTxn();
    HasVersionJPA hv = em.find(clazz, keyStr);

    hv.setValue("value");
    commitTxn();
    assertEquals(2L, hv.getVersion().longValue());
    // make sure the version gets bumped
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 3L);

    beginTxn();
    hv = em.find(clazz, keyStr);
    // we update the entity directly in the datastore right before commit
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 7L);
    em.remove(hv);
    ds.put(entity);
    try {
      commitTxn();
      fail("expected optimistic exception");
    } catch (RollbackException re) {
      // good
      assertTrue(re.getCause() instanceof OptimisticLockException);
    }
    // make sure the version didn't change on the model object
    assertEquals(2L, JDOHelper.getVersion(hv));
  }

  public void testOptimisticLocking_UpdateAlreadyDeleted() {
    testOptimisticLocking_UpdateAlreadyDeleted(HasLongVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyDeleted(HasPrimitiveLongVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyDeleted(HasIntVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyDeleted(HasIntegerVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyDeleted(HasShortVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyDeleted(HasPrimitiveShortVersionJPA.class);
  }

  private void testOptimisticLocking_UpdateAlreadyDeleted(Class<? extends HasVersionJPA> clazz) {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed);
    Entity entity = new Entity(clazz.getSimpleName());
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 1L);
    Key key = ds.put(entity);

    String keyStr = KeyFactory.keyToString(key);
    beginTxn();
    HasVersionJPA hv = em.find(clazz, keyStr);

    // delete the entity in the datastore right before we commit
    ds.delete(key);
    hv.setValue("value");
    try {
      commitTxn();
      fail("expected optimistic exception");
    } catch (RollbackException re) {
      // good
      assertTrue(re.getCause() instanceof OptimisticLockException);
    }
    // make sure the version didn't change on the model object
    assertEquals(1L, JDOHelper.getVersion(hv));
  }

  public void testOptimisticLocking_Merge() {
    testOptimisticLocking_Merge(HasLongVersionJPA.class);
    testOptimisticLocking_Merge(HasPrimitiveLongVersionJPA.class);
    testOptimisticLocking_Merge(HasIntVersionJPA.class);
    testOptimisticLocking_Merge(HasIntegerVersionJPA.class);
    testOptimisticLocking_Merge(HasShortVersionJPA.class);
    testOptimisticLocking_Merge(HasPrimitiveShortVersionJPA.class);
  }

  private void testOptimisticLocking_Merge(Class<? extends HasVersionJPA> clazz) {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed);
    Entity entity = new Entity(clazz.getSimpleName());
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 1L);
    Key key = ds.put(entity);

    String keyStr = KeyFactory.keyToString(key);
    beginTxn();
    HasVersionJPA hv = em.find(clazz, keyStr);
    hv.setValue("value");
    commitTxn();
    assertEquals(2L, hv.getVersion().longValue());
    // make sure the version gets bumped
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 3L);

    beginTxn();
    // we update the entity directly in the datastore right before commit
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 7L);
    ds.put(entity);
    hv.setValue("another value");
    em.merge(hv);
    try {
      commitTxn();
      fail("expected optimistic exception");
    } catch (RollbackException re) {
      // good
      assertTrue(re.getCause() instanceof OptimisticLockException);
    }
    // make sure the version didn't change on the model object
    assertEquals(2L, JDOHelper.getVersion(hv));
  }

  public void testOptimisticLocking_UpdateAlreadyUpdated() {
    testOptimisticLocking_UpdateAlreadyUpdated(HasLongVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyUpdated(HasPrimitiveLongVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyUpdated(HasIntVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyUpdated(HasIntegerVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyUpdated(HasShortVersionJPA.class);
    testOptimisticLocking_UpdateAlreadyUpdated(HasPrimitiveShortVersionJPA.class);
  }

  private void testOptimisticLocking_UpdateAlreadyUpdated(Class<? extends HasVersionJPA> clazz) {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_not_allowed);
    Entity entity = new Entity(clazz.getSimpleName());
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 1L);
    Key key = ds.put(entity);

    String keyStr = KeyFactory.keyToString(key);
    beginTxn();
    HasVersionJPA hv = em.find(clazz, keyStr);
    hv.setValue("value");
    commitTxn();
    assertEquals(2L, hv.getVersion().longValue());

    beginTxn();
    hv = em.find(clazz, keyStr);
    hv.setValue("a different value");
    commitTxn();
    assertEquals(3L, hv.getVersion().longValue());

    // make sure the version gets bumped
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 4L);

    beginTxn();
    hv = em.find(clazz, keyStr);
    hv.setValue("another value");
    // we update the entity directly in the datastore right before commit
    entity.setProperty(DEFAULT_VERSION_PROPERTY_NAME, 7L);
    ds.put(entity);
    try {
      commitTxn();
      fail("expected optimistic exception");
    } catch (RollbackException re) {
      // good
      assertTrue(re.getCause() instanceof OptimisticLockException);
    }
    // make sure the version didn't change on the model object
    assertEquals(3L, JDOHelper.getVersion(hv));
  }

  public void testVersionIncrement() {
    HasIntegerVersionJPA hv = new HasIntegerVersionJPA();
    beginTxn();
    hv.setValue("value");
    em.persist(hv);
    commitTxn();
    assertEquals(1L, hv.getVersion().longValue());
    beginTxn();
    hv = em.find(hv.getClass(), hv.getId());
    hv.setValue("another value");
    commitTxn();
    assertEquals(2, hv.getVersion().longValue());
    beginTxn();
    hv.setValue("yet another value");
    hv = em.merge(hv);
    commitTxn();
    assertEquals(3, hv.getVersion().longValue());
  }

  public void testVersionIncrement_NoTxn() {
    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
    HasIntegerVersionJPA hv = new HasIntegerVersionJPA();
    hv.setValue("value");
    em.persist(hv);
    em.close();
    assertEquals(1L, hv.getVersion().longValue());
    em = emf.createEntityManager();
    hv = em.find(hv.getClass(), hv.getId());
    hv.setValue("another value");
    em.close();
    assertEquals(2, hv.getVersion().longValue());
    em = emf.createEntityManager();
    hv.setValue("yet another value");
    hv = em.merge(hv);
    em.close();
    assertEquals(3, hv.getVersion().longValue());
  }


  public void testVersionInheritance() {
    BaseVersionSubclass base = new BaseVersionSubclass(1, "First");
    beginTxn();
    em.persist(base);
    commitTxn();
    assertEquals(1, base.getVersion());

    beginTxn();
    base.setName("Second");
    commitTxn();
    assertEquals(2, base.getVersion());

    em.close();
  }

  /**
   * Tests the use of a java.sql.Timestamp field for versioning.
   */
  public void testTimestampVersion() {
    beginTxn();
    HasTimestampVersionJPA tv = new HasTimestampVersionJPA();
    tv.setValue("First Value");
    em.persist(tv);
    commitTxn();
    Timestamp firstVersion = tv.getVersion();
    Assert.assertNotNull(firstVersion);

    beginTxn();
    tv.setValue("Second Value");
    commitTxn();
    Timestamp secondVersion = tv.getVersion();
    Assert.assertNotNull(secondVersion);
    long firstMillis = firstVersion.getTime();
    long secondMillis = secondVersion.getTime();
    Assert.assertTrue(secondMillis > firstMillis);
  }

  public void testParentChildWithVersion() {

    Key mainKey = KeyFactory.createKey(HasVersionMain.class.getSimpleName(), 1);

    // Persist a Main
    em.getTransaction().begin();
    HasVersionMain m = new HasVersionMain(mainKey);
    em.persist(m);
    em.getTransaction().commit();
    em.close();

    // Add a Sub to the Main
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    HasVersionMain main = em.find(HasVersionMain.class, mainKey);
    HasVersionSub s = new HasVersionSub();
    s.setKey(mainKey, "Init db #0");
    main.getSubs().add(s);
    em.getTransaction().commit();
    em.close();

    // Get and detach Main (1)
    em = emf.createEntityManager();
    em.getTransaction().begin();
    HasVersionMain m1 = em.find(HasVersionMain.class, mainKey);
    m1.getSubs(); // Make sure subs are loaded
    HasVersionSub s1 = m1.getSubs().get(0);
    s1.getValue(); s1.getVersion();
    assertNotNull("Version on element is null", JDOHelper.getVersion(s1));
    em.getTransaction().commit();
    em.close();

    // Get and detach Main (2)
    em = emf.createEntityManager();
    em.getTransaction().begin();
    HasVersionMain m2 = em.find(HasVersionMain.class, mainKey);
    m2.getSubs(); // Make sure subs are loaded
    HasVersionSub s2 = m2.getSubs().get(0);
    s2.getValue(); s2.getVersion();
    assertNotNull("Version on element is null", JDOHelper.getVersion(s2));
    em.getTransaction().commit();
    em.close();

    // Update both detached objects
    s1.incValue(2);
    s2.incValue(3);

    // Merge m1
    em = emf.createEntityManager();
    em.getTransaction().begin();
    em.merge(m1);
    em.getTransaction().commit();
    em.close();

    // Merge m2
    em = emf.createEntityManager();
    try {
      em.getTransaction().begin();
      em.merge(m2);
      em.flush();
      em.getTransaction().commit();
      fail("Should have thrown OptimisticLockException on merge but didnt");
    } catch (OptimisticLockException ole) {
      NucleusLogger.GENERAL.info(">> Exception thrown on merge", ole);
    } finally {
      if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
      }
      em.close();
    }
  }
}
TOP

Related Classes of com.google.appengine.datanucleus.jpa.JPAVersionTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.