Package org.hivedb.hibernate

Source Code of org.hivedb.hibernate.BaseDataAccessObject

package org.hivedb.hibernate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.*;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hivedb.Hive;
import org.hivedb.HiveLockableException;
import org.hivedb.HiveRuntimeException;
import org.hivedb.annotations.AnnotationHelper;
import org.hivedb.annotations.DataIndexDelegate;
import org.hivedb.annotations.IndexType;
import org.hivedb.configuration.EntityConfig;
import org.hivedb.configuration.EntityIndexConfig;
import org.hivedb.configuration.EntityIndexConfigDelegator;
import org.hivedb.configuration.EntityIndexConfigImpl;
import org.hivedb.util.Lists;
import org.hivedb.util.classgen.GenerateInstance;
import org.hivedb.util.classgen.GeneratedClassFactory;
import org.hivedb.util.classgen.GeneratedInstanceInterceptor;
import org.hivedb.util.classgen.ReflectionTools;
import org.hivedb.util.functional.*;
import org.hivedb.util.functional.Filter;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;

public class BaseDataAccessObject implements DataAccessObject<Object, Serializable> {
  private final Log log = LogFactory.getLog(BaseDataAccessObject.class);
  private static int CHUNK_SIZE = 10;
  private final HiveSessionFactory factory;
  private final EntityConfig config;
  private final Class<?> clazz;
  private Hive hive;
  private EntityIndexConfig partitionIndexEntityIndexConfig;

  public Hive getHive() {
    return hive;
  }

  public void setHive(Hive hive) {
    this.hive = hive;
  }

  public BaseDataAccessObject(EntityConfig config, Hive hive, HiveSessionFactory factory) {
    this.clazz = config.getRepresentedInterface();
    this.config = config;
    this.factory = factory;
    this.hive = hive;

  }


  public Boolean exists(Serializable id) {
    return hive.directory().doesResourceIdExist(config.getResourceName(), id);
  }

  public Object get(final Serializable id) {
    try {
      QueryCallback query = new QueryCallback() {
        public Collection<Object> execute(Session session) {
          Object fetched = get(id, session);
          if (fetched == null && exists(id)) {
            try {
              hive.directory().deleteResourceId(config.getResourceName(), id);
            } catch (HiveLockableException e) {
              log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Unable to cleanup record because Hive was read-only.", config.getResourceName(), id));
            }
            log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Directory record removed.", config.getResourceName(), id));
          }
          return Collections.singletonList(fetched);
        }
      };
      Object fetched = Atom.getFirstOrThrow(queryInTransaction(query, getSession()));
      if (fetched == null && exists(id)) {
        try {
          hive.directory().deleteResourceId(config.getResourceName(), id);
        } catch (HiveLockableException e) {
          log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Unable to cleanup record because Hive was read-only.", config.getResourceName(), id));
        }
        log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Directory record removed.", config.getResourceName(), id));
      }
      return fetched;
    } catch (NoSuchElementException e) {
      //TODO previous code may make this logic irrelevant
      //This save us a directory hit for all cases except when requesting a non-existent id.
      if (!exists(id))
        return null;
      else
        throw e;
    }
  }

  public Collection<Object> getPropertyValue(final String propertyName, final int firstResult, final int maxResults) {
    QueryCallback callback = new QueryCallback() {
      @SuppressWarnings("unchecked")
      public Collection<Object> execute(Session session) {
        Query query =
            session.createQuery(
                String.format(
                    "select %s from %s",
                    propertyName,
                    GeneratedClassFactory.getGeneratedClass(config.getRepresentedInterface()).getSimpleName()));
        if (maxResults > 0) {
          query.setFirstResult(firstResult);
          query.setMaxResults(maxResults);
        }
        return query.list();
      }
    };
    return queryInTransaction(callback, getSession());
  }

  public Collection<Object> findByProperty(final String propertyName, final Object propertyValue) {
    return findByProperties(propertyName, Collections.singletonMap(propertyName, propertyValue));
  }

  public Collection<Object> findByProperty(final String propertyName, final Object propertyValue, final Integer firstResult, final Integer maxResults) {
    return findByProperties(propertyName, Collections.singletonMap(propertyName, propertyValue), firstResult, maxResults);
  }

  public Collection<Object> findByProperties(String partitioningPropertyName, final Map<String, Object> propertyNameValueMap) {
    return findByProperties(partitioningPropertyName, propertyNameValueMap, 0, 0);
  }

  public Collection<Object> findByProperties(String partitioningPropertyName, final Map<String, Object> propertyNameValueMap, final Integer firstResult, final Integer maxResults) {
    return queryByProperties(partitioningPropertyName, propertyNameValueMap, firstResult, maxResults, false);
  }

  public Integer getCount(final String propertyName, final Object propertyValue) {
    return (Integer) sumCounts(queryByProperties(propertyName, Collections.singletonMap(propertyName, propertyValue), 0, 0, true));
  }

  public Integer getCountByProperties(String partitioningPropertyName, Map<String, Object> propertyNameValueMap) {
    return (Integer) sumCounts(queryByProperties(partitioningPropertyName, propertyNameValueMap, 0, 0, true));
  }

  public Integer getCountByProperties(String partitioningPropertyName, Map<String, Object> propertyNameValueMap, Integer firstResult, Integer maxResults) {
    return (Integer) sumCounts(queryByProperties(partitioningPropertyName, propertyNameValueMap, firstResult, maxResults, true));
  }

  private Integer sumCounts(Collection<Object> objects) {
    int count = 0;
    for (Object object : objects) {
      count += ((Number) object).intValue();
    }
    return count;
  }

  public Collection<Object> findByPropertyRange(final String propertyName, final Object minValue, final Object maxValue) {
    // Use an AllShardsresolutionStrategy + Criteria
    final EntityConfig entityConfig = config;
    final EntityIndexConfig indexConfig = config.getEntityIndexConfig(propertyName);
    Session session = factory.openAllShardsSession();
    QueryCallback callback;
    if (isPrimitiveCollection(propertyName)) {
      callback = new QueryCallback() {
        @SuppressWarnings("unchecked")
        public Collection<Object> execute(Session session) {
          Query query = session.createQuery(String.format("from %s as x where x.%s between (:minValue, :maxValue)",
              entityConfig.getRepresentedInterface().getSimpleName(),
              indexConfig.getIndexName())
          ).setEntity("minValue", minValue).setEntity("maxValue", maxValue);
          return query.list();
        }
      };
    } else {
      callback = new QueryCallback() {
        @SuppressWarnings("unchecked")
        public Collection<Object> execute(Session session) {
          Criteria criteria = session.createCriteria(config.getRepresentedInterface()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
          addPropertyRangeRestriction(criteria, propertyName, minValue, maxValue);
          return criteria.list();
        }
      };
    }
    return queryInTransaction(callback, session);
  }

  public Integer getCountByRange(final String propertyName, final Object minValue, final Object maxValue) {
    // Use an AllShardsresolutionStrategy + Criteria
    Session session = factory.openAllShardsSession();
    QueryCallback query = new QueryCallback() {
      @SuppressWarnings("unchecked")
      public Collection<Object> execute(Session session) {
        Criteria criteria = session.createCriteria(config.getRepresentedInterface()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        addPropertyRangeRestriction(criteria, propertyName, minValue, maxValue);
        criteria.setProjection(Projections.rowCount());
        return criteria.list();
      }
    };
    return (Integer) Atom.getFirstOrThrow(queryInTransaction(query, session));
  }

  public Collection<Object> findByPropertyRange(final String propertyName, final Object minValue, final Object maxValue, final Integer firstResult, final Integer maxResults) {
    // Use an AllShardsresolutionStrategy + Criteria
    final EntityConfig entityConfig = config;
    final EntityIndexConfig indexConfig = config.getEntityIndexConfig(propertyName);
    Session session = factory.openAllShardsSession();
    QueryCallback callback;
    if (isPrimitiveCollection(propertyName)) {
      callback = new QueryCallback() {
        @SuppressWarnings("unchecked")
        public Collection<Object> execute(Session session) {
          Query query = session.createQuery(String.format("from %s as x where %s between (:minValue, :maxValue) order by x.%s asc limit %s, %s",
              entityConfig.getRepresentedInterface().getSimpleName(),
              indexConfig.getIndexName(),
              entityConfig.getIdPropertyName(),
              firstResult,
              maxResults)
          ).setEntity("minValue", minValue).setEntity("maxValue", maxValue);
          return query.list();
        }
      };
    } else {
      callback = new QueryCallback() {
        @SuppressWarnings("unchecked")
        public Collection<Object> execute(Session session) {
          Criteria criteria = session.createCriteria(config.getRepresentedInterface()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
          addPropertyRangeRestriction(criteria, propertyName, minValue, maxValue);
          criteria.add(Restrictions.between(propertyName, minValue, maxValue));
          criteria.setFirstResult(firstResult);
          criteria.setMaxResults(maxResults);
          criteria.addOrder(Order.asc(propertyName));
          return criteria.list();
        }
      };
    }
    return queryInTransaction(callback, session);
  }

  public Object save(Object entity) {
    final Object populatedEntity = Atom.getFirstOrThrow(populateDataIndexDelegates(Collections.singletonList(entity)));
    SessionCallback callback = new SessionCallback() {
      public void execute(Session session) {
        session.saveOrUpdate(getRespresentedClass().getName(), populatedEntity);
      }
    };

    SessionCallback cleanupCallback = new SessionCallback() {
      public void execute(Session session) {
        session.refresh(populatedEntity);
        session.lock(getRespresentedClass().getName(), populatedEntity, LockMode.UPGRADE);
        session.update(getRespresentedClass().getName(), populatedEntity);
        log.warn(String.format("%s with id %s exists in the data node but not on the directory. Data node record was updated and re-indexed.", config.getResourceName(), config.getId(populatedEntity)));
      }
    };

    if (partionDimensionKeyHasChanged(entity))
      delete(config.getId(entity));
    doSave(populatedEntity, callback, cleanupCallback);
    return entity;
  }

  private boolean partionDimensionKeyHasChanged(Object entity) {
    return hive.directory().doesResourceIdExist(config.getResourceName(), config.getId(entity)) &&
        !config.getPrimaryIndexKey(entity).equals(getHive().directory().getPrimaryIndexKeyOfResourceId(config.getResourceName(), config.getId(entity)));
  }

  public Collection<Object> saveAll(Collection<Object> collection) {
    List<Object> entities = Lists.newList(populateDataIndexDelegates(collection));
    validateNonNull(entities);
    final boolean partitionDimensionKeyHasChanged = partionDimensionKeyHasChanged(Atom.getFirstOrThrow(entities));
    //o large save operations in manageable sized chunks
    for (int chunkId = 0; chunkId < entities.size(); chunkId += BaseDataAccessObject.getSaveChunkSize()) {
      final Collection<Object> chunk =
          entities.subList(
              chunkId,
              chunkId + getSaveChunkSize() <= entities.size() ? chunkId + getSaveChunkSize() : entities.size());

      // If the partition dimension key has changed for any entity we assume that we need
      // to delete all entities before saving, in case the new partition dimension key
      // is on a different node
      if (partitionDimensionKeyHasChanged) {
        SessionCallback callback = new SessionCallback() {
          public void execute(Session session) {
            for (Object entity : chunk) {
              Object deleted = get(config.getId(entity), session);
              session.delete(deleted);
            }
          }
        };
        deleteAll(callback);
      }

      SessionCallback callback = new SessionCallback() {
        public void execute(Session session) {
          for (Object entity : chunk) {
            session.saveOrUpdate(getRespresentedClass().getName(), entity);
          }
        }
      };
      SessionCallback cleanupCallback = new SessionCallback() {
        public void execute(Session session) {
          for (Object entity : chunk) {
            try {
              session.refresh(entity);
            } catch (RuntimeException e) {
              //Damned Hibernate
            }
            if (!exists(config.getId(entity))) {
              if (existsInSession(session, config.getId(entity))) {
                session.lock(getRespresentedClass().getName(), entity, LockMode.UPGRADE);
                session.update(getRespresentedClass().getName(), entity);
                log.warn(String.format("%s with id %s exists in the data node but not on the directory. Data node record was updated and re-indexed.", config.getResourceName(), config.getId(entity)));
              } else {
                session.saveOrUpdate(getRespresentedClass().getName(), entity);
              }
            } else {
              if (!existsInSession(session, config.getId(entity))) {
                try {
                  getHive().directory().deleteResourceId(config.getResourceName(), config.getId(entity));
                } catch (HiveLockableException e) {
                  log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Unable to cleanup record because Hive was read-only.", config.getResourceName(), config.getId(entity)));
                }
                log.warn(String.format("%s with id %s exists in the directory but not on the data node.  Directory record removed.", config.getResourceName(), config.getId(entity)));
              }
              session.saveOrUpdate(getRespresentedClass().getName(), entity);
            }
          }
        }
      };
      doSaveAll(chunk, callback, cleanupCallback);
    }

    return collection;
  }

  public Serializable delete(final Serializable id) {
    SessionCallback callback = new SessionCallback() {
      public void execute(Session session) {
        Object deleted = get(id, session);
        session.delete(deleted);
      }
    };
    doInTransaction(callback, getSession());
    return id;
  }

  private Object get(Serializable id, Session session) {
    return session.get(getRespresentedClass(), id);
  }

  protected Collection<Object> queryByProperties(
      String partitioningPropertyName,
      final Map<String, Object> propertyNameValueMap,
      final Integer firstResult, final Integer maxResults,
      final boolean justCount) {
    final EntityIndexConfig entityIndexConfig = resolveEntityIndexConfig(partitioningPropertyName);
    Session session = createSessionForIndex(config, entityIndexConfig, propertyNameValueMap.get(partitioningPropertyName));

    final Map<String, Entry<EntityIndexConfig, Object>> propertyNameEntityIndexConfigValueMap = createPropertyNameToValueMap(propertyNameValueMap);

    QueryCallback query;

    if (Filter.isMatch(new Predicate<String>() {
      public boolean f(String propertyName) {
        return isPrimitiveCollection(propertyName);
      }
    }, propertyNameEntityIndexConfigValueMap.keySet()))
      query = new QueryCallback() {
        public Collection<Object> execute(Session session) {
          Map<String, Object> revisedPropertyNameValueMap = Transform.toMap(
              new Unary<Entry<String, Entry<EntityIndexConfig, Object>>, String>() {
                public String f(Map.Entry<String, Map.Entry<EntityIndexConfig, Object>> item) {
                  return item.getKey();
                }
              },
              new Unary<Entry<String, Entry<EntityIndexConfig, Object>>, Object>() {
                public Object f(Map.Entry<String, Map.Entry<EntityIndexConfig, Object>> item) {
                  return item.getValue().getValue();
                }
              },
              propertyNameEntityIndexConfigValueMap.entrySet());

          return justCount
              ? queryWithHQLRowCount(session, revisedPropertyNameValueMap, firstResult, maxResults)
              : queryWithHQL(session, revisedPropertyNameValueMap, firstResult, maxResults);
        }
      };
    else
      query = new QueryCallback() {
        @SuppressWarnings("unchecked")
        public Collection<Object> execute(Session session) {
          Criteria criteria = session.createCriteria(config.getRepresentedInterface()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
          for (Entry<EntityIndexConfig, Object> entityIndexConfigValueEntry : propertyNameEntityIndexConfigValueMap.values()) {
            EntityIndexConfig entityIndexConfig = entityIndexConfigValueEntry.getKey();
            Object value = entityIndexConfigValueEntry.getValue();
            addPropertyRestriction(entityIndexConfig, criteria, entityIndexConfig.getPropertyName(), value);
          }
          addPaging(firstResult, maxResults, criteria);
          if (justCount)
            criteria.setProjection(Projections.rowCount());
          return criteria.list();
        }
      };
    return queryInTransaction(query, session);
  }

  private Map<String, Entry<EntityIndexConfig, Object>> createPropertyNameToValueMap(
      final Map<String, Object> propertyNameValueMap) {
    return
        Transform.toOrderedMap(
            new Unary<String, Entry<String, Entry<EntityIndexConfig, Object>>>() {
              public Entry<String, Entry<EntityIndexConfig, Object>> f(String propertyName) {
                EntityIndexConfig entityIndexConfig = resolveEntityIndexConfig(propertyName);
                DataIndexDelegate dataIndexDelegate = AnnotationHelper.getAnnotationDeeply(clazz, propertyName, DataIndexDelegate.class);
                EntityIndexConfig resolvedEntityIndexConfig = (dataIndexDelegate != null)
                    ? resolveEntityIndexConfig(dataIndexDelegate.value())
                    : entityIndexConfig;
                return new Pair<String, Entry<EntityIndexConfig, Object>>(
                    resolvedEntityIndexConfig.getPropertyName(),
                    new Pair<EntityIndexConfig, Object>(resolvedEntityIndexConfig, propertyNameValueMap.get(propertyName)));
              }
            }, propertyNameValueMap.keySet());
  }


  @SuppressWarnings("unchecked")
  protected Collection<Object> queryWithHQL(Session session, Map<String, Object> propertyNameValueMap, Integer firstResult, Integer maxResults) {
    String queryString = createHQLQuery(propertyNameValueMap);
    Query query = session.createQuery(queryString);
    if (maxResults != 0) {
      query.setFirstResult(firstResult);
      query.setMaxResults(maxResults);
    }
    for (Entry<String, Object> entry : propertyNameValueMap.entrySet())
      query.setParameter(entry.getKey(), entry.getValue());
    return query.list();
  }

  @SuppressWarnings("unchecked")
  protected Collection queryWithHQLRowCount(Session session, Map<String, Object> propertyNameValueMap, Integer firstResult, Integer maxResults) {
    String queryString = String.format("select count(%s) %s",
        config.getIdPropertyName(),
        createHQLQuery(propertyNameValueMap));

    Query query = session.createQuery(queryString);
    if (maxResults != 0) {
      query.setFirstResult(firstResult);
      query.setMaxResults(maxResults);
    }
    for (Entry<String, Object> entry : propertyNameValueMap.entrySet())
      query.setParameter(entry.getKey(), entry.getValue());
    return Transform.map(new Unary<Long, Integer>() {
      public Integer f(Long item) {
        return item.intValue();
      }
    }, query.list());
  }

  private String createHQLQuery(Map<String, Object> propertyNameValueMap) {
    return String.format("from %s as x where", GeneratedClassFactory.getGeneratedClass(config.getRepresentedInterface()).getSimpleName())
        + Amass.join(
        new Joiner<Entry<String, Object>, String>() {
          @Override
          public String f(Entry<String, Object> entry, String result) {
            return result + " and " + toHql(entry);
          }
        },
        new Unary<Entry<String, Object>, String>() {
          public String f(Entry<String, Object> entry) {
            return toHql(entry);
          }
        },
        propertyNameValueMap.entrySet());
  }

  private String toHql(Entry<String, Object> entry) {
    String propertyName = entry.getKey();
    if (ReflectionTools.isCollectionProperty(config.getRepresentedInterface(), propertyName))
      return String.format(" :%s in elements (x.%s)", propertyName, propertyName);
    else
      return String.format(" :%s = x.%s", propertyName, propertyName);
  }


  private static int getSaveChunkSize() {
    return BaseDataAccessObject.CHUNK_SIZE;
  }

  public synchronized static void setSaveChunkSize(int size) {
    BaseDataAccessObject.CHUNK_SIZE = size;
  }

  @SuppressWarnings("unchecked")
  public Class<Object> getRespresentedClass() {
    return (Class<Object>) EntityResolver.getPersistedImplementation(clazz);
  }

  public static void doInTransaction(SessionCallback callback, Session session) {
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      callback.execute(session);
      tx.commit();
    } catch (RuntimeException e) {
      LogFactory.getLog(BaseDataAccessObject.class).error("doInTransaction: Error on data node " + RecordNodeOpenSessionEvent.getNode(), e);
      if (tx != null)
        tx.rollback();
      throw e;
    } finally {
      session.close();
    }
  }

  public static Collection<Object> queryInTransaction(QueryCallback callback, Session session) {
    Collection<Object> results = Lists.newArrayList();
    try {
      session.setFlushMode(FlushMode.MANUAL);
      Transaction tx = session.beginTransaction();
      results = callback.execute(session);
      tx.commit();
    } catch (RuntimeException e) {
      LogFactory.getLog(BaseDataAccessObject.class).error("queryInTransaction: Error on data node " + RecordNodeOpenSessionEvent.getNode(), e);
      throw e;
    } finally {
      session.close();
    }
    return results;
  }

  public Collection<Object> populateDataIndexDelegates(Collection<Object> instances) {
    return Transform.map(new Unary<Object, Object>() {
      @SuppressWarnings("unchecked")
      public Object f(final Object instance) {
        final List<Method> allMethodsWithAnnotation = AnnotationHelper.getAllMethodsWithAnnotation(clazz, DataIndexDelegate.class);
        if (allMethodsWithAnnotation.size() == 0)
          return instance;
        Object modified = new GenerateInstance<Object>((Class<Object>) clazz).generateAndCopyProperties(instance);
        for (Method getter : allMethodsWithAnnotation) {
          String delegatorPropertyName = ReflectionTools.getPropertyNameOfAccessor(getter);
          EntityIndexConfig entityIndexConfig = config.getEntityIndexConfig(delegatorPropertyName);
          String delegatePropertyName = AnnotationHelper.getAnnotationDeeply(clazz, delegatorPropertyName, DataIndexDelegate.class).value();
          GeneratedInstanceInterceptor.setProperty(
              modified,
              delegatePropertyName,
              Filter.grepUnique(entityIndexConfig.getIndexValues(modified)));
        }
        return modified;
      }
    }, instances);
  }

  private boolean isPrimitiveCollection(final String propertyName) {
    return ReflectionTools.isCollectionProperty(config.getRepresentedInterface(), propertyName)
        && !ReflectionTools.isComplexCollectionItemProperty(config.getRepresentedInterface(), propertyName);
  }

  protected EntityIndexConfig resolveEntityIndexConfig(String propertyName) {
    return config.getPrimaryIndexKeyPropertyName().equals(propertyName)
        ? createEntityIndexConfigForPartitionIndex(config)
        : config.getEntityIndexConfig(propertyName);
  }

  private EntityIndexConfig createEntityIndexConfigForPartitionIndex(EntityConfig entityConfig) {
    if (partitionIndexEntityIndexConfig == null)
      partitionIndexEntityIndexConfig = new EntityIndexConfigImpl(entityConfig.getRepresentedInterface(), entityConfig.getPrimaryIndexKeyPropertyName());
    return partitionIndexEntityIndexConfig;
  }

  private void addPropertyRestriction(EntityIndexConfig indexConfig, Criteria criteria, String propertyName, Object propertyValue) {
    if (ReflectionTools.isCollectionProperty(config.getRepresentedInterface(), propertyName))
      if (ReflectionTools.isComplexCollectionItemProperty(config.getRepresentedInterface(), propertyName)) {
        criteria.createAlias(propertyName, "x")
            .add(Restrictions.eq("x." + indexConfig.getInnerClassPropertyName(), propertyValue));
      } else
        throw new UnsupportedOperationException("This call should have used HQL, not Criteria");
    else
      criteria.add(Restrictions.eq(propertyName, propertyValue));
  }

  protected Session createSessionForIndex(EntityConfig entityConfig, EntityIndexConfig indexConfig, Object propertyValue) {
    if (indexConfig.getIndexType().equals(IndexType.Delegates))
      return factory.openSession(
          ((EntityIndexConfigDelegator) indexConfig).getDelegateEntityConfig().getResourceName(),
          propertyValue);
    else if (indexConfig.getIndexType().equals(IndexType.Hive))
      return factory.openSession(
          entityConfig.getResourceName(),
          indexConfig.getIndexName(),
          propertyValue);
    else if (indexConfig.getIndexType().equals(IndexType.Data))
      return factory.openAllShardsSession();
    else if (indexConfig.getIndexType().equals(IndexType.Partition))
      return factory.openSession(propertyValue);
    throw new RuntimeException(String.format("Unknown IndexType: %s", indexConfig.getIndexType()));
  }

  private void addPropertyRangeRestriction(Criteria criteria, String propertyName, Object minValue, Object maxValue) {
    if (ReflectionTools.isCollectionProperty(config.getRepresentedInterface(), propertyName))
      if (ReflectionTools.isComplexCollectionItemProperty(config.getRepresentedInterface(), propertyName)) {
        criteria.createAlias(propertyName, "x")
            .add(Restrictions.between("x." + propertyName, minValue, maxValue));
      } else
        throw new UnsupportedOperationException("This isn't working yet");
    else
      criteria.add(Restrictions.between(propertyName, minValue, maxValue));
  }

  private void doSave(final Object entity, SessionCallback callback, SessionCallback cleanupCallback) {
    try {
      doInTransaction(callback, getSession());
    } catch (org.hibernate.TransactionException dupe) {
      if (dupe.getCause().getClass().equals(org.hibernate.exception.ConstraintViolationException.class)
          && !exists(config.getId(entity))) {
        doInTransaction(cleanupCallback, factory.openSession(config.getPrimaryIndexKey(entity)));
      } else {
        log.error(String.format("Detected an integrity constraint violation on the data node but %s with id %s exists in the directory.", config.getResourceName(), config.getId(entity)));
        throw dupe;
      }
    } catch (org.hibernate.exception.ConstraintViolationException dupe) {
      if (!exists(config.getId(entity))) {
        doInTransaction(cleanupCallback, factory.openSession(config.getPrimaryIndexKey(entity)));
      } else {
        log.error(String.format("Detected an integrity constraint violation on the data node but %s with id %s exists in the directory.", config.getResourceName(), config.getId(entity)));
        throw dupe;
      }
    }
  }

  private void doSaveAll(final Collection<Object> entities, SessionCallback callback, SessionCallback cleanupCallback) {
    try {
      doInTransaction(callback, getSession());
    } catch (org.hibernate.TransactionException dupe) {
      if (dupe.getCause().getClass().equals(org.hibernate.exception.ConstraintViolationException.class)
          || dupe.getCause().getClass().equals(org.hibernate.StaleObjectStateException.class)) {
        doInTransaction(cleanupCallback, factory.openSession(config.getPrimaryIndexKey(Atom.getFirstOrThrow(entities))));
      } else {
        log.error(String.format("Detected an integrity constraint violation on the data node while doing a saveAll with entities of class %s.", config.getResourceName()));
        throw dupe;
      }
    } catch (org.hibernate.exception.ConstraintViolationException dupe) {
      doInTransaction(cleanupCallback, factory.openSession(config.getPrimaryIndexKey(Atom.getFirstOrThrow(entities))));
    }
  }

  public void deleteAll(SessionCallback callback) {
    doInTransaction(callback, getSession());
  }


  private Boolean existsInSession(Session session, Serializable id) {
    return null != session.get(getRespresentedClass(), id);
  }

  private void validateNonNull(final Collection<Object> collection) {
    if (Filter.isMatch(new Filter.NullPredicate<Object>(), collection)) {
      String ids = Amass.joinByToString(new Joiner.ConcatStrings<String>(", "),
          Transform.map(new Unary<Object, String>() {
            public String f(Object item) {
              return item != null ? config.getId(item).toString() : "null";
            }
          }, collection));
      throw new HiveRuntimeException(String.format("Encountered null items in collection: %s", ids));
    }
  }

  protected Session getSession() {
    return factory.openSession(factory.getDefaultInterceptor());
  }

  private void addPaging(final Integer firstResult,
                         final Integer maxResults, Criteria criteria) {
    if (maxResults > 0) {
      criteria.setFirstResult(firstResult);
      criteria.setMaxResults(maxResults);
    }
  }

  /**
   * for debugging only
   */
  public Collection<Object> getAll() {
    QueryCallback query = new QueryCallback() {
      @SuppressWarnings("unchecked")
      public Collection<Object> execute(Session session) {
        Criteria criteria = session.createCriteria(config.getRepresentedInterface()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        return criteria.list();
      }
    };

    return queryInTransaction(query, factory.openAllShardsSession());
  }

  public Collection<Object> queryDataIndex(final String joinTableName, Object primaryIndexKey) {
    QueryCallback query = new QueryCallback() {
      @SuppressWarnings("unchecked")
      public Collection<Object> execute(Session session) {
        SQLQuery query = session.createSQLQuery("select * from " + joinTableName);
        return query.list();
      }
    };

    return queryInTransaction(query, factory.openSession(primaryIndexKey));
  }
}
TOP

Related Classes of org.hivedb.hibernate.BaseDataAccessObject

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.