001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine.query;
029:
030: import java.lang.reflect.Array;
031: import java.util.Collection;
032:
033: import net.sf.jasperreports.engine.JRRuntimeException;
034:
035: /**
036: * Base (NOT) IN clause function for SQL queries.
037: *
038: * @author Lucian Chirita (lucianc@users.sourceforge.net)
039: * @version $Id: JRSqlAbstractInClause.java 1683 2007-03-29 16:04:15Z lucianc $
040: */
041: public abstract class JRSqlAbstractInClause implements JRClauseFunction {
042:
043: protected static final int POSITION_DB_COLUMN = 1;
044: protected static final int POSITION_PARAMETER = 2;
045:
046: protected static final String CLAUSE_TRUISM = "0 = 0";
047:
048: protected JRSqlAbstractInClause() {
049: }
050:
051: /**
052: * Creates a (NOT) IN SQL clause.
053: *
054: * <p>
055: * The function expects two clause tokens (after the ID token):
056: * <ul>
057: * <li>The first token is the SQL column to be used in the clause.</li>
058: * <li>The second token is the name of the report parameter that contains the value list.
059: * <br/>
060: * The value of this parameter has to be an array, a <code>java.util.Collection</code>
061: * or <code>null</code>.
062: * </li>
063: * </p>
064: *
065: * <p>
066: * The function constructs a <code>column [NOT] IN (?, ?, .., ?)</code> clause.
067: * If the values list is null or empty, the function generates a SQL clause that
068: * will always evaluate to true (e.g. <code>0 = 0</code>).
069: * </p>
070: */
071: public void apply(JRClauseTokens clauseTokens,
072: JRQueryClauseContext queryContext) {
073: String col = clauseTokens.getToken(POSITION_DB_COLUMN);
074: String param = clauseTokens.getToken(POSITION_PARAMETER);
075:
076: if (col == null) {
077: throw new JRRuntimeException(
078: "SQL IN clause missing DB column token");
079: }
080:
081: if (param == null) {
082: throw new JRRuntimeException(
083: "SQL IN clause missing parameter token");
084: }
085:
086: StringBuffer sbuffer = queryContext.queryBuffer();
087:
088: Object paramValue = queryContext.getValueParameter(param)
089: .getValue();
090: if (paramValue == null) {
091: handleNoValues(queryContext);
092: } else {
093: int count = valuesCount(param, paramValue);
094: if (count == 0) {
095: handleNoValues(queryContext);
096: } else {
097: sbuffer.append(col);
098: sbuffer.append(' ');
099: appendInOperator(sbuffer);
100: sbuffer.append(' ');
101: sbuffer.append('(');
102: for (int idx = 0; idx < count; ++idx) {
103: if (idx > 0) {
104: sbuffer.append(", ");
105: }
106: sbuffer.append('?');
107: }
108: sbuffer.append(')');
109:
110: queryContext.addQueryMultiParameters(param, count);
111: }
112: }
113: }
114:
115: protected void handleNoValues(JRQueryClauseContext queryContext) {
116: queryContext.queryBuffer().append(CLAUSE_TRUISM);
117: }
118:
119: protected int valuesCount(String paramName, Object paramValue) {
120: int count;
121: if (paramValue.getClass().isArray()) {
122: count = Array.getLength(paramValue);
123: } else if (paramValue instanceof Collection) {
124: count = ((Collection) paramValue).size();
125: } else {
126: throw new JRRuntimeException(
127: "Invalid type + "
128: + paramValue.getClass().getName()
129: + " for parameter "
130: + paramName
131: + " used in an IN clause; the value must be an array or a collection.");
132: }
133: return count;
134: }
135:
136: protected abstract void appendInOperator(StringBuffer sBuffer);
137: }
|