/**
   * Returns an entity in the given revision for the given entity-id.
   *
   * @param revisionNumber
   * @param id
   * @param reader
   * @return
   */
  @SuppressWarnings("unchecked")
  private Revision<N, T> getEntityForRevision(N revisionNumber, ID id, AuditReader reader) {

    Class<?> type = revisionEntityInformation.getRevisionEntityClass();

    T revision = (T) reader.findRevision(type, revisionNumber);
    Object entity = reader.find(entityInformation.getJavaType(), id, revisionNumber);

    return new Revision<N, T>((RevisionMetadata<N>) getRevisionMetadata(revision), (T) entity);
  }
  /*
   * (non-Javadoc)
   * @see org.springframework.data.repository.history.RevisionRepository#findRevisions(java.io.Serializable)
   */
  @SuppressWarnings("unchecked")
  public Revisions<N, T> findRevisions(ID id) {

    Class<T> type = entityInformation.getJavaType();
    AuditReader reader = AuditReaderFactory.get(entityManager);
    List<? extends Number> revisionNumbers = reader.getRevisions(type, id);

    return revisionNumbers.isEmpty()
        ? new Revisions<N, T>(Collections.EMPTY_LIST)
        : getEntitiesForRevisions((List<N>) revisionNumbers, id, reader);
  }
 public void setRepositories(Collection<CrudRepository> repositories) {
   for (CrudRepository repository : repositories) {
     Class<?> repoClass = AopUtils.getTargetClass(repository);
     Field infoField = ReflectionUtils.findField(repoClass, "entityInformation");
     ReflectionUtils.makeAccessible(infoField);
     Method m = ReflectionUtils.findMethod(repository.getClass(), "getTargetSource");
     ReflectionUtils.makeAccessible(m);
     try {
       SingletonTargetSource targetRepo = (SingletonTargetSource) m.invoke(repository);
       EntityInformation entityInfo = (EntityInformation) infoField.get(targetRepo.getTarget());
       Class<?>[] intfs = repository.getClass().getInterfaces();
       String name =
           StringUtils.uncapitalize(intfs[0].getSimpleName().replaceAll("Repository", ""));
       this.repositories.put(
           entityInfo.getJavaType(), new RepositoryCacheEntry(name, repository, entityInfo, null));
     } catch (Throwable t) {
       throw new IllegalStateException(t);
     }
   }
 }
  /**
   * Returns the entities in the given revisions for the entitiy with the given id.
   *
   * @param revisionNumbers
   * @param id
   * @param reader
   * @return
   */
  @SuppressWarnings("unchecked")
  private Revisions<N, T> getEntitiesForRevisions(
      List<N> revisionNumbers, ID id, AuditReader reader) {

    Class<T> type = entityInformation.getJavaType();
    Map<N, T> revisions = new HashMap<N, T>(revisionNumbers.size());

    Class<?> revisionEntityClass = revisionEntityInformation.getRevisionEntityClass();
    Map<Number, Object> revisionEntities =
        (Map<Number, Object>)
            reader.findRevisions(revisionEntityClass, new HashSet<Number>(revisionNumbers));

    for (Number number : revisionNumbers) {
      revisions.put((N) number, reader.find(type, id, number));
    }

    return new Revisions<N, T>(toRevisions(revisions, revisionEntities));
  }
  /*
   * (non-Javadoc)
   * @see org.springframework.data.repository.history.RevisionRepository#findRevisions(java.io.Serializable, org.springframework.data.domain.Pageable)
   */
  @SuppressWarnings("unchecked")
  public Page<Revision<N, T>> findRevisions(ID id, Pageable pageable) {

    Class<T> type = entityInformation.getJavaType();
    AuditReader reader = AuditReaderFactory.get(entityManager);
    List<Number> revisionNumbers = reader.getRevisions(type, id);

    if (pageable.getOffset() > revisionNumbers.size()) {
      return new PageImpl<Revision<N, T>>(Collections.<Revision<N, T>>emptyList(), pageable, 0);
    }

    int upperBound = pageable.getOffset() + pageable.getPageSize();
    upperBound = upperBound > revisionNumbers.size() ? revisionNumbers.size() : upperBound;

    List<? extends Number> subList = revisionNumbers.subList(pageable.getOffset(), upperBound);
    Revisions<N, T> revisions = getEntitiesForRevisions((List<N>) subList, id, reader);

    return new PageImpl<Revision<N, T>>(revisions.getContent(), pageable, revisionNumbers.size());
  }
  /*
   * (non-Javadoc)
   * @see org.springframework.data.repository.history.RevisionRepository#findLastChangeRevision(java.io.Serializable)
   */
  @SuppressWarnings("unchecked")
  public Revision<N, T> findLastChangeRevision(ID id) {

    Class<T> type = entityInformation.getJavaType();
    AuditReader reader = AuditReaderFactory.get(entityManager);

    List<Number> revisions = reader.getRevisions(type, id);

    if (revisions.isEmpty()) {
      return null;
    }

    N latestRevision = (N) revisions.get(revisions.size() - 1);

    Class<?> revisionEntityClass = revisionEntityInformation.getRevisionEntityClass();

    Object revisionEntity = reader.findRevision(revisionEntityClass, latestRevision);
    RevisionMetadata<N> metadata = (RevisionMetadata<N>) getRevisionMetadata(revisionEntity);
    return new Revision<N, T>(metadata, reader.find(type, id, latestRevision));
  }
 /*
  * (non-Javadoc)
  *
  * @see org.springframework.data.repository.CrudRepository#save(S)
  */
 @Override
 public <U extends T> U save(U entity) {
   template.put(entityInformation.getId(entity), entity);
   return entity;
 }
 /*
  * (non-Javadoc)
  *
  * @see
  * org.springframework.data.repository.CrudRepository#delete(java.lang.Object
  * )
  */
 @Override
 public void delete(T entity) {
   template.remove(entityInformation.getId(entity));
 }