package com.plexobject.rbac.repository.bdb; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import org.apache.log4j.Logger; import com.plexobject.rbac.repository.BaseRepository; import com.plexobject.rbac.repository.NotFoundException; import com.plexobject.rbac.repository.PagedList; import com.plexobject.rbac.repository.PersistenceException; import com.plexobject.rbac.domain.PersistentObject; import com.plexobject.rbac.domain.Identifiable; import com.plexobject.rbac.domain.Validatable; import com.plexobject.rbac.metric.Metric; import com.plexobject.rbac.metric.Timing; import com.plexobject.rbac.utils.CurrentRequest; import com.sleepycat.je.DatabaseException; import com.sleepycat.persist.EntityCursor; import com.sleepycat.persist.EntityStore; import com.sleepycat.persist.PrimaryIndex; public class BaseRepositoryImpl<T extends Identifiable<ID>, ID> implements BaseRepository<T, ID> { static final int MAX_LIMIT = 512; static final int DEFAULT_LIMIT = 20; final Logger LOGGER = Logger.getLogger(getClass()); private final Class<T> entityBeanType; private final Class<ID> pkType; protected final EntityStore store; protected PrimaryIndex<ID, T> primaryIndex; @SuppressWarnings("unchecked") public BaseRepositoryImpl(final EntityStore store) { this.store = store; this.entityBeanType = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; this.pkType = (Class<ID>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[1]; try { primaryIndex = store.getPrimaryIndex(pkType, entityBeanType); } catch (DatabaseException e) { throw new PersistenceException(e); } } @Override public PagedList<T, ID> findAll(ID firstKey, int limit) { if (limit <= 0) { limit = DEFAULT_LIMIT; } limit = Math.max(limit, MAX_LIMIT); final Timing timer = Metric .newTiming(getClass().getName() + ".findAll"); EntityCursor<T> cursor = null; List<T> all = new ArrayList<T>(); try { cursor = primaryIndex.entities(firstKey, false, null, true); Iterator<T> it = cursor.iterator(); ID lastKey = null; for (int i = 0; it.hasNext() && i < limit; i++) { T next = it.next(); all.add(next); lastKey = next.getId(); } return new PagedList<T, ID>(all, firstKey, lastKey, limit, all .size() == limit); } catch (DatabaseException e) { throw new PersistenceException("Failed to find all in " + store.getStoreName(), e); } finally { timer.stop(); if (cursor != null) { try { cursor.close(); } catch (DatabaseException e) { LOGGER.error("failed to close cursor", e); } } } } @Override public T findById(ID id) throws PersistenceException { final Timing timer = Metric.newTiming(getClass().getName() + ".findById"); try { T t = primaryIndex.get(id); if (t == null) { throw new NotFoundException("Failed to find " + id + " in " + store.getStoreName()); } return t; } catch (DatabaseException e) { throw new NotFoundException("Failed to find " + id + " in " + store.getStoreName(), e); } finally { timer.stop(); } } @Override public boolean remove(ID id) throws PersistenceException { final Timing timer = Metric.newTiming(getClass().getName() + ".remove"); try { return primaryIndex.delete(id); } catch (DatabaseException e) { throw new NotFoundException("Failed to remove " + id + " in " + store.getStoreName(), e); } finally { timer.stop(); } } @Override public T save(T object) throws PersistenceException { final Timing timer = Metric.newTiming(getClass().getName() + ".remove"); try { // call validation if (object instanceof Validatable) { ((Validatable) object).validate(); } if (object instanceof PersistentObject) { PersistentObject auditable = (PersistentObject) object; if (auditable.getCreatedBy() == null) { auditable.setCreatedAt(new Date()); auditable.setCreatedBy(CurrentRequest.getSubjectName()); auditable .setCreatedIPAddress(CurrentRequest.getIPAddress()); } auditable.setUpdatedAt(new Date()); auditable.setUpdatedBy(CurrentRequest.getSubjectName()); auditable.setUpdatedIPAddress(CurrentRequest.getIPAddress()); } T old = primaryIndex.put(object); if (LOGGER.isDebugEnabled()) { LOGGER.debug("saving old " + old + ", new " + object); } return object; } catch (DatabaseException e) { throw new PersistenceException("Failed to save " + object + " in " + store.getStoreName(), e); } finally { timer.stop(); } } public Class<T> getEntityBeanType() { return entityBeanType; } public void clear() throws PersistenceException { try { store.truncateClass(entityBeanType); } catch (DatabaseException e) { throw new PersistenceException("Failed to remove all objects in " + store.getStoreName(), e); } } public void close() { try { store.close(); } catch (DatabaseException e) { throw new PersistenceException(e); } } }