/******************************************************************************* * 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.List; import java.util.Map; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.entity.Delegator; 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 entity functions. * */ @SuppressWarnings("serial") public abstract class EntityFunction<T extends Comparable<?>> extends EntityConditionValue { public static interface Fetcher<T> { T getValue(Object value); } public static enum SQLFunction { LENGTH, TRIM, UPPER, LOWER; } public static final int ID_LENGTH = SQLFunction.LENGTH.ordinal(); public static final int ID_TRIM = SQLFunction.TRIM.ordinal(); public static final int ID_UPPER = SQLFunction.UPPER.ordinal(); public static final int ID_LOWER = SQLFunction.LOWER.ordinal(); public static EntityFunction<Integer> LENGTH(EntityConditionValue nested) { return new LENGTH(nested); } public static EntityFunction<Integer> LENGTH(Object value) { return new LENGTH(value); } public static EntityFunction<String> TRIM(EntityConditionValue nested) { return new TRIM(nested); } public static EntityFunction<String> TRIM(Object value) { return new TRIM(value); } public static EntityFunction<String> UPPER(EntityConditionValue nested) { return new UPPER(nested); } public static EntityFunction<String> UPPER(Object value) { return new UPPER(value); } public static EntityFunction<String> UPPER_FIELD(String fieldName) { return new UPPER(EntityFieldValue.makeFieldValue(fieldName)); } public static EntityFunction<String> LOWER(EntityConditionValue nested) { return new LOWER(nested); } public static EntityFunction<String> LOWER(Object value) { return new LOWER(value); } /** * Length() entity function. * */ public static class LENGTH extends EntityFunctionSingle<Integer> { public static Fetcher<Integer> FETCHER = new Fetcher<Integer>() { public Integer getValue(Object value) { return value.toString().length(); } }; private LENGTH(Object value) { super(FETCHER, SQLFunction.LENGTH, value); } } /** * Trim() entity function. * */ public static class TRIM extends EntityFunctionSingle<String> { public static Fetcher<String> FETCHER = new Fetcher<String>() { public String getValue(Object value) { return value.toString().trim(); } }; private TRIM(Object value) { super(FETCHER, SQLFunction.TRIM, value); } } /** * Upper() entity function. * */ public static class UPPER extends EntityFunctionSingle<String> { public static Fetcher<String> FETCHER = new Fetcher<String>() { public String getValue(Object value) { return value.toString().toUpperCase(); } }; private UPPER(Object value) { super(FETCHER, SQLFunction.UPPER, value); } } /** * Lower() entity function. * */ public static class LOWER extends EntityFunctionSingle<String> { public static Fetcher<String> FETCHER = new Fetcher<String>() { public String getValue(Object value) { return value.toString().toLowerCase(); } }; private LOWER(Object value) { super(FETCHER, SQLFunction.LOWER, value); } } public static abstract class EntityFunctionSingle<T extends Comparable<?>> extends EntityFunction<T> { protected EntityFunctionSingle(Fetcher<T> fetcher, SQLFunction function, Object value) { super(fetcher, function, value); } } public static abstract class EntityFunctionNested<T extends Comparable<?>> extends EntityFunction<T> { protected EntityFunctionNested(Fetcher<T> fetcher, SQLFunction function, EntityConditionValue nested) { super(fetcher, function, nested); } } protected final SQLFunction function; protected final EntityConditionValue nested; protected final Object value; protected final Fetcher<T> fetcher; protected ModelField field; protected EntityFunction(Fetcher<T> fetcher, SQLFunction function, EntityConditionValue nested) { this.fetcher = fetcher; this.function = function; this.nested = nested; this.value = null; } protected EntityFunction(Fetcher<T> fetcher, SQLFunction function, Object value) { this.fetcher = fetcher; this.function = function; if (value instanceof EntityConditionValue) { this.nested = (EntityConditionValue) value; this.value = null; } else { this.nested = null; this.value = value; } } @Override public EntityConditionValue freeze() { if (nested != null) { return new EntityFunctionNested<T>(fetcher, function, nested.freeze()) {}; } else { return new EntityFunctionSingle<T>(fetcher, function, value) {}; } } public String getCode() { return function.name(); } public Object getOriginalValue() { return this.value; } public int getId() { return function.ordinal(); } @Override public int hashCode() { return function.hashCode(); } @Override public boolean equals(Object obj) { if (!(obj instanceof EntityFunction<?>)) return false; EntityFunction<?> otherFunc = UtilGenerics.cast(obj); return (this.function == otherFunc.function && (this.nested != null ? nested.equals(otherFunc.nested) : otherFunc.nested == null) && (this.value != null ? value.equals(otherFunc.value) : otherFunc.value == null)); } @Override public void addSqlValue(StringBuilder sql, Map<String, String> tableAliases, ModelEntity modelEntity, List<EntityConditionParam> entityConditionParams, boolean includeTableNamePrefix, Datasource datasourceinfo) { sql.append(function.name()).append('('); if (nested != null) { nested.addSqlValue(sql, tableAliases, modelEntity, entityConditionParams, includeTableNamePrefix, datasourceinfo); } else { addValue(sql, null, value, entityConditionParams); } sql.append(')'); } @Override public void visit(EntityConditionVisitor visitor) { if (nested != null) { visitor.acceptEntityConditionValue(nested); } else { visitor.acceptObject(value); } } @Override public void accept(EntityConditionVisitor visitor) { visitor.acceptEntityFunction(this); } @Override public ModelField getModelField(ModelEntity modelEntity) { if (nested != null) { return nested.getModelField(modelEntity); } return field; } @Override public void setModelField(ModelField field) { this.field = field; } @Override public void validateSql(ModelEntity modelEntity) throws GenericModelException { if (nested != null) { nested.validateSql(modelEntity); } } @Override public Object getValue(Delegator delegator, Map<String, ? extends Object> map) { Object value = nested != null ? nested.getValue(delegator, map) : this.value; return value != null ? fetcher.getValue(value) : null; } }