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)); } }