blob: 1f602d0f9284d5fffc2a24576b0c1ee8b3435ec6 [file] [log] [blame]
/*******************************************************************************
* 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.ofbiz.entity.condition;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.oro.text.regex.MalformedPatternException;
import org.ofbiz.base.util.CompilerMatcher;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilGenerics;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericModelException;
import org.ofbiz.entity.config.model.Datasource;
import org.ofbiz.entity.model.ModelEntity;
import org.ofbiz.entity.model.ModelField;
/**
* Base class for comparisons.
*/
@SuppressWarnings("serial")
public abstract class EntityComparisonOperator<L, R> extends EntityOperator<L, R, Boolean> {
public static final String module = EntityComparisonOperator.class.getName();
protected transient static ThreadLocal<CompilerMatcher> compilerMatcher = CompilerMatcher.getThreadLocal();
public static String makeOroPattern(String sqlLike) {
try {
sqlLike = compilerMatcher.get().substitute("s/([$^.+*?])/\\\\$1/g", sqlLike);
sqlLike = compilerMatcher.get().substitute("s/%/.*/g", sqlLike);
sqlLike = compilerMatcher.get().substitute("s/_/./g", sqlLike);
} catch (Throwable t) {
String errMsg = "Error in ORO pattern substitution for SQL like clause [" + sqlLike + "]: " + t.toString();
Debug.logError(t, errMsg, module);
throw new IllegalArgumentException(errMsg);
}
return sqlLike;
}
@Override
public void validateSql(ModelEntity entity, L lhs, R rhs) throws GenericModelException {
if (lhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) lhs;
ecv.validateSql(entity);
}
if (rhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) rhs;
ecv.validateSql(entity);
}
}
@Override
public void visit(EntityConditionVisitor visitor, L lhs, R rhs) {
visitor.accept(lhs);
visitor.accept(rhs);
}
@Override
public void addSqlValue(StringBuilder sql, ModelEntity entity, List<EntityConditionParam> entityConditionParams, boolean compat, L lhs, R rhs, Datasource datasourceInfo) {
//Debug.logInfo("EntityComparisonOperator.addSqlValue field=" + lhs + ", value=" + rhs + ", value type=" + (rhs == null ? "null object" : rhs.getClass().getName()), module);
// if this is an IN operator and the rhs Object isEmpty, add "1=0" instead of the normal SQL. Note that "FALSE" does not work with all databases.
if (this.idInt == EntityOperator.ID_IN && UtilValidate.isEmpty(rhs)) {
sql.append("1=0");
return;
}
ModelField field;
if (lhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) lhs;
ecv.addSqlValue(sql, entity, entityConditionParams, false, datasourceInfo);
field = ecv.getModelField(entity);
} else if (compat && lhs instanceof String) {
field = getField(entity, (String) lhs);
if (field == null) {
sql.append(lhs);
} else {
sql.append(field.getColName());
}
} else {
addValue(sql, null, lhs, entityConditionParams);
field = null;
}
makeRHSWhereString(entity, entityConditionParams, sql, field, rhs, datasourceInfo);
}
@Override
public boolean isEmpty(L lhs, R rhs) {
return false;
}
protected void makeRHSWhereString(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sql, ModelField field, R rhs, Datasource datasourceInfo) {
sql.append(' ').append(getCode()).append(' ');
makeRHSWhereStringValue(entity, entityConditionParams, sql, field, rhs, datasourceInfo);
}
protected void makeRHSWhereStringValue(ModelEntity entity, List<EntityConditionParam> entityConditionParams, StringBuilder sql, ModelField field, R rhs, Datasource datasourceInfo) {
if (rhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) rhs;
if (ecv.getModelField(entity) == null) {
ecv.setModelField(field);
}
ecv.addSqlValue(sql, entity, entityConditionParams, false, datasourceInfo);
} else {
addValue(sql, field, rhs, entityConditionParams);
}
}
public abstract boolean compare(L lhs, R rhs);
public Boolean eval(Delegator delegator, Map<String, ? extends Object> map, L lhs, R rhs) {
return Boolean.valueOf(mapMatches(delegator, map, lhs, rhs));
}
@Override
public boolean mapMatches(Delegator delegator, Map<String, ? extends Object> map, L lhs, R rhs) {
Object leftValue;
if (lhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) lhs;
leftValue = ecv.getValue(delegator, map);
} else if (lhs instanceof String) {
leftValue = map.get(lhs);
} else {
leftValue = lhs;
}
Object rightValue;
if (rhs instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) rhs;
rightValue = ecv.getValue(delegator, map);
} else {
rightValue = rhs;
}
if (leftValue == WILDCARD || rightValue == WILDCARD) return true;
return compare(UtilGenerics.<L>cast(leftValue), UtilGenerics.<R>cast(rightValue));
}
@Override
public EntityCondition freeze(L lhs, R rhs) {
return EntityCondition.makeCondition(freeze(lhs), this, freeze(rhs));
}
protected Object freeze(Object item) {
if (item instanceof EntityConditionValue) {
EntityConditionValue ecv = (EntityConditionValue) item;
return ecv.freeze();
} else {
return item;
}
}
public EntityComparisonOperator(int id, String code) {
super(id, code);
}
public static final <T> boolean compareEqual(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (!lhs.equals(rhs)) {
return false;
}
return true;
}
public static final <T> boolean compareNotEqual(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs == null) {
return false;
}
} else if (lhs.equals(rhs)) {
return false;
}
return true;
}
public static final <T> boolean compareGreaterThan(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (lhs.compareTo(rhs) <= 0) {
return false;
}
return true;
}
public static final <T> boolean compareGreaterThanEqualTo(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (lhs.compareTo(rhs) < 0) {
return false;
}
return true;
}
public static final <T> boolean compareLessThan(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (lhs.compareTo(rhs) >= 0) {
return false;
}
return true;
}
public static final <T> boolean compareLessThanEqualTo(Comparable<T> lhs, T rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (lhs.compareTo(rhs) > 0) {
return false;
}
return true;
}
public static final <L,R> boolean compareIn(L lhs, R rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
} else {
return true;
}
} else if (rhs instanceof Collection<?>) {
if (((Collection<?>) rhs).contains(lhs)) {
return true;
} else {
return false;
}
} else if (lhs.equals(rhs)) {
return true;
} else {
return false;
}
}
public static final <L,R> boolean compareLike(L lhs, R rhs) {
if (lhs == null) {
if (rhs != null) {
return false;
}
} else if (lhs instanceof String && rhs instanceof String) {
//see if the lhs value is like the rhs value, rhs will have the pattern characters in it...
try {
return compilerMatcher.get().matches((String) lhs, makeOroPattern((String) rhs));
}
catch (MalformedPatternException e) {
Debug.logError(e, module);
return false;
}
}
return true;
}
}