/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.envers.tools.query; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.envers.tools.MutableBoolean; import org.hibernate.envers.tools.MutableInteger; /** * Parameters of a query, built using {@link QueryBuilder}. * @author Adam Warski (adam at warski dot org) */ public class Parameters { public final static String AND = "and"; public final static String OR = "or"; /** * Main alias of the entity. */ private final String alias; /** * Connective between these parameters - "and" or "or". */ private final String connective; /** * For use by the parameter generator. Must be the same in all "child" (and parent) parameters. */ private final MutableInteger queryParamCounter; /** * A list of sub-parameters (parameters with a different connective). */ private final List<Parameters> subParameters; /** * A list of negated parameters. */ private final List<Parameters> negatedParameters; /** * A list of complete where-expressions. */ private final List<String> expressions; /** * Values of parameters used in expressions. */ private final Map<String, Object> localQueryParamValues; Parameters(String alias, String connective, MutableInteger queryParamCounter) { this.alias = alias; this.connective = connective; this.queryParamCounter = queryParamCounter; subParameters = new ArrayList<Parameters>(); negatedParameters = new ArrayList<Parameters>(); expressions = new ArrayList<String>(); localQueryParamValues = new HashMap<String, Object>(); } private String generateQueryParam() { return "_p" + queryParamCounter.getAndIncrease(); } /** * Adds sub-parameters with a new connective. That is, the parameters will be grouped in parentheses in the * generated query, e.g.: ... and (exp1 or exp2) and ..., assuming the old connective is "and", and the * new connective is "or". * @param newConnective New connective of the parameters. * @return Sub-parameters with the given connective. */ public Parameters addSubParameters(String newConnective) { if (connective.equals(newConnective)) { return this; } else { Parameters newParams = new Parameters(alias, newConnective, queryParamCounter); subParameters.add(newParams); return newParams; } } /** * Adds negated parameters, by default with the "and" connective. These paremeters will be grouped in parentheses * in the generated query and negated, e.g. ... not (exp1 and exp2) ... * @return Negated sub paremters. */ public Parameters addNegatedParameters() { Parameters newParams = new Parameters(alias, AND, queryParamCounter); negatedParameters.add(newParams); return newParams; } public void addWhere(String left, String op, String right) { addWhere(left, true, op, right, true); } /** * Adds <code>IS NULL</code> restriction. * @param propertyName Property name. * @param addAlias Positive if an alias to property name shall be added. */ public void addNullRestriction(String propertyName, boolean addAlias) { addWhere(propertyName, addAlias, "is", "null", false); } /** * Adds <code>IS NOT NULL</code> restriction. * @param propertyName Property name. * @param addAlias Positive if an alias to property name shall be added. */ public void addNotNullRestriction(String propertyName, boolean addAlias) { addWhere(propertyName, addAlias, "is not", "null", false); } public void addWhere(String left, boolean addAliasLeft, String op, String right, boolean addAliasRight) { StringBuilder expression = new StringBuilder(); if (addAliasLeft) { expression.append(alias).append("."); } expression.append(left); expression.append(" ").append(op).append(" "); if (addAliasRight) { expression.append(alias).append("."); } expression.append(right); expressions.add(expression.toString()); } public void addWhereWithParam(String left, String op, Object paramValue) { addWhereWithParam(left, true, op, paramValue); } public void addWhereWithParam(String left, boolean addAlias, String op, Object paramValue) { String paramName = generateQueryParam(); localQueryParamValues.put(paramName, paramValue); addWhereWithNamedParam(left, addAlias, op, paramName); } public void addWhereWithNamedParam(String left, String op, String paramName) { addWhereWithNamedParam(left, true, op, paramName); } public void addWhereWithNamedParam(String left, boolean addAlias, String op, String paramName) { StringBuilder expression = new StringBuilder(); if (addAlias) { expression.append(alias).append("."); } expression.append(left); expression.append(" ").append(op).append(" "); expression.append(":").append(paramName); expressions.add(expression.toString()); } public void addWhereWithParams(String left, String opStart, Object[] paramValues, String opEnd) { StringBuilder expression = new StringBuilder(); expression.append(alias).append(".").append(left).append(" ").append(opStart); for (int i=0; i<paramValues.length; i++) { Object paramValue = paramValues[i]; String paramName = generateQueryParam(); localQueryParamValues.put(paramName, paramValue); expression.append(":").append(paramName); if (i != paramValues.length-1) { expression.append(", "); } } expression.append(opEnd); expressions.add(expression.toString()); } public void addWhere(String left, String op, QueryBuilder right) { addWhere(left, true, op, right); } public void addWhere(String left, boolean addAlias, String op, QueryBuilder right) { StringBuilder expression = new StringBuilder(); if (addAlias) { expression.append(alias).append("."); } expression.append(left); expression.append(" ").append(op).append(" "); expression.append("("); right.build(expression, localQueryParamValues); expression.append(")"); expressions.add(expression.toString()); } private void append(StringBuilder sb, String toAppend, MutableBoolean isFirst) { if (!isFirst.isSet()) { sb.append(" ").append(connective).append(" "); } sb.append(toAppend); isFirst.unset(); } boolean isEmpty() { return expressions.size() == 0 && subParameters.size() == 0 && negatedParameters.size() == 0; } void build(StringBuilder sb, Map<String, Object> queryParamValues) { MutableBoolean isFirst = new MutableBoolean(true); for (String expression : expressions) { append(sb, expression, isFirst); } for (Parameters sub : subParameters) { if (!subParameters.isEmpty()) { append(sb, "(", isFirst); sub.build(sb, queryParamValues); sb.append(")"); } } for (Parameters negated : negatedParameters) { if (!negatedParameters.isEmpty()) { append(sb, "not (", isFirst); negated.build(sb, queryParamValues); sb.append(")"); } } queryParamValues.putAll(localQueryParamValues); } }