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.util;
029:
030: import java.util.ArrayList;
031: import java.util.List;
032: import java.util.StringTokenizer;
033:
034: import net.sf.jasperreports.engine.JRQueryChunk;
035:
036: /**
037: * Report query parser.
038: *
039: * @author Lucian Chirita (lucianc@users.sourceforge.net)
040: * @version $Id: JRQueryParser.java 1683 2007-03-29 16:04:15Z lucianc $
041: */
042: public class JRQueryParser {
043:
044: protected static final String CLAUSE_TOKEN_SEPARATOR = ",";
045:
046: private static final JRQueryParser singleton = new JRQueryParser();
047:
048: /**
049: * Returns a query parser instance.
050: *
051: * @return a query parser instance
052: */
053: public static JRQueryParser instance() {
054: return singleton;
055: }
056:
057: /**
058: * Parses a report query.
059: *
060: * @param text the query text
061: * @param chunkHandler a handler that will be asked to handle parsed query chunks
062: */
063: public void parse(String text, JRQueryChunkHandler chunkHandler) {
064: if (text != null) {
065: StringBuffer textChunk = new StringBuffer();
066:
067: StringTokenizer tkzer = new StringTokenizer(text, "$", true);
068: boolean wasDelim = false;
069: while (tkzer.hasMoreTokens()) {
070: String token = tkzer.nextToken();
071:
072: if (token.equals("$")) {
073: if (wasDelim) {
074: textChunk.append("$");
075: }
076:
077: wasDelim = true;
078: } else {
079: if (token.startsWith("P{") && wasDelim) {
080: int end = token.indexOf('}');
081: if (end > 0) {
082: if (textChunk.length() > 0) {
083: chunkHandler.handleTextChunk(textChunk
084: .toString());
085: }
086: String parameterChunk = token.substring(2,
087: end);
088: chunkHandler
089: .handleParameterChunk(parameterChunk);
090: textChunk = new StringBuffer(token
091: .substring(end + 1));
092: } else {
093: if (wasDelim) {
094: textChunk.append("$");
095: }
096: textChunk.append(token);
097: }
098: } else if (token.startsWith("P!{") && wasDelim) {
099: int end = token.indexOf('}');
100: if (end > 0) {
101: if (textChunk.length() > 0) {
102: chunkHandler.handleTextChunk(textChunk
103: .toString());
104: }
105: String parameterClauseChunk = token
106: .substring(3, end);
107: chunkHandler
108: .handleParameterClauseChunk(parameterClauseChunk);
109: textChunk = new StringBuffer(token
110: .substring(end + 1));
111: } else {
112: if (wasDelim) {
113: textChunk.append("$");
114: }
115: textChunk.append(token);
116: }
117: } else if (token.startsWith("X{") && wasDelim) {
118: int end = token.indexOf('}');
119: if (end > 0) {
120: if (textChunk.length() > 0) {
121: chunkHandler.handleTextChunk(textChunk
122: .toString());
123: }
124: String clauseChunk = token
125: .substring(2, end);
126: String[] tokens = parseClause(clauseChunk);
127: chunkHandler.handleClauseChunk(tokens);
128: textChunk = new StringBuffer(token
129: .substring(end + 1));
130: } else {
131: if (wasDelim) {
132: textChunk.append("$");
133: }
134: textChunk.append(token);
135: }
136: } else {
137: if (wasDelim) {
138: textChunk.append("$");
139: }
140: textChunk.append(token);
141: }
142:
143: wasDelim = false;
144: }
145: }
146: if (wasDelim) {
147: textChunk.append("$");
148: }
149: if (textChunk.length() > 0) {
150: chunkHandler.handleTextChunk(textChunk.toString());
151: }
152: }
153: }
154:
155: protected String[] parseClause(String clauseChunk) {
156: List tokens = new ArrayList();
157:
158: boolean wasClauseToken = false;
159: StringTokenizer tokenizer = new StringTokenizer(clauseChunk,
160: CLAUSE_TOKEN_SEPARATOR, true);
161: while (tokenizer.hasMoreTokens()) {
162: String token = tokenizer.nextToken();
163: if (token.equals(CLAUSE_TOKEN_SEPARATOR)) {
164: if (!wasClauseToken) {
165: tokens.add("");
166: }
167: wasClauseToken = false;
168: } else {
169: tokens.add(token);
170: wasClauseToken = true;
171: }
172: }
173: if (!wasClauseToken) {
174: tokens.add("");
175: }
176:
177: return (String[]) tokens.toArray(new String[tokens.size()]);
178: }
179:
180: /**
181: * (Re)creates the query text from a list of chunks.
182: *
183: * @param chunks the chunks
184: * @return the recreated query text
185: */
186: public String asText(JRQueryChunk[] chunks) {
187: String text = "";
188:
189: if (chunks != null && chunks.length > 0) {
190: StringBuffer sbuffer = new StringBuffer();
191:
192: for (int i = 0; i < chunks.length; i++) {
193: JRQueryChunk queryChunk = chunks[i];
194: switch (queryChunk.getType()) {
195: case JRQueryChunk.TYPE_PARAMETER: {
196: sbuffer.append("$P{");
197: sbuffer.append(queryChunk.getText());
198: sbuffer.append("}");
199: break;
200: }
201: case JRQueryChunk.TYPE_PARAMETER_CLAUSE: {
202: sbuffer.append("$P!{");
203: sbuffer.append(queryChunk.getText());
204: sbuffer.append("}");
205: break;
206: }
207: case JRQueryChunk.TYPE_CLAUSE_TOKENS: {
208: sbuffer.append("$X{");
209: sbuffer.append(queryChunk.getText());
210: sbuffer.append("}");
211: break;
212: }
213: case JRQueryChunk.TYPE_TEXT:
214: default: {
215: sbuffer.append(queryChunk.getText());
216: break;
217: }
218: }
219: }
220:
221: text = sbuffer.toString();
222: }
223:
224: return text;
225: }
226:
227: /**
228: * (Re)constructs a query clause chunk from the chunk tokens.
229: *
230: * @param tokens the chunk tokens
231: * @return the reconstructed query clause chunk
232: * @see JRQueryChunk#TYPE_CLAUSE_TOKENS
233: */
234: public String asClauseText(String[] tokens) {
235: StringBuffer sb = new StringBuffer();
236: if (tokens != null && tokens.length > 0) {
237: for (int i = 0; i < tokens.length; i++) {
238: if (i > 0) {
239: sb.append(',');
240: }
241: String token = tokens[i];
242: if (token != null) {
243: sb.append(token);
244: }
245: }
246: }
247: return sb.toString();
248: }
249:
250: }
|