/* * Copyright 2009 The Fornax Project Team, including the original * author or authors. * * 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 org.sculptor.framework.accessimpl.mongodb; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import org.sculptor.framework.accessapi.ConditionalCriteria; import org.sculptor.framework.accessapi.ConditionalCriteria.Operator; import org.sculptor.framework.accessapi.FindByConditionAccess; import org.sculptor.framework.domain.Property; import com.mongodb.BasicDBObject; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.QueryOperators; /** * <p> * Implementation of Access command FindByConditionAccess. * </p> * <p> * Command design pattern. * </p> */ public class MongoDbFindByConditionAccessImpl<T> extends MongoDbAccessBase<T> implements FindByConditionAccess<T> { private List<ConditionalCriteria> cndCriterias = new ArrayList<ConditionalCriteria>(); private Set<String> fetchAssociations = new HashSet<String>(); private int firstResult = -1; private int maxResult = 0; private List<T> result; private Long rowCount = null; private Property<?>[] fetchEager; public MongoDbFindByConditionAccessImpl(Class<T> persistentClass) { setPersistentClass(persistentClass); } public void setCondition(List<ConditionalCriteria> criteria) { cndCriterias = criteria; } public void addCondition(ConditionalCriteria criteria) { cndCriterias.add(criteria); } public void setFetchAssociations(Set<String> associationPaths) { this.fetchAssociations = associationPaths; } public void addFetchAssociation(String associationPath) { this.fetchAssociations.add(associationPath); } protected Set<String> getFetchAssociations() { return fetchAssociations; } public void setFetchEager(Property<?>[] fetchEager) { this.fetchEager = fetchEager; } public Property<?>[] getFetchEager() { return fetchEager; } protected int getFirstResult() { return firstResult; } public void setFirstResult(int firstResult) { this.firstResult = firstResult; } protected int getMaxResult() { return maxResult; } public void setMaxResult(int maxResult) { this.maxResult = maxResult; } public List<T> getResult() { return this.result; } @Override public void performExecute() { DBObject query = createQuery(); DBCursor cur = getDBCollection().find(query); sort(cur); if (firstResult >= 0) { cur.skip(firstResult); } if (maxResult >= 1) { cur.limit(maxResult); } List<T> foundResult = new ArrayList<T>(); for (DBObject each : cur) { T eachResult = getDataMapper().toDomain(each); foundResult.add(eachResult); } this.result = foundResult; } private DBObject createQuery() { DBObject query = new BasicDBObject(); for (ConditionalCriteria crit : cndCriterias) { makeCriterion(query, crit, false); } return query; } protected void makeCriterion(DBObject query, ConditionalCriteria crit, boolean not) { ConditionalCriteria.Operator operator = crit.getOperator(); if (Operator.Equal.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.NE, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.Like.equals(operator)) { Pattern regex = regex(crit.getFirstOperant(), false); Object dbValue = wrapNot(not, regex); query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.IgnoreCaseLike.equals(operator)) { Pattern regex = regex(crit.getFirstOperant(), true); Object dbValue = wrapNot(not, regex); query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.In.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.NIN, dbValue); } else { dbValue = new BasicDBObject(QueryOperators.IN, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.LessThan.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.GTE, dbValue); } else { dbValue = new BasicDBObject(QueryOperators.LT, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.LessThanOrEqual.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.GT, dbValue); } else { dbValue = new BasicDBObject(QueryOperators.LTE, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.GreatThan.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.LTE, dbValue); } else { dbValue = new BasicDBObject(QueryOperators.GT, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.GreatThanOrEqual.equals(operator)) { Object dbValue = toData(crit.getFirstOperant()); if (not) { dbValue = new BasicDBObject(QueryOperators.LT, dbValue); } else { dbValue = new BasicDBObject(QueryOperators.GTE, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.IsNull.equals(operator)) { Object dbValue = null; if (not) { dbValue = new BasicDBObject(QueryOperators.NE, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.IsNotNull.equals(operator)) { Object dbValue; if (not) { dbValue = null; } else { dbValue = new BasicDBObject(QueryOperators.NE, null); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.IsEmpty.equals(operator)) { Object dbValue = ""; if (not) { dbValue = new BasicDBObject(QueryOperators.NE, dbValue); } query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.IsNotEmpty.equals(operator)) { Object dbValue; if (not) { dbValue = ""; } else { dbValue = new BasicDBObject(QueryOperators.NE, ""); } query.put(crit.getPropertyFullName(), dbValue); } else if (not && Operator.Between.equals(operator)) { throw new UnsupportedOperationException("Not between condition not supported"); } else if (Operator.Between.equals(operator)) { Object first = toData(crit.getFirstOperant()); Object second = toData(crit.getSecondOperant()); DBObject dbValue = new BasicDBObject(); dbValue.put(QueryOperators.GTE, first); dbValue.put(QueryOperators.LTE, second); query.put(crit.getPropertyFullName(), dbValue); } else if (Operator.And.equals(operator)) { makeCriterion(query, (ConditionalCriteria) crit.getFirstOperant(), not); makeCriterion(query, (ConditionalCriteria) crit.getSecondOperant(), not); } else if (Operator.Not.equals(operator)) { makeCriterion(query, (ConditionalCriteria) crit.getFirstOperant(), !not); } else if (Operator.Or.equals(operator)) { throw new UnsupportedOperationException("Or condition not supported"); } } private Object wrapNot(boolean not, Object dbValue) { if (not) { dbValue = new BasicDBObject("$not", dbValue); } return dbValue; } protected Pattern regex(Object expression, boolean ignoreCase) { if (expression instanceof Pattern) { return (Pattern) expression; } String strExpression = String.valueOf(expression); if (ignoreCase) { return Pattern.compile(strExpression, Pattern.CASE_INSENSITIVE); } else { return Pattern.compile(strExpression); } } protected void sort(DBCursor cur) { BasicDBObject orderBy = new BasicDBObject(); for (ConditionalCriteria crit : cndCriterias) { if (Operator.OrderAsc.equals(crit.getOperator())) { orderBy.put(crit.getPropertyFullName(), 1); } else if (Operator.OrderDesc.equals(crit.getOperator())) { orderBy.put(crit.getPropertyFullName(), -1); } } if (!orderBy.isEmpty()) { cur.sort(orderBy); } } public Long getResultCount() { return rowCount; } public void executeCount() { DBObject query = createQuery(); long count = getDBCollection().getCount(query); if (count > Integer.MAX_VALUE) { throw new IllegalStateException("Too many in count: " + count); } rowCount = count; } }