| /******************************************************************************* |
| * 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); |
| } |
| } |