com.ocs.dynamo.envers.dao.impl.VersionedEntityDaoImpl Maven / Gradle / Ivy
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.ocs.dynamo.envers.dao.impl;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import javax.persistence.NoResultException;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.query.AuditQuery;
import org.hibernate.envers.query.criteria.AuditConjunction;
import org.hibernate.envers.query.criteria.AuditCriterion;
import org.hibernate.envers.query.criteria.AuditDisjunction;
import org.hibernate.envers.query.criteria.AuditProperty;
import org.springframework.transaction.annotation.Transactional;
import com.ocs.dynamo.constants.DynamoConstants;
import com.ocs.dynamo.dao.FetchJoinInformation;
import com.ocs.dynamo.dao.Pageable;
import com.ocs.dynamo.dao.SortOrder;
import com.ocs.dynamo.dao.SortOrders;
import com.ocs.dynamo.dao.impl.BaseDaoImpl;
import com.ocs.dynamo.domain.AbstractEntity;
import com.ocs.dynamo.envers.dao.VersionedEntityDao;
import com.ocs.dynamo.envers.domain.DynamoRevisionEntity;
import com.ocs.dynamo.envers.domain.RevisionKey;
import com.ocs.dynamo.envers.domain.RevisionType;
import com.ocs.dynamo.envers.domain.VersionedEntity;
import com.ocs.dynamo.exception.OCSRuntimeException;
import com.ocs.dynamo.filter.And;
import com.ocs.dynamo.filter.Compare;
import com.ocs.dynamo.filter.Contains;
import com.ocs.dynamo.filter.DynamoFilterUtil;
import com.ocs.dynamo.filter.Filter;
import com.ocs.dynamo.filter.In;
import com.ocs.dynamo.filter.Like;
import com.ocs.dynamo.filter.Not;
import com.ocs.dynamo.filter.Or;
import com.ocs.dynamo.utils.DateUtils;
import com.querydsl.core.types.dsl.EntityPathBase;
/**
* Implementation of Data Access object for versioned entities
*
* @author bas.rutten
*
* @param the type of the primary key
* @param the type of the original entity
* @param the type of the versioned entity
*/
public abstract class VersionedEntityDaoImpl, U extends VersionedEntity>
extends BaseDaoImpl, U> implements VersionedEntityDao {
private static final String ENTITY_STRING = "entity.";
private static final Map REVISION_PROPS = new ConcurrentHashMap<>();
/**
* Adds any additional filters to an AuditQuery
*
* @param aq the AuditQuery to which to add the filters
* @param filter the filter to translate
*/
private void addAdditionalFilters(AuditQuery aq, Filter filter) {
AuditCriterion ac = createAuditCriterion(filter);
if (ac != null) {
aq.add(ac);
}
}
/**
* Adds a filter on the ID field to an audit query
*
* @param aq the audit query
* @param filter the overall filter
*/
@SuppressWarnings("unchecked")
private void addIdFilter(AuditQuery aq, Filter filter) {
if (filter != null) {
Filter idFilter = DynamoFilterUtil.extractFilter(filter, DynamoConstants.ID);
if (idFilter != null) {
Compare.Equal comp = (Compare.Equal) idFilter;
ID id = (ID) comp.getValue();
aq.add(AuditEntity.id().eq(id));
}
}
}
/**
* Overwrite count method to query the revision tables
*/
@Override
@Transactional
public long count(Filter filter, boolean distinct) {
// filter on ID (this should always be there)
AuditQuery aq = getAuditReader().createQuery().forRevisionsOfEntity(getBaseEntityClass(), false, true);
addIdFilter(aq, filter);
addAdditionalFilters(aq, filter);
return aq.getResultList().size();
}
/**
* Translates a filter to an AuditCriterion
*
* @param filter
* @return
*/
private AuditCriterion createAuditCriterion(Filter filter) {
if (filter instanceof Compare.Equal) {
Compare.Equal eq = (Compare.Equal) filter;
return createAuditProperty(eq.getPropertyId()).eq(eq.getValue());
} else if (filter instanceof Like) {
Like like = (Like) filter;
return createAuditProperty(like.getPropertyId()).like(like.getValue());
} else if (filter instanceof Compare.Greater) {
Compare.Greater gt = (Compare.Greater) filter;
return createAuditProperty(gt.getPropertyId()).gt(gt.getValue());
} else if (filter instanceof Compare.GreaterOrEqual) {
Compare.GreaterOrEqual ge = (Compare.GreaterOrEqual) filter;
return createAuditProperty(ge.getPropertyId()).ge(ge.getValue());
} else if (filter instanceof Compare.Less) {
Compare.Less lt = (Compare.Less) filter;
return createAuditProperty(lt.getPropertyId()).lt(lt.getValue());
} else if (filter instanceof Compare.LessOrEqual) {
Compare.LessOrEqual le = (Compare.LessOrEqual) filter;
return createAuditProperty(le.getPropertyId()).le(le.getValue());
} else if (filter instanceof And) {
And and = (And) filter;
AuditConjunction ac = AuditEntity.conjunction();
for (Filter f : and.getFilters()) {
AuditCriterion ct = createAuditCriterion(f);
if (ct != null) {
ac.add(ct);
}
}
return ac;
} else if (filter instanceof Or) {
Or or = (Or) filter;
AuditDisjunction ad = AuditEntity.disjunction();
for (Filter f : or.getFilters()) {
AuditCriterion ct = createAuditCriterion(f);
if (ct != null) {
ad.add(ct);
}
}
return ad;
} else if (filter instanceof Not) {
Not not = (Not) filter;
AuditCriterion ct = createAuditCriterion(not.getFilter());
if (ct != null) {
return AuditEntity.not(ct);
}
} else if (filter instanceof In) {
In in = (In) filter;
return AuditEntity.property(in.getPropertyId()).in(in.getValues());
} else if (filter instanceof Contains) {
Contains c = (Contains) filter;
throw new OCSRuntimeException("Contains filter is not supported for property " + c.getPropertyId());
}
return null;
}
/**
* Translates a property name to an AuditProperty
*
* @param prop the name of the property
* @return
*/
@SuppressWarnings("unchecked")
private AuditProperty createAuditProperty(String prop) {
if ("revisionType".equals(prop)) {
return (AuditProperty) AuditEntity.revisionType();
} else if (REVISION_PROPS.containsKey(prop)) {
prop = REVISION_PROPS.get(prop);
return (AuditProperty) AuditEntity.revisionProperty(prop);
} else {
int index = prop.indexOf(ENTITY_STRING);
if (index >= 0) {
prop = prop.substring(index + ENTITY_STRING.length());
}
return (AuditProperty) AuditEntity.property(prop);
}
}
/**
* Creates a new instance of the versioned entity
*
* @return
*/
protected abstract U createVersionedEntity(T t, int revision);
protected void doMap(U u) {
// overwrite in subclasses
}
@Override
@Transactional
public List fetch(Filter filter, FetchJoinInformation... joins) {
return fetch(filter, (Pageable) null, joins);
}
@Override
@Transactional
@SuppressWarnings("unchecked")
public List fetch(Filter filter, Pageable pageable, FetchJoinInformation... joins) {
AuditQuery aq = getAuditReader().createQuery().forRevisionsOfEntity(getBaseEntityClass(), false, true);
addIdFilter(aq, filter);
addAdditionalFilters(aq, filter);
if (pageable != null) {
aq.setFirstResult(pageable.getOffset());
aq.setMaxResults(pageable.getPageSize());
if (pageable.getSortOrders() != null) {
for (SortOrder so : pageable.getSortOrders().toArray()) {
String prop = so.getProperty();
AuditProperty> ap = createAuditProperty(prop);
if (so.isAscending()) {
aq.addOrder(ap.asc());
} else {
aq.addOrder(ap.desc());
}
}
}
}
List resultList = new ArrayList<>();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy