blob: 3a65de3c6b2a09399fea6ae2e657f58cc97a3c29 [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.apache.ofbiz.entity.condition;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.ObjectType;
import org.apache.ofbiz.base.util.UtilGenerics;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.DelegatorFactory;
import org.apache.ofbiz.entity.GenericEntity;
import org.apache.ofbiz.entity.GenericEntityException;
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;
import org.apache.ofbiz.entity.model.ModelFieldType;
/**
* Encapsulates simple expressions used for specifying queries
*
*/
@SuppressWarnings("serial")
public final class EntityExpr extends EntityCondition {
public static final String module = EntityExpr.class.getName();
private final Object lhs;
private final EntityOperator<Object, Object, ?> operator;
private final Object rhs;
public <L,R,LL,RR> EntityExpr(L lhs, EntityComparisonOperator<LL,RR> operator, R rhs) {
if (lhs == null) {
throw new IllegalArgumentException("The field name/value cannot be null");
}
if (operator == null) {
throw new IllegalArgumentException("The operator argument cannot be null");
}
if (rhs == null || rhs == GenericEntity.NULL_FIELD) {
if (!EntityOperator.NOT_EQUAL.equals(operator) && !EntityOperator.EQUALS.equals(operator)) {
throw new IllegalArgumentException("Operator must be EQUALS or NOT_EQUAL when right/rhs argument is NULL ");
}
}
if (EntityOperator.BETWEEN.equals(operator)) {
if (!(rhs instanceof Collection<?>) || (((Collection<?>) rhs).size() != 2)) {
throw new IllegalArgumentException("BETWEEN Operator requires a Collection with 2 elements for the right/rhs argument");
}
}
if (lhs instanceof String) {
this.lhs = EntityFieldValue.makeFieldValue((String) lhs);
} else {
this.lhs = lhs;
}
this.operator = UtilGenerics.cast(operator);
this.rhs = rhs;
//Debug.logInfo("new EntityExpr internal field=" + lhs + ", value=" + rhs + ", value type=" + (rhs == null ? "null object" : rhs.getClass().getName()), module);
}
public EntityExpr(EntityCondition lhs, EntityJoinOperator operator, EntityCondition rhs) {
if (lhs == null) {
throw new IllegalArgumentException("The left EntityCondition argument cannot be null");
}
if (rhs == null) {
throw new IllegalArgumentException("The right EntityCondition argument cannot be null");
}
if (operator == null) {
throw new IllegalArgumentException("The operator argument cannot be null");
}
this.lhs = lhs;
this.operator = UtilGenerics.cast(operator);
this.rhs = rhs;
}
public Object getLhs() {
return lhs;
}
public <L,R,T> EntityOperator<L,R,T> getOperator() {
return UtilGenerics.cast(operator);
}
public Object getRhs() {
return rhs;
}
@Override
public boolean isEmpty() {
return operator.isEmpty(lhs, rhs);
}
@Override
public String makeWhereString(ModelEntity modelEntity, List<EntityConditionParam> entityConditionParams, Datasource datasourceInfo) {
// if (Debug.verboseOn()) Debug.logVerbose("makeWhereString for entity " + modelEntity.getEntityName(), module);
this.checkRhsType(modelEntity, null);
StringBuilder sql = new StringBuilder();
operator.addSqlValue(sql, modelEntity, entityConditionParams, true, lhs, rhs, datasourceInfo);
return sql.toString();
}
@Override
public boolean mapMatches(Delegator delegator, Map<String, ? extends Object> map) {
return operator.mapMatches(delegator, map, lhs, rhs);
}
@Override
public void checkCondition(ModelEntity modelEntity) throws GenericModelException {
// if (Debug.verboseOn()) Debug.logVerbose("checkCondition for entity " + modelEntity.getEntityName(), module);
if (lhs instanceof EntityCondition) {
((EntityCondition) lhs).checkCondition(modelEntity);
((EntityCondition) rhs).checkCondition(modelEntity);
}
}
@Override
protected void addValue(StringBuilder buffer, ModelField field, Object value, List<EntityConditionParam> params) {
if (rhs instanceof EntityFunction.UPPER) {
if (value instanceof String) {
value = ((String) value).toUpperCase();
}
}
super.addValue(buffer, field, value, params);
}
@Override
public EntityCondition freeze() {
return operator.freeze(lhs, rhs);
}
@Override
public void visit(EntityConditionVisitor visitor) {
visitor.acceptEntityOperator(operator, lhs, rhs);
}
@Override
public void accept(EntityConditionVisitor visitor) {
visitor.acceptEntityExpr(this);
}
public void checkRhsType(ModelEntity modelEntity, Delegator delegator) {
if (this.rhs == null || this.rhs == GenericEntity.NULL_FIELD || modelEntity == null) return;
Object value = this.rhs;
if (this.rhs instanceof EntityFunction<?>) {
value = UtilGenerics.<EntityFunction<?>>cast(this.rhs).getOriginalValue();
}
if (value instanceof Collection<?>) {
Collection<?> valueCol = UtilGenerics.cast(value);
if (valueCol.size() > 0) {
value = valueCol.iterator().next();
} else {
value = null;
}
}
if (delegator == null) {
// this will be the common case for now as the delegator isn't available where we want to do this
// we'll cheat a little here and assume the default delegator
delegator = DelegatorFactory.getDelegator("default");
}
String fieldName = null;
ModelField curField;
if (this.lhs instanceof EntityFieldValue) {
EntityFieldValue efv = (EntityFieldValue) this.lhs;
fieldName = efv.getFieldName();
curField = efv.getModelField(modelEntity);
} else {
// nothing to check
return;
}
if (curField == null) {
throw new IllegalArgumentException("FieldName " + fieldName + " not found for entity: " + modelEntity.getEntityName());
}
ModelFieldType type = null;
try {
type = delegator.getEntityFieldType(modelEntity, curField.getType());
} catch (GenericEntityException e) {
Debug.logWarning(e, module);
}
if (type == null) {
throw new IllegalArgumentException("Type " + curField.getType() + " not found for entity [" + modelEntity.getEntityName() + "]; probably because there is no datasource (helper) setup for the entity group that this entity is in: [" + delegator.getEntityGroupName(modelEntity.getEntityName()) + "]");
}
if (value instanceof EntityConditionSubSelect){
ModelFieldType valueType = null;
try {
ModelEntity valueModelEntity= ((EntityConditionSubSelect) value).getModelEntity();
valueType = delegator.getEntityFieldType(valueModelEntity, valueModelEntity.getField(((EntityConditionSubSelect) value).getKeyFieldName()).getType());
} catch (GenericEntityException e) {
Debug.logWarning(e, module);
}
// make sure the type of keyFieldName of EntityConditionSubSelect matches the field Java type
try {
if (!ObjectType.instanceOf(ObjectType.loadClass(valueType.getJavaType()), type.getJavaType())) {
String errMsg = "Warning using ["+ value.getClass().getName() + "] and entity field [" + modelEntity.getEntityName() + "." + curField.getName() + "]. The Java type of keyFieldName : [" + valueType.getJavaType()+ "] is not compatible with the Java type of the field [" + type.getJavaType() + "]";
// eventually we should do this, but for now we'll do a "soft" failure: throw new IllegalArgumentException(errMsg);
Debug.logWarning(new Exception("Location of database type warning"), "=-=-=-=-=-=-=-=-= Database type warning in EntityExpr =-=-=-=-=-=-=-=-= " + errMsg, module);
}
} catch (ClassNotFoundException e) {
String errMsg = "Warning using ["+ value.getClass().getName() + "] and entity field [" + modelEntity.getEntityName() + "." + curField.getName() + "]. The Java type of keyFieldName : [" + valueType.getJavaType()+ "] could not be found]";
// eventually we should do this, but for now we'll do a "soft" failure: throw new IllegalArgumentException(errMsg);
Debug.logWarning(e, "=-=-=-=-=-=-=-=-= Database type warning in EntityExpr =-=-=-=-=-=-=-=-= " + errMsg, module);
}
} else if (value instanceof EntityFieldValue) {
EntityFieldValue efv = (EntityFieldValue) this.lhs;
String rhsFieldName = efv.getFieldName();
ModelField rhsField = efv.getModelField(modelEntity);
if (rhsField == null) {
throw new IllegalArgumentException("FieldName " + rhsFieldName + " not found for entity: " + modelEntity.getEntityName());
}
ModelFieldType rhsType = null;
try {
rhsType = delegator.getEntityFieldType(modelEntity, rhsField.getType());
} catch (GenericEntityException e) {
Debug.logWarning(e, module);
}
try {
if (!ObjectType.instanceOf(ObjectType.loadClass(rhsType.getJavaType()), type.getJavaType())) {
String errMsg = "Warning using ["+ value.getClass().getName() + "] and entity field [" + modelEntity.getEntityName() + "." + curField.getName() + "]. The Java type [" + rhsType.getJavaType() + "] of rhsFieldName : [" + rhsFieldName + "] is not compatible with the Java type of the field [" + type.getJavaType() + "]";
// eventually we should do this, but for now we'll do a "soft" failure: throw new IllegalArgumentException(errMsg);
Debug.logWarning(new Exception("Location of database type warning"), "=-=-=-=-=-=-=-=-= Database type warning in EntityExpr =-=-=-=-=-=-=-=- " + errMsg, module);
}
} catch (ClassNotFoundException e) {
String errMsg = "Warning using ["+ value.getClass().getName() + "] and entity field [" + modelEntity.getEntityName() + "." + curField.getName() + "]. The Java type [" + rhsType.getJavaType() + "] of rhsFieldName : [" + rhsFieldName + "] could not be found]";
// eventually we should do this, but for now we'll do a "soft" failure: throw new IllegalArgumentException(errMsg);
Debug.logWarning(e, "=-=-=-=-=-=-=-=-= Database type warning in EntityExpr =-=-=-=-=-=-=-=-= " + errMsg, module);
}
} else {
// make sure the type matches the field Java type
if (!ObjectType.instanceOf(value, type.getJavaType())) {
String errMsg = "In entity field [" + modelEntity.getEntityName() + "." + curField.getName() + "] set the value passed in [" + value.getClass().getName() + "] is not compatible with the Java type of the field [" + type.getJavaType() + "]";
// eventually we should do this, but for now we'll do a "soft" failure: throw new IllegalArgumentException(errMsg);
Debug.logWarning(new Exception("Location of database type warning"), "=-=-=-=-=-=-=-=-= Database type warning in EntityExpr =-=-=-=-=-=-=-=-= " + errMsg, module);
}
}
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof EntityExpr)) return false;
EntityExpr other = (EntityExpr) obj;
boolean isEqual = equals(lhs, other.lhs) &&
equals(operator, other.operator) &&
equals(rhs, other.rhs);
//if (!isEqual) {
// Debug.logWarning("EntityExpr.equals is false for: \n-this.lhs=" + this.lhs + "; other.lhs=" + other.lhs +
// "\nthis.operator=" + this.operator + "; other.operator=" + other.operator +
// "\nthis.rhs=" + this.rhs + "other.rhs=" + other.rhs, module);
//}
return isEqual;
}
@Override
public int hashCode() {
return hashCode(lhs) +
hashCode(operator) +
hashCode(rhs);
}
}