package org.opennms.netmgt.dao.hibernate;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Subqueries;
import org.hibernate.type.StringType;
import org.opennms.core.criteria.AbstractCriteriaVisitor;
import org.opennms.core.criteria.Alias;
import org.opennms.core.criteria.Criteria;
import org.opennms.core.criteria.Fetch;
import org.opennms.core.criteria.Order;
import org.opennms.core.criteria.Order.OrderVisitor;
import org.opennms.core.criteria.restrictions.AllRestriction;
import org.opennms.core.criteria.restrictions.AnyRestriction;
import org.opennms.core.criteria.restrictions.BaseRestrictionVisitor;
import org.opennms.core.criteria.restrictions.BetweenRestriction;
import org.opennms.core.criteria.restrictions.EqRestriction;
import org.opennms.core.criteria.restrictions.GeRestriction;
import org.opennms.core.criteria.restrictions.GtRestriction;
import org.opennms.core.criteria.restrictions.IlikeRestriction;
import org.opennms.core.criteria.restrictions.InRestriction;
import org.opennms.core.criteria.restrictions.IplikeRestriction;
import org.opennms.core.criteria.restrictions.LeRestriction;
import org.opennms.core.criteria.restrictions.LikeRestriction;
import org.opennms.core.criteria.restrictions.LtRestriction;
import org.opennms.core.criteria.restrictions.NeRestriction;
import org.opennms.core.criteria.restrictions.NotNullRestriction;
import org.opennms.core.criteria.restrictions.NotRestriction;
import org.opennms.core.criteria.restrictions.NullRestriction;
import org.opennms.core.criteria.restrictions.Restriction;
import org.opennms.core.criteria.restrictions.RestrictionVisitor;
import org.opennms.core.criteria.restrictions.SqlRestriction;
import org.opennms.netmgt.dao.CriteriaConverter;
public class HibernateCriteriaConverter implements CriteriaConverter<DetachedCriteria> {
public org.hibernate.Criteria convert(final Criteria criteria, final Session session) {
final HibernateCriteriaVisitor visitor = new HibernateCriteriaVisitor();
criteria.visit(visitor);
return visitor.getCriteria(session);
}
@Override
public DetachedCriteria convert(final Criteria criteria) {
final HibernateCriteriaVisitor visitor = new HibernateCriteriaVisitor();
criteria.visit(visitor);
return visitor.getCriteria();
}
public static final class HibernateCriteriaVisitor extends AbstractCriteriaVisitor {
private DetachedCriteria m_criteria;
private Class<?> m_class;
private Set<org.hibernate.criterion.Order> m_orders = new LinkedHashSet<org.hibernate.criterion.Order>();
private Set<org.hibernate.criterion.Criterion> m_criterions = new LinkedHashSet<org.hibernate.criterion.Criterion>();
private boolean m_distinct = false;
private Integer m_limit;
private Integer m_offset;
public org.hibernate.Criteria getCriteria(final Session session) {
final org.hibernate.Criteria hibernateCriteria = getCriteria().getExecutableCriteria(session);
if (m_limit != null) hibernateCriteria.setMaxResults(m_limit);
if (m_offset != null) hibernateCriteria.setFirstResult(m_offset);
return hibernateCriteria;
}
public DetachedCriteria getCriteria() {
if (m_criteria == null) {
throw new IllegalStateException("Unable to determine Class<?> of this criteria!");
}
for (final Criterion criterion : m_criterions) {
m_criteria.add(criterion);
}
if (m_distinct) {
m_criteria.setProjection(Projections.distinct(Projections.id()));
final DetachedCriteria newCriteria = DetachedCriteria.forClass(m_class);
newCriteria.add(Subqueries.propertyIn("id", m_criteria));
m_criteria = newCriteria;
}
for (final org.hibernate.criterion.Order order : m_orders) {
m_criteria.addOrder(order);
}
return m_criteria;
}
@Override
public void visitClass(final Class<?> clazz) {
m_class = clazz;
m_criteria = DetachedCriteria.forClass(clazz);
}
@Override
public void visitOrder(final Order order) {
final HibernateOrderVisitor visitor = new HibernateOrderVisitor();
order.visit(visitor);
// we hold onto these later because they need to be applied after distinct projection
m_orders.add(visitor.getOrder());
}
@Override
public void visitAlias(final Alias alias) {
int aliasType = 0;
switch(alias.getType()) {
case FULL_JOIN:
aliasType = org.hibernate.Criteria.FULL_JOIN;
break;
case LEFT_JOIN:
aliasType = org.hibernate.Criteria.LEFT_JOIN;
break;
case INNER_JOIN:
aliasType = org.hibernate.Criteria.INNER_JOIN;
break;
default:
aliasType = org.hibernate.Criteria.INNER_JOIN;
break;
}
m_criteria.createAlias(alias.getAssociationPath(), alias.getAlias(), aliasType);
}
@Override
public void visitFetch(final Fetch fetch) {
switch(fetch.getFetchType()) {
case DEFAULT:
m_criteria.setFetchMode(fetch.getAttribute(), FetchMode.DEFAULT);
break;
case EAGER:
m_criteria.setFetchMode(fetch.getAttribute(), FetchMode.JOIN);
break;
case LAZY:
m_criteria.setFetchMode(fetch.getAttribute(), FetchMode.SELECT);
break;
default:
m_criteria.setFetchMode(fetch.getAttribute(), FetchMode.DEFAULT);
break;
}
}
@Override
public void visitRestriction(final Restriction restriction) {
final HibernateRestrictionVisitor visitor = new HibernateRestrictionVisitor();
restriction.visit(visitor);
m_criterions.addAll(visitor.getCriterions());
}
@Override
public void visitDistinct(final boolean distinct) {
m_distinct = distinct;
}
@Override
public void visitLimit(final Integer limit) {
m_limit = limit;
}
@Override
public void visitOffset(final Integer offset) {
m_offset = offset;
}
};
public static final class HibernateOrderVisitor implements OrderVisitor {
private String m_attribute;
private boolean m_ascending = true;
@Override
public void visitAttribute(final String attribute) {
m_attribute = attribute;
}
@Override
public void visitAscending(final boolean ascending) {
m_ascending = ascending;
}
public org.hibernate.criterion.Order getOrder() {
if (m_ascending) {
return org.hibernate.criterion.Order.asc(m_attribute);
} else {
return org.hibernate.criterion.Order.desc(m_attribute);
}
}
}
public static final class HibernateRestrictionVisitor extends BaseRestrictionVisitor implements RestrictionVisitor {
private static final StringType STRING_TYPE = new StringType();
private List<Criterion> m_criterions = new ArrayList<Criterion>();
public List<Criterion> getCriterions() {
return m_criterions;
}
@Override
public void visitNull(final NullRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.isNull(restriction.getAttribute()));
}
@Override
public void visitNotNull(final NotNullRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.isNotNull(restriction.getAttribute()));
}
@Override
public void visitEq(final EqRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.eq(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitNe(final NeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.ne(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitGt(final GtRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.gt(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitGe(final GeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.ge(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitLt(final LtRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.lt(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitLe(final LeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.le(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitAllComplete(final AllRestriction restriction) {
final int restrictionSize = restriction.getRestrictions().size();
final int criterionSize = m_criterions.size();
if (criterionSize < restrictionSize) {
throw new IllegalStateException("AllRestriction with " + restrictionSize + " entries encountered, but we only have " + criterionSize + " criterions!");
}
final List<Criterion> criterions = m_criterions.subList(criterionSize - restrictionSize, criterionSize);
final Junction j = org.hibernate.criterion.Restrictions.conjunction();
for (final Criterion crit : criterions) {
j.add(crit);
}
criterions.clear();
m_criterions.add(j);
}
@Override
public void visitAnyComplete(final AnyRestriction restriction) {
final int restrictionSize = restriction.getRestrictions().size();
final int criterionSize = m_criterions.size();
if (criterionSize < restrictionSize) {
throw new IllegalStateException("AllRestriction with " + restrictionSize + " entries encountered, but we only have " + criterionSize + " criterions!");
}
final List<Criterion> criterions = m_criterions.subList(criterionSize - restrictionSize, criterionSize);
final Junction j = org.hibernate.criterion.Restrictions.disjunction();
for (final Criterion crit : criterions) {
j.add(crit);
}
criterions.clear();
m_criterions.add(j);
}
@Override
public void visitLike(final LikeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.like(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitIlike(final IlikeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.ilike(restriction.getAttribute(), restriction.getValue()));
}
@Override
public void visitIn(final InRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.in(restriction.getAttribute(), restriction.getValues()));
}
@Override
public void visitNotComplete(final NotRestriction restriction) {
if (m_criterions.size() == 0) {
throw new IllegalStateException("NotRestriction called, but no criterions exist to negate!");
}
final Criterion criterion = m_criterions.remove(m_criterions.size() - 1);
m_criterions.add(org.hibernate.criterion.Restrictions.not(criterion));
}
@Override
public void visitBetween(final BetweenRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.between(restriction.getAttribute(), restriction.getBegin(), restriction.getEnd()));
}
@Override
public void visitSql(final SqlRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.sqlRestriction(restriction.getAttribute()));
}
@Override
public void visitIplike(final IplikeRestriction restriction) {
m_criterions.add(org.hibernate.criterion.Restrictions.sqlRestriction("iplike({alias}.ipAddr, ?)", (String)restriction.getValue(), STRING_TYPE));
}
}
}