net.sf.jasperreports.engine.util.JRQueryParser Maven / Gradle / Ivy
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.util;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRQueryChunk;
import net.sf.jasperreports.engine.JRRuntimeException;
/**
* Report query parser.
*
* @author Lucian Chirita ([email protected])
*/
public class JRQueryParser
{
public static final String EXCEPTION_MESSAGE_KEY_TOKEN_SEPARATORS_NOT_CONFIGURED = "util.query.token.separators.not.configured";
private static final JRQueryParser singleton = new JRQueryParser();
/**
* Returns a query parser instance.
*
* @return a query parser instance
*/
public static JRQueryParser instance()
{
return singleton;
}
/**
* Parses a report query.
*
* @param text the query text
* @param chunkHandler a handler that will be asked to handle parsed query chunks
*/
public void parse(String text, JRQueryChunkHandler chunkHandler)
{
if (text != null)
{
StringBuilder textChunk = new StringBuilder();
StringTokenizer tkzer = new StringTokenizer(text, "$", true);
boolean wasDelim = false;
while (tkzer.hasMoreTokens())
{
String token = tkzer.nextToken();
if (token.equals("$"))
{
if (wasDelim)
{
textChunk.append("$");
}
wasDelim = true;
}
else
{
if ( token.startsWith("P{") && wasDelim )
{
int end = token.indexOf('}');
if (end > 0)
{
if (textChunk.length() > 0)
{
chunkHandler.handleTextChunk(textChunk.toString());
}
String parameterChunk = token.substring(2, end);
chunkHandler.handleParameterChunk(parameterChunk);
textChunk = new StringBuilder(token.substring(end + 1));
}
else
{
if (wasDelim)
{
textChunk.append("$");
}
textChunk.append(token);
}
}
else if ( token.startsWith("P!{") && wasDelim )
{
int end = token.indexOf('}');
if (end > 0)
{
if (textChunk.length() > 0)
{
chunkHandler.handleTextChunk(textChunk.toString());
}
String parameterClauseChunk = token.substring(3, end);
chunkHandler.handleParameterClauseChunk(parameterClauseChunk);
textChunk = new StringBuilder(token.substring(end + 1));
}
else
{
if (wasDelim)
{
textChunk.append("$");
}
textChunk.append(token);
}
}
else if ( token.startsWith("X{") && wasDelim )
{
int end = token.indexOf('}');
if (end > 0)
{
if (textChunk.length() > 0)
{
chunkHandler.handleTextChunk(textChunk.toString());
}
String clauseChunk = token.substring(2, end);
parseClause(chunkHandler, clauseChunk);
textChunk = new StringBuilder(token.substring(end + 1));
}
else
{
if (wasDelim)
{
textChunk.append("$");
}
textChunk.append(token);
}
}
else
{
if (wasDelim)
{
textChunk.append("$");
}
textChunk.append(token);
}
wasDelim = false;
}
}
if (wasDelim)
{
textChunk.append("$");
}
if (textChunk.length() > 0)
{
chunkHandler.handleTextChunk(textChunk.toString());
}
}
}
protected void parseClause(JRQueryChunkHandler chunkHandler, String clauseChunk)
{
List tokens = new ArrayList();
boolean wasClauseToken = false;
char separator = determineClauseTokenSeparator(clauseChunk);
String separatorString = String.valueOf(separator);
StringTokenizer tokenizer = new StringTokenizer(clauseChunk, separatorString, true);
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (token.equals(separatorString))
{
if (!wasClauseToken)
{
tokens.add("");
}
wasClauseToken = false;
}
else
{
tokens.add(token);
wasClauseToken = true;
}
}
if (!wasClauseToken)
{
tokens.add("");
}
String[] tokensArray = tokens.toArray(new String[tokens.size()]);
chunkHandler.handleClauseChunk(tokensArray, separator);
}
protected char determineClauseTokenSeparator(String clauseChunk)
{
String allSeparators = getTokenSeparators();
if (allSeparators == null || allSeparators.length() == 0)
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_TOKEN_SEPARATORS_NOT_CONFIGURED,
(Object[])null);
}
int firstSepIdx = 0;//if none of the separators are found in the text, return the first separator
int clauseLenght = clauseChunk.length();
for (int idx = 0; idx < clauseLenght; ++idx)
{
int sepIdx = allSeparators.indexOf(clauseChunk.charAt(idx));
if (sepIdx >= 0)
{
firstSepIdx = sepIdx;
break;
}
}
return allSeparators.charAt(firstSepIdx);
}
protected String getTokenSeparators()
{
return JRPropertiesUtil.getInstance(DefaultJasperReportsContext.getInstance()).getProperty(JRQueryChunk.PROPERTY_CHUNK_TOKEN_SEPARATOR);
}
/**
* (Re)creates the query text from a list of chunks.
*
* @param chunks the chunks
* @return the recreated query text
*/
public String asText(JRQueryChunk[] chunks)
{
String text = "";
if (chunks != null && chunks.length > 0)
{
StringBuilder sb = new StringBuilder();
for(int i = 0; i < chunks.length; i++)
{
JRQueryChunk queryChunk = chunks[i];
switch(queryChunk.getType())
{
case JRQueryChunk.TYPE_PARAMETER :
{
sb.append("$P{");
sb.append( queryChunk.getText() );
sb.append("}");
break;
}
case JRQueryChunk.TYPE_PARAMETER_CLAUSE :
{
sb.append("$P!{");
sb.append( queryChunk.getText() );
sb.append("}");
break;
}
case JRQueryChunk.TYPE_CLAUSE_TOKENS :
{
sb.append("$X{");
sb.append(queryChunk.getText());
sb.append("}");
break;
}
case JRQueryChunk.TYPE_TEXT :
default :
{
sb.append( queryChunk.getText() );
break;
}
}
}
text = sb.toString();
}
return text;
}
/**
* (Re)constructs a query clause chunk from the chunk tokens.
*
* @param tokens the chunk tokens
* @return the reconstructed query clause chunk
* @see JRQueryChunk#TYPE_CLAUSE_TOKENS
* @deprecated Replaced by {@link #asClauseText(String[], Character)}.
*/
public String asClauseText(String[] tokens)
{
return asClauseText(tokens, null);
}
/**
* (Re)constructs a query clause chunk from the chunk tokens.
*
* @param tokens the chunk tokens
* @param separator the chunk tokens separator character
* @return the reconstructed query clause chunk
* @see JRQueryChunk#TYPE_CLAUSE_TOKENS
*/
public String asClauseText(String[] tokens, Character separator)
{
if (separator == null)
{
separator = defaultTokenSeparator();
}
StringBuilder sb = new StringBuilder();
if (tokens != null && tokens.length > 0)
{
for (int i = 0; i < tokens.length; i++)
{
if (i > 0)
{
sb.append(separator);
}
String token = tokens[i];
if (token != null)
{
sb.append(token);
}
}
}
return sb.toString();
}
protected char defaultTokenSeparator()
{
String tokenSeparators = getTokenSeparators();
return tokenSeparators == null || tokenSeparators.isEmpty()
? ',' // would not normally happen, determineClauseTokenSeparator throws exception
: tokenSeparators.charAt(0);
}
}