/**
  * Helper method to unset the specified ShardedEntity from the ShardedEntityContextHolder
  *
  * @param entity the ShardedEntity to unset from the ShardedEntityContextHolder
  * @throws PersistenceException in case the shard hint of specified ShardedEntity does not match
  *     with the value of the entity held by ShardedEntityContextHolder
  */
 private void unsetShardedEntityContextHolder(ShardedEntity entity) throws PersistenceException {
   // unset the ShardedEntity from the ShardedEntityContextHolder if the type is
   // ShardedPersistentEntity. Cleans up the context that was
   // populated earlier using the ShardedEntityContextHolder#setShardedPersistentEntity() call
   ShardedEntity contextEntity = ShardedEntityContextHolder.getShardedEntity();
   if (contextEntity != null
       && !contextEntity.getShardHint().equals(((ShardedEntity) entity).getShardHint())) {
     throw new PersistenceException(
         "Shard hints do not match for the specified ShardedEntity instance and the one held in the context"
             + " Mismatched values are : "
             + contextEntity.getShardHint()
             + ","
             + ((ShardedEntity) entity).getShardHint());
   }
   ShardedEntityContextHolder.clearShardedEntity();
 }
 /**
  * Helper method to set the first of specified Criteria instances into the
  * ShardedEntityContextHolder if it is of type ShardedEntity. Throws an exception if
  * shardedentities are mixed with non-sharded ones in the same call. Also checks to see if all the
  * ShardedEntity instances belong to the same shard i.e. {@link ShardedEntity#getShardHint()}
  * returns the same value. Throws a PersistenceException otherwise. This defensive check is done
  * to avoid indeterministic transaction boundary behavior when shards are mapped to multiple
  * database instances. when shards are mapped to multiple database instances.
  *
  * @param criteria the ShardedEntity instances, the first of which is to be set into the
  *     ShardedEntityContextHolder if it is of type ShardedEntity
  * @throws PersistenceException in case the shard hints of specified ShardedEntity instances do
  *     not match
  */
 private void checkAndPopulateShardedEntityContextHolder(Criteria[] criteria)
     throws PersistenceException {
   if (criteria.length != 0) {
     // check to see if sharded and non-sharded entities are part of the same call
     ShardedEntity shardedEntity = null;
     Criteria nonShardedEntity = null;
     for (Criteria entity : criteria) {
       if (ShardedEntity.class.isAssignableFrom(entity.getClass())) {
         shardedEntity = (ShardedEntity) entity;
       } else {
         nonShardedEntity = entity;
       }
     }
     if (shardedEntity != null && nonShardedEntity != null) {
       throw new PersistenceException(
           "Attempt to use sharded and non-sharded criteria in the same call. "
               + "Mixed types are : "
               + shardedEntity.getClass().getName()
               + ","
               + nonShardedEntity.getClass().getName());
     }
     Criteria firstEntity = criteria[0];
     String shardHint =
         (ShardedEntity.class.isAssignableFrom(firstEntity.getClass()))
             ? ((ShardedEntity) firstEntity).getShardHint()
             : ShardedEntity.DEFAULT_SHARD;
     for (Criteria entity : criteria) {
       if (ShardedEntity.class.isAssignableFrom(entity.getClass())) {
         if (!((ShardedEntity) entity).getShardHint().equals(shardHint)) {
           throw new PersistenceException(
               "Shard hints do not match for the specified Criteria i.e. ShardedEntity instances."
                   + " Mismatched values are : "
                   + shardHint
                   + ","
                   + ((ShardedEntity) entity).getShardHint());
         }
       }
       // Set the PersistentEntity into the ShardedEntityContextHolder if the type is
       // ShardedPersistentEntity. Will be used in Datasource resolution
       if (ShardedEntity.class.isAssignableFrom(firstEntity.getClass())) {
         ShardedEntityContextHolder.setShardedEntity((ShardedEntity) firstEntity);
       }
     }
   }
 }