I need to create a entity that can be locked which stores an
incrementor given to another business logic object a unique id.  I am
using vanilla GAE so I don't have JPA or JDO and need to implement
this with standard GAE DatastoreService logic.

Here is my first attempt at the logic

public static final String PHOTO_COLLECTION_UNIQUE_ID_GENERATOR_NAME =
"photoCollection";
private static final Key key =
KeyFactory.createKey(UniqueIdGenerator.class.getName(),
PHOTO_COLLECTION_UNIQUE_ID_GENERATOR_NAME);
        private static final String NEXT_ID_PROPERTY_KEY = "nextId";

        public long fetchNextPhotoCollectionId(){
                long nextId;
                Entity collectionUniqueIdGenerator = null;
                Transaction txn = _datastore.beginTransaction();
                try {

                        try {
                                collectionUniqueIdGenerator = 
_datastore.get(key);
                        } catch (EntityNotFoundException e) {
                                collectionUniqueIdGenerator = new Entity(key);
                                
collectionUniqueIdGenerator.setProperty(NEXT_ID_PROPERTY_KEY, 1L);
                                _datastore.put(collectionUniqueIdGenerator);
                        }
                        nextId =
(Long)collectionUniqueIdGenerator.getProperty(NEXT_ID_PROPERTY_KEY);
                        
collectionUniqueIdGenerator.setProperty(NEXT_ID_PROPERTY_KEY,
nextId + 1L);
                        _datastore.put(collectionUniqueIdGenerator);
                } finally {
                    if (txn.isActive()) {
                        txn.commit();
                    }
                }
                return nextId;
        }


The method is done withing a transaction and bootstraps the entity if
it does not yet exist.  If it does the current value is returned and
the incremented value is stored for the next request.

When I try and test via java Executor's service I get the error

 No API environment is registered for this thread.

Here is my junit code, the problem is when the
testfetchNextPhotoCollectionIdLockingTest method.  Oh I'm using Guice
and passing the DatastoreService in as a constructor parameter instead
of using the factory in the class, but I had the same error when using
the normal factory pattern.

I'd like to test the way of creating unique ids before relying on it.
But, if there is another preferred way to create them I'd like to hear
about it.

public class TestPhotoDAOTest {

        private final LocalServiceTestHelper helper =
                        new LocalServiceTestHelper(new 
LocalDatastoreServiceTestConfig());

        @Before
        public void setUp() {
                helper.setUp();

        }

        @After
        public void tearDown() {
                helper.tearDown();
        }

        /**
         * Testing when no previous PhotoCollection UniqueIDGenerator existed
         */
        @Test
        public void testfetchNextPhotoCollectionIdBootStrapTest(){
                DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
                PhotoDAO testClass = new PhotoDAO(datastore);
                final long nextId  = testClass.fetchNextPhotoCollectionId();
                Assert.assertEquals(1L, nextId);
        }

        /**
         * Testing that the second number generated is two
         */
        @Test
        public void testfetchNextPhotoCollectionIdPreviouslyCreatedTest(){
                DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
                PhotoDAO testClass = new PhotoDAO(datastore);
                testClass.fetchNextPhotoCollectionId();
                final long nextId  = testClass.fetchNextPhotoCollectionId();
                Assert.assertEquals(2L, nextId);
        }

        /**
         * Testing a random number of iteration
         */
        @Test
        public void testfetchNextPhotoCollectionIdRandomIterationTest(){
                DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
                PhotoDAO testClass = new PhotoDAO(datastore);
                final long randomNumber = (long) (1000L * Math.random());

                for( long i = 0; i < randomNumber; i++){
                        testClass.fetchNextPhotoCollectionId();
                }

                final long nextId  = testClass.fetchNextPhotoCollectionId();
                Assert.assertEquals(randomNumber + 1, nextId);
        }


        @Test  //This test is having problems see stack below
        public void testfetchNextPhotoCollectionIdLockingTest() throws
Exception{
                DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
                final PhotoDAO instance = new PhotoDAO(datastore);

                ExecutorService executor = Executors.newFixedThreadPool(1);

                final long longIterationTarget = 10000L;

                FutureTask<Long> future = new FutureTask<Long>(new 
Callable<Long>(){

                        @Override
                        public Long call() throws Exception {
                                final long largeNumber = longIterationTarget;

                                for( long i = 0; i < largeNumber; i++){
                                        instance.fetchNextPhotoCollectionId();
                                }

                                final long nextId  = 
instance.fetchNextPhotoCollectionId();
                                return nextId;
                        }});
                 executor.execute(future);


                final long nextId  = instance.fetchNextPhotoCollectionId();
                Assert.assertEquals(1L, nextId);

                while( !future.isDone() ){
                        Thread.sleep(100L);
                }
                final long longRunningId = future.get();
                Assert.assertEquals(longIterationTarget + 1L, longRunningId);
        }
}

here is the stack trace the last test generates

java.util.concurrent.ExecutionException:
java.lang.NullPointerException: No API environment is registered for
this thread.
        at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
        at java.util.concurrent.FutureTask.get(Unknown Source)
        at
org.rwpid.backend.dao.TestPhotoDAOTest.testfetchNextPhotoCollectionIdLockingTest(TestPhotoDAOTest.java:
109)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.junit.runners.model.FrameworkMethod
$1.runReflectiveCall(FrameworkMethod.java:44)
        at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
15)
        at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:
41)
        at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:
20)
        at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:
28)
        at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:
31)
        at
org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:
79)
        at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
71)
        at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
49)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:
50)
        at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:
38)
        at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
467)
        at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
683)
        at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:
390)
        at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:
197)
Caused by: java.lang.NullPointerException: No API environment is
registered for this thread.
        at
com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:
108)
        at
com.google.appengine.api.datastore.BaseDatastoreServiceImpl.beginTransactionInternal(BaseDatastoreServiceImpl.java:
123)
        at
com.google.appengine.api.datastore.DatastoreServiceImpl.beginTransaction(DatastoreServiceImpl.java:
227)
        at
com.google.appengine.api.datastore.DatastoreServiceImpl.beginTransaction(DatastoreServiceImpl.java:
222)
        at
org.rwpid.backend.dao.PhotoDAO.fetchNextPhotoCollectionId(PhotoDAO.java:
238)
        at org.rwpid.backend.dao.TestPhotoDAOTest
$1.call(TestPhotoDAOTest.java:94)
        at org.rwpid.backend.dao.TestPhotoDAOTest
$1.call(TestPhotoDAOTest.java:1)
        at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown
Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)






-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to