package com.ciant.techgallery.transaction.idempotency; import static com.googlecode.objectify.ObjectifyService.ofy; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.EntityNotFoundException; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyRange; import com.googlecode.objectify.impl.EntityMetadata; import java.lang.reflect.Method; import java.util.logging.Logger; public class AutoIdempotencyHandler implements IdempotencyHandler { private Key generatedKey; private Object result; private static final Logger LOG = Logger.getLogger(AutoIdempotencyHandler.class.getName()); @SuppressWarnings("unchecked") @Override public boolean shouldTransactionProceed(Object target, Method method, Object[] args) { for (Object arg : args) { try { EntityMetadata<Object> metadata = (EntityMetadata<Object>) ofy().factory().getMetadata(arg.getClass()); DatastoreService dataStoreService = DatastoreServiceFactory.getDatastoreService(); try { Key key = metadata.getKeyMetadata().getRawKey(arg); if (key != null && key.isComplete()) { generatedKey = key; } } catch (IllegalArgumentException iae) { //do nothing. Will be handled after } //havent generated key. First time executing if (generatedKey == null && metadata.getKeyMetadata().isIdGeneratable()) { KeyRange keyRange = dataStoreService.allocateIds(metadata.getKeyMetadata().getKind(), 1); generatedKey = keyRange.getStart(); } else { try { dataStoreService.get(generatedKey); return false; } catch (EntityNotFoundException e) { //do nothing. Should continue } } if (metadata.getKeyMetadata().isIdGeneratable()) { metadata.getKeyMetadata().setLongId(args[0], generatedKey.getId()); } return true; } catch (IllegalArgumentException iae) { continue; } } LOG.warning("Method " + method + " using autoIdempotency but no entity was passed in the parameters. " + "No idempotency check will be applied."); return true; } @Override public void setReturn(Object object) { this.result = object; } @Override public Object getReturn() { return this.result; } }