/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.ofbiz.entity.condition; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntity; import org.apache.ofbiz.entity.GenericModelException; import org.apache.ofbiz.entity.config.model.Datasource; import org.apache.ofbiz.entity.model.ModelEntity; import org.apache.ofbiz.entity.model.ModelField; /** * Base class for operators (less than, greater than, equals, etc). * */ @SuppressWarnings("serial") public abstract class EntityOperator<L, R, T> extends EntityConditionBase { public static final int ID_EQUALS = 1; public static final int ID_NOT_EQUAL = 2; public static final int ID_LESS_THAN = 3; public static final int ID_GREATER_THAN = 4; public static final int ID_LESS_THAN_EQUAL_TO = 5; public static final int ID_GREATER_THAN_EQUAL_TO = 6; public static final int ID_IN = 7; public static final int ID_BETWEEN = 8; public static final int ID_NOT = 9; public static final int ID_AND = 10; public static final int ID_OR = 11; public static final int ID_LIKE = 12; public static final int ID_NOT_IN = 13; public static final int ID_NOT_LIKE = 14; private static final AtomicInteger dynamicId = new AtomicInteger(); private static HashMap<String, EntityOperator<?,?,?>> registry = new HashMap<String, EntityOperator<?,?,?>>(); private static <L,R,T> void registerCase(String name, EntityOperator<L,R,T> operator) { registry.put(name.toLowerCase(), operator); registry.put(name.toUpperCase(), operator); } public static <L,R,T> void register(String name, EntityOperator<L,R,T> operator) { registerCase(name, operator); registerCase(name.replaceAll("-", "_"), operator); registerCase(name.replaceAll("_", "-"), operator); } public static <L,R,T> EntityOperator<L,R,T> lookup(String name) { return UtilGenerics.cast(registry.get(name)); } public static <L,R> EntityComparisonOperator<L,R> lookupComparison(String name) { EntityOperator<?,?,Boolean> operator = lookup(name); if (!(operator instanceof EntityComparisonOperator<?,?>)) throw new IllegalArgumentException(name + " is not a comparison operator"); return UtilGenerics.cast(operator); } public static EntityJoinOperator lookupJoin(String name) { EntityOperator<?,?,Boolean> operator = lookup(name); if (!(operator instanceof EntityJoinOperator)) throw new IllegalArgumentException(name + " is not a join operator"); return UtilGenerics.cast(operator); } public static int requestId() { return dynamicId.get(); } public static final EntityComparisonOperator<?,?> EQUALS = new ComparableEntityComparisonOperator<Object>(ID_EQUALS, "=") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareEqual(lhs, rhs); } @Override protected void makeRHSWhereString(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sb, ModelField field, Object rhs, Datasource datasourceInfo) { if (rhs == null || rhs == GenericEntity.NULL_FIELD) { //Debug.logInfo("makeRHSWhereString: field IS NULL: " + field.getName(), module); sb.append(" IS NULL"); } else { //Debug.logInfo("makeRHSWhereString: field not null, doing super: " + field.getName() + ", type: " + rhs.getClass().getName() + ", value: " + rhs, module); super.makeRHSWhereString(entity, entityConditionParams, sb, field, rhs, datasourceInfo); } } }; static { register("equals", EQUALS); } static { register("=", EQUALS); } public static final EntityComparisonOperator<?,?> NOT_EQUAL = new ComparableEntityComparisonOperator<Object>(ID_NOT_EQUAL, "<>") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareNotEqual(lhs, rhs); } @Override protected void makeRHSWhereString(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sb, ModelField field, Object rhs, Datasource datasourceInfo) { if (rhs == null || rhs == GenericEntity.NULL_FIELD) { sb.append(" IS NOT NULL"); } else { super.makeRHSWhereString(entity, entityConditionParams, sb, field, rhs, datasourceInfo); } } }; static { register("not-equal", NOT_EQUAL); } static { register("not-equals", NOT_EQUAL); } static { register("notEqual", NOT_EQUAL); } static { register("!=", NOT_EQUAL); } static { register("<>", NOT_EQUAL); } public static final EntityComparisonOperator<?,?> LESS_THAN = new ComparableEntityComparisonOperator<Object>(ID_LESS_THAN, "<") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareLessThan(lhs, rhs); } }; static { register("less", LESS_THAN); } static { register("less-than", LESS_THAN); } static { register("lessThan", LESS_THAN); } static { register("<", LESS_THAN); } public static final EntityComparisonOperator<?,?> GREATER_THAN = new ComparableEntityComparisonOperator<Object>(ID_GREATER_THAN, ">") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareGreaterThan(lhs, rhs); } }; static { register("greater", GREATER_THAN); } static { register("greater-than", GREATER_THAN); } static { register("greaterThan", GREATER_THAN); } static { register(">", GREATER_THAN); } public static final EntityComparisonOperator<?,?> LESS_THAN_EQUAL_TO = new ComparableEntityComparisonOperator<Object>(ID_LESS_THAN_EQUAL_TO, "<=") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareLessThanEqualTo(lhs, rhs); } }; static { register("less-equals", LESS_THAN_EQUAL_TO); } static { register("less-than-equal-to", LESS_THAN_EQUAL_TO); } static { register("lessThanEqualTo", LESS_THAN_EQUAL_TO); } static { register("<=", LESS_THAN_EQUAL_TO); } public static final EntityComparisonOperator<?,?> GREATER_THAN_EQUAL_TO = new ComparableEntityComparisonOperator<Object>(ID_GREATER_THAN_EQUAL_TO, ">=") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareGreaterThanEqualTo(lhs, rhs); } }; static { register("greater-equals", GREATER_THAN_EQUAL_TO); } static { register("greater-than-equal-to", GREATER_THAN_EQUAL_TO); } static { register("greaterThanEqualTo", GREATER_THAN_EQUAL_TO); } static { register(">=", GREATER_THAN_EQUAL_TO); } public static final EntityComparisonOperator<?,?> IN = new CollectionEntityComparisonOperator<Object>(ID_IN, "IN") { @Override public boolean compare(Comparable<Object> lhs, Collection<Comparable<Object>> rhs) { return EntityComparisonOperator.compareIn(lhs, rhs); } @Override protected void makeRHSWhereStringValue(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sb, ModelField field, Collection<Comparable<Object>> rhs, Datasource datasourceInfo) { appendRHSList(entityConditionParams, sb, field, rhs); } }; static { register("in", IN); } public static final EntityComparisonOperator<?,?> BETWEEN = new CollectionEntityComparisonOperator<Object>(ID_BETWEEN, "BETWEEN") { @Override public boolean compare(Comparable<Object> lhs, Collection<Comparable<Object>> rhs) { return EntityComparisonOperator.compareIn(lhs, rhs); } @Override protected void makeRHSWhereStringValue(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sb, ModelField field, Collection<Comparable<Object>> rhs, Datasource datasourceInfo) { appendRHSBetweenList(entityConditionParams, sb, field, rhs); } }; static { register("between", BETWEEN); } public static final EntityComparisonOperator<?,?> NOT = new EntityComparisonOperator<Object, EntityCondition>(ID_NOT, "NOT") { @Override public boolean compare(Object lhs, EntityCondition rhs) { throw new UnsupportedOperationException(); } }; static { register("not", NOT); } public static final EntityJoinOperator AND = new EntityJoinOperator(ID_AND, "AND", false); static { register("and", AND); } public static final EntityJoinOperator OR = new EntityJoinOperator(ID_OR, "OR", true); static { register("or", OR); } public static final EntityComparisonOperator<?,?> LIKE = new ComparableEntityComparisonOperator<Object>(ID_LIKE, "LIKE") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return EntityComparisonOperator.compareLike(lhs, rhs); } }; static { register("like", LIKE); } public static final EntityComparisonOperator<?,?> NOT_LIKE = new ComparableEntityComparisonOperator<Object>(ID_NOT_LIKE, "NOT LIKE") { @Override public boolean compare(Comparable<Object> lhs, Object rhs) { return !EntityComparisonOperator.compareLike(lhs, rhs); } }; static { register("not-like", NOT_LIKE); } public static final EntityComparisonOperator<?,?> NOT_IN = new CollectionEntityComparisonOperator<Object>(ID_NOT_IN, "NOT IN") { @Override public boolean compare(Comparable<Object> lhs, Collection<Comparable<Object>> rhs) { return !EntityComparisonOperator.compareIn(lhs, rhs); } @Override protected void makeRHSWhereStringValue(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sb, ModelField field, Collection<Comparable<Object>> rhs, Datasource datasourceInfo) { appendRHSList(entityConditionParams, sb, field, rhs); } }; static { register("not-in", NOT_IN); } protected int idInt; protected String codeString; public EntityOperator(int id, String code) { idInt = id; codeString = code; } public String getCode() { if (codeString == null) { return "null"; } else { return codeString; } } public int getId() { return idInt; } @Override public String toString() { return codeString; } @Override public int hashCode() { return this.codeString.hashCode(); } // FIXME: CCE @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof EntityOperator<?,?,?>) { EntityOperator<?,?,?> otherOper = UtilGenerics.cast(obj); return this.idInt == otherOper.idInt; } return false; } public boolean entityMatches(GenericEntity entity, L lhs, R rhs) { return mapMatches(entity.getDelegator(), entity, lhs, rhs); } protected void appendRHSList(List<EntityConditionParam> entityConditionParams, StringBuilder whereStringBuilder, ModelField field, R rhs) { whereStringBuilder.append('('); if (rhs instanceof Collection<?>) { Iterator<R> rhsIter = UtilGenerics.<Collection<R>>cast(rhs).iterator(); while (rhsIter.hasNext()) { Object inObj = rhsIter.next(); addValue(whereStringBuilder, field, inObj, entityConditionParams); if (rhsIter.hasNext()) { whereStringBuilder.append(", "); } } } else { addValue(whereStringBuilder, field, rhs, entityConditionParams); } whereStringBuilder.append(')'); } protected <X> void appendRHSBetweenList(List<EntityConditionParam> entityConditionParams, StringBuilder whereStringBuilder, ModelField field, X rhs) { if (rhs instanceof Collection<?>) { Iterator<R> rhsIter = UtilGenerics.<Collection<R>>cast(rhs).iterator(); while (rhsIter.hasNext()) { Object inObj = rhsIter.next(); addValue(whereStringBuilder, field, inObj, entityConditionParams); if (rhsIter.hasNext()) { whereStringBuilder.append(" AND "); } } } } /* public T eval(Delegator delegator, Map<String, ? extends Object> map, Object lhs, Object rhs) { return castBoolean(mapMatches(delegator, map, lhs, rhs)); } */ public abstract boolean isEmpty(L lhs, R rhs); public abstract boolean mapMatches(Delegator delegator, Map<String, ? extends Object> map, L lhs, R rhs); public abstract void validateSql(ModelEntity entity, L lhs, R rhs) throws GenericModelException; public void addSqlValue(StringBuilder sql, ModelEntity entity, List<EntityConditionParam> entityConditionParams, L lhs, R rhs, Datasource datasourceInfo) { addSqlValue(sql, entity, entityConditionParams, true, lhs, rhs, datasourceInfo); } public abstract void addSqlValue(StringBuilder sql, ModelEntity entity, List<EntityConditionParam> entityConditionParams, boolean compat, L lhs, R rhs, Datasource datasourceInfo); public abstract EntityCondition freeze(L lhs, R rhs); public abstract void visit(EntityConditionVisitor visitor, L lhs, R rhs); public static final Comparable<?> WILDCARD = new Comparable<Object>() { public int compareTo(Object obj) { if (obj != WILDCARD) throw new ClassCastException(); return 0; } @Override public String toString() { return "(WILDCARD)"; } }; /** * Comparison operator for <code>Collection</code> types. * * @param <E> */ public static abstract class CollectionEntityComparisonOperator<E> extends EntityComparisonOperator<Comparable<E>, Collection<Comparable<E>>> { public CollectionEntityComparisonOperator(int id, String code) { super(id, code); } } /** * Comparison operator for <code>Comparable</code> types. * * @param <E> */ public static abstract class ComparableEntityComparisonOperator<E> extends EntityComparisonOperator<Comparable<E>, E> { public ComparableEntityComparisonOperator(int id, String code) { super(id, code); } } }