/*
* SqlStatement
*
* Copyright (C) 2010 Jaroslav Merxbauer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package notwa.sql;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
/**
* This <code>class</code> represents a single parameter placeholders statement
* present in the SQL template.
* This <code>SqlStatement</code> should be than provided with the parameter collection
* and it will produce the built SQL to be a part of the related SQL template.
*
* @author Jaroslav Merxbauer
* @version %I% %G%
*/
public class SqlStatement {
private String connectWith;
private HashMap<String,String> mappings;
private StringBuilder statement;
/**
* The sole, parameter-less, constructor, initializing the class members.
*/
public SqlStatement() {
statement = new StringBuilder();
mappings = new HashMap<String, String>();
}
/**
* Accepts the single raw statement factored out from the sql template and
* brings him into the object look.
* <p>It, at first, recognizes, how the given statement should be related with
* its surroundings (It is the opening WHERE? Or continues it as AND? Or or?)
* Than it creates parameter name to column name mappings, to be able to compile
* the final result which should replace the parameter name with the actual
* value found within the <code>SqlParameter</code>.</p>
*
* @param rawStatement The raw statement.
* @return <code>true</code> if the parsing process completes successfully,
* <code>false</code> otherwise.
*/
public boolean parse(String rawStatement) {
connectWith = rawStatement.substring(rawStatement.indexOf("=") + 1, rawStatement.indexOf(";")).trim();
try {
StringTokenizer relations = new StringTokenizer(rawStatement, "{}");
relations.nextToken(); // skip the first token which is obviously the statement header parsed before
while (relations.hasMoreTokens()) {
String column = null;
String parameter = null;
StringTokenizer relation = new StringTokenizer(relations.nextToken(), ";=");
while (relation.hasMoreTokens()) {
String token = relation.nextToken();
if (token.equals("column")) {
column = relation.nextToken().trim();
} else if (token.equals("parameter")) {
parameter = relation.nextToken().trim();
}
if (column != null && parameter != null) {
mappings.put(parameter, column);
column = null;
parameter = null;
}
}
}
} catch (Exception ex) {
Logger.getLogger(this.getClass()).debug("Unable to parse the SqlStatement pattern!", ex);
return false;
}
return true;
}
/**
* Returns the final SQL Query result built from the statement given at the
* begining by mixing it with the actual <code>SqlParameter</code>s.
*
* @return The SQL Query part of the parent sql template.
*/
public String compileStatement() {
return statement.toString();
}
/**
* Appends the given <code>SqlParameter</code> to this <code>SqlStatement</code>
* itteratively building the resulting SQL part.
*
* @param parameter The parameter where the value and the actual relation will
* be found.
*/
public void applyFilter(SqlFilter filter) {
String builtFilter = filter.formatForSql();
/**
* Make sure there is any filter to append, otherwise don't dare to append
* connection keyword! Standalon where doesn't make SQL Server happy ...
*/
if (builtFilter.isEmpty()) {
return;
}
TemplateResolver resolver = new TemplateResolver(this.mappings);
statement.append(connectWith);
statement.append(" ");
statement.append(resolver.resolve(builtFilter));
}
}