/**

  * 更新処理

  * @param product

  */

 public void update(Product product) throws EntityNotFoundException {

 

  // Low-level Datastore API

  DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

  Transaction tx = null;

  EntityConverter entityConverter = new EntityConverter();

  FieldMapper fieldMapper = new FieldMapper();

  int NUM_RETRIES = 3;

 

  try {

   KeyUtils keyUtils = new KeyUtils(BASE_KIND_CLASS);

 

   for (int r = 0; r < NUM_RETRIES; r++) {

    try {

     tx = datastore.beginTransaction();

     logger.info("tx begin.");

 

     if (product != null) {

      Key parentKey = keyUtils.getBaseKeyBuilder().getKey();

      Key currentKey = keyUtils.getChildKey(RECORD_KIND_CLASS, product.getOriginalKey());

      Entity entity = datastore.get(tx, currentKey);

      Product current = (Product)new EntityConverter().convert(RECORD_KIND_CLASS, entity);

 

      // 業務アプリによる楽観的ロック

      if (!current.getRevision().equals(product.getRevision())) {

       throw new ConcurrentModificationException();

 

      // 削除済データ

      } else if (!"".equals(current.getDeleted())) {

       throw new EntityNotFoundException(currentKey);

 

      } else {

       // Revision1上げ、登録

       Product target = new Product();

 

       // 更新があるものだけをセット

       fieldMapper.setValue(current, target); // Persistent項目のみ

       fieldMapper.setValue(product, target); // Persistent項目のみ

       target.setId(current.getId());

 

       // 更新カウントアップ

       target.setRevision(target.getRevision() + 1);

       // キーの設定

       target.updateKeyItem();

 

       String currentTime = getCurrentTime();

       target.setUpdated(currentTime);

       datastore.put(tx, entityConverter.generate(

target, keyUtils.getKeyName(target.getOriginalKey()), parentKey));

 

       // 以前のものは削除し、履歴として残す

       current.setDeleted(currentTime);

       datastore.put(tx, entityConverter.generate(

current, keyUtils.getKeyName(current.getOriginalKey()), parentKey));

      }

     }

 

     logger.info("commit.");

     tx.commit();

     break;

 

    } catch (DatastoreTimeoutException e) {

     logger.info("DatastoreTimeoutException:"+e.getMessage());

     if (r == (NUM_RETRIES - 1)) {

      throw e;

     }

     logger.info("rollbacked.");

     try {

      tx.rollback();

     } catch (Throwable ee) {}

    } catch (IllegalStateException e) { 

// トランザクションのコミットやロール バックがすでに行われている場合、

// またはコミットやロール バックの試行に失敗している場合。

     logger.info("IllegalStateException:"+e.getMessage());

     throw e;

    } catch (DatastoreFailureException e) { 

// データベース エラーが発生する場合に発生。再試行しない。

     logger.info("DatastoreFailureException:"+e.getMessage());

     throw e;

    } catch (ConcurrentModificationException e) {

     logger.info("ConcurrentModificationException:"+e.getMessage());

     throw e;

    }

   } // for loop

 

  } finally {

   if (tx.isActive()) {

    logger.info("rollbacked.");

    try {

     tx.rollback();

    } catch (Throwable e) {}

   }

  }