/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source: /cvsroot/slrp/common/com.ibm.adtech.jdbc.utils/src/com/ibm/adtech/jdbc/utils/opgen/RdbStatement.java,v $
* Created by: Joe Betz
* Created on: 9/30/2005
* Revision: $Id: RdbStatement.java 176 2007-07-31 14:22:30Z mroy $
*
* Contributors:
* IBM Corporation - initial API and implementation
* Cambridge Semantics Incorporated - Fork to Anzo
*******************************************************************************/
package org.openanzo.jdbc.opgen;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Provides XML deserialization and accessors for rdf statements (SQL, DDL, etc.) for use in composing PreparedStatementProvider compatable .sql files and
* generating java rdf statement wrappers.
*
* @author Joe Betz
*
*/
public class RdbStatement {
static final String element = "preparedstatement";
static final String nameAttribute = "name";
static final String inputsAttribute = "inputs";
static final String outputsAttribute = "outputs";
static final String resultsAttribute = "results";
static final String templateParamsAttribute = "templateParams";
static final String PREPARE = "prepare";
String name;
String sqlPackageName;
String sql;
List<Parameter> inputs;
List<Parameter> outputs;
List<Parameter> templateParams;
Result results;
boolean prepare = true;
/**
* Create a new RdbStatement
*
* @param sqlPackageName
* name of package
* @param name
* name of prepared statement
* @param sql
* SQL query text
* @param inputs
* inputs to the query
* @param outputs
* outputs expected from the query
* @param templateParams
* set of template parameters for the query
* @param results
* results type for query
* @param prepare
* true if statement should be prepared, otherwise use callable statement
*/
public RdbStatement(String sqlPackageName, String name, String sql, List<Parameter> inputs, List<Parameter> outputs, List<Parameter> templateParams, Result results, boolean prepare) {
this.sqlPackageName = sqlPackageName;
this.name = name;
this.sql = sql;
this.inputs = inputs;
this.outputs = outputs;
this.templateParams = templateParams;
this.results = results;
this.prepare = prepare;
initialize();
}
// make a best effort to get the text within a node.
private static String getText(Node n) {
NodeList nl = n.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n2 = nl.item(i);
if (n2.getNodeType() == Node.TEXT_NODE) {
String text = n2.getNodeValue();
if (text.trim().length() > 0) {
return text;
}
} else if (n2.getNodeType() == Node.CDATA_SECTION_NODE) {
return n2.getNodeValue();
} else {
return getText(n);
}
}
return null;
}
private static final Pattern pattern = Pattern.compile("(\\s+)");
/**
* Create a new RdbStatement from the given XML emement data
*
* @param sqlPackageName
* package name for statement
* @param xmlElement
* XML element containing data
*/
public RdbStatement(String sqlPackageName, Element xmlElement) {
this.sqlPackageName = sqlPackageName;
if (!xmlElement.getNodeName().equals(element))
throw new InvalidParameterException("XML element not of type '" + element + "'");
sql = getText(xmlElement);
if (sql == null)
throw new InvalidParameterException("Node has no text: " + xmlElement);
if (sql.trim().equals("EMPTY")) {
sql = "";
}
Node nameNode = xmlElement.getAttributes().getNamedItem(nameAttribute);
if (nameNode == null)
throw new InvalidParameterException("'" + nameAttribute + "' is a required attribute for '" + element + "' element.");
name = nameNode.getNodeValue();
Node inputsNode = xmlElement.getAttributes().getNamedItem(inputsAttribute);
if (inputsNode != null) {
String paramList = inputsNode.getNodeValue();
inputs = getParams(paramList);
} else {
inputs = new ArrayList<Parameter>(0);
}
Node templateParamsNode = xmlElement.getAttributes().getNamedItem(templateParamsAttribute);
if (templateParamsNode != null) {
String paramList = templateParamsNode.getNodeValue();
templateParams = getParams(paramList);
} else {
templateParams = new ArrayList<Parameter>(0);
}
Node outputsNode = xmlElement.getAttributes().getNamedItem(outputsAttribute);
if (outputsNode != null) {
String paramList = outputsNode.getNodeValue();
outputs = getParams(paramList);
} else {
outputs = new ArrayList<Parameter>(0);
}
Node resultsNode = xmlElement.getAttributes().getNamedItem(resultsAttribute);
if (resultsNode != null) {
results = Result.getResultsEnum(resultsNode);
}
Node dpNode = xmlElement.getAttributes().getNamedItem(PREPARE);
if (dpNode != null) {
prepare = Boolean.parseBoolean(dpNode.getNodeValue());
}
initialize();
}
private void initialize() {
if (results == null)
results = Result.NONE;
if (results == Result.ROW && outputs.size() <= 1)
throw new InvalidParameterException(name + ": ROW return type not allowed when there is zero or one outputs, use VALUE or ITERATOR instead.");
if (results == Result.COUNTER && outputs.size() > 0)
throw new InvalidParameterException(name + ": COUNTER return type not allowed when there is one our more outputs, use VALUE,ROW or ITERATOR instead.");
}
private static List<Parameter> getParams(String paramList) {
List<Parameter> list = new ArrayList<Parameter>();
if (paramList.length() > 0) {
String[] params = paramList.split(",");
for (int i = 0; i < params.length; i++) {
String param = params[i].trim();
String[] vals = pattern.split(param);
String type = vals[0];
String name = vals[1];
boolean canBeNull = !type.startsWith("+");
if (!canBeNull) {
type = type.substring(1);
}
ParameterType pType = ParameterType.valueOf(type);
if (pType != null) {
list.add(new Parameter(name, pType, canBeNull));
} else {
throw new RuntimeException(type + " type is invalid:" + paramList);
}
}
}
return list;
}
/**
* Get the name of the statement
*
* @return the name of the statement
*/
public String getName() {
return name;
}
/**
* Get the qualified name of the statement
*
* @return the qualified name of the statement
*/
public String getQualifiedName() {
if (sqlPackageName != "") {
return sqlPackageName + "." + name;
}
return name;
}
/**
* Capitalize the name of the statement
*
* @return capitalized name of the statement
*/
public String capitalizedName() {
return org.apache.commons.lang.StringUtils.capitalize(name);
}
/**
* Return if the provided string is a primitive value type
*
* @param string
* type of value for which to determine primitive nature
* @return if the provided string is a primitive value type
*/
public static boolean isPrimitive(String string) {
return string.equals("short") || string.equals("byte") || string.equals("boolean") || string.equals("long") || string.equals("int") || string.equals("char");
}
/**
* Get the SQL query text for this statement
*
* @return the SQL query text for this statement
*/
public String getSql() {
return sql;
}
/**
* @return the dontPrepare
*/
public boolean getPrepare() {
return prepare;
}
/**
* Get the input parameters for this statement
*
* @return the input parameters for this statement
*/
public List<Parameter> getInputs() {
return inputs;
}
/**
* Get the output parameters for this statement
*
* @return the output parameters for this statement
*/
public List<Parameter> getOutputs() {
return outputs;
}
/**
* Get the template parameters for this statement
*
* @return the template parameters for this statement
*/
public List<Parameter> getParams() {
return templateParams;
}
/**
* Get the return type for this statement
*
* @return the return type for this statement
*/
public String getReturnType() {
if (results == Result.NONE) {
return "void";
} else if (results == Result.ITERATOR) {
return "org.openanzo.jdbc.utils.ClosableIterator";
} else if (results == Result.ROW) {
return capitalizedName() + "Result";
} else if (results == Result.VALUE) {
return getValueReturnType(false);
} else if (results == Result.COUNTER) {
return "int";
} else if (results == Result.IDENTITY) {
return "Long";
}
throw new InvalidParameterException("Not a valid enumeration value: " + results.getValue());
}
/**
* Determine if this statement has input parameters
*
* @return if this statement has input parameters
*/
public boolean hasInputParamType() {
return (inputs.size() > 1);
}
/**
* Get the Interface name for this statement's parameters
*
* @return the Interface name for this statements parameters
*/
public String getInputParamInterface() {
return capitalizedName() + "Params";
}
/**
* Get the Implementation name for this statement's parameters
*
* @return the Implementation name for this statement's parameters
*/
public String getInputParamImpl() {
return capitalizedName() + "ParamsImpl";
}
/**
* Get the interface name for this statement's results
*
* @return the interface name for this statement's results
*/
public String getResultsInterface() {
return capitalizedName() + "Result";
}
/**
* Get the implementation name for this statement's results
*
* @return the implementation name for this statement's results
*/
public String getResultsImpl() {
return capitalizedName() + "ResultImpl";
}
String inputParamSigniture = null;
/**
* Get the full string representing for the input parameters to this statement
*
* @return the full string representing for the input parameters to this statement
*/
public String getInputParamSigniture() {
if (inputParamSigniture == null) {
inputParamSigniture = buildSignitureString(inputs);
}
return inputParamSigniture;
}
String inputExceptionSignature = null;
/**
* Get the full string representing for the input parameters to this statement
*
* @return the full string representing for the input parameters to this statement
*/
public String getInputExceptionSignature() {
if (inputExceptionSignature == null) {
inputExceptionSignature = buildExceptionSignitureString(inputs);
}
return inputExceptionSignature;
}
String templateExceptionSignature = null;
/**
* Get the full string representing for the input parameters to this statement
*
* @return the full string representing for the input parameters to this statement
*/
public String getTemplateExceptionSignature() {
if (templateExceptionSignature == null) {
templateExceptionSignature = buildExceptionSignitureString(templateParams);
}
return templateExceptionSignature;
}
String inputParams = null;
/**
* Get the string representing for the input parameters to this statement
*
* @return the string representing for the input parameters to this statement
*/
public String getInputParams() {
if (inputParams == null) {
inputParams = buildParamString(inputs);
}
return inputParams;
}
/**
* Return true if this statement has template parameters
*
* @return true if this statement has template parameters
*/
public boolean hasTemplateParams() {
return templateParams.size() > 0;
}
String templateParamSigniture = null;
/**
* Get the full string representing for the template parameters to this statement
*
* @return the full string representing for the template parameters to this statement
*/
public String getTemplateParamSigniture() {
if (templateParamSigniture == null) {
templateParamSigniture = buildSignitureString(templateParams);
}
return templateParamSigniture;
}
String templateParamsString = null;
/**
* Get the string representing for the template parameters to this statement
*
* @return the string representing for the template parameters to this statement
*/
public String getTemplateParams() {
if (templateParamsString == null) {
templateParamsString = buildParamString(templateParams);
}
return templateParamsString;
}
String templateParamsJavadocString = null;
/**
* Get the javadoc representing for the template parameters to this statement
*
* @return the javadoc representing for the template parameters to this statement
*/
public String getTemplateParamsJavadoc() {
if (templateParamsJavadocString == null) {
templateParamsJavadocString = buildJavadocParamString(templateParams);
}
return templateParamsJavadocString;
}
String inputParamsJavadocString = null;
/**
* Get the javadoc representing for the input parameters to this statement
*
* @return the javadoc representing for the input parameters to this statement
*/
public String getInputParamsJavadoc() {
if (inputParamsJavadocString == null) {
inputParamsJavadocString = buildJavadocParamString(inputs);
}
return inputParamsJavadocString;
}
/**
* Return true if this statement has input parameters
*
* @return true if this statement has input parameters
*/
public boolean hasInputParams() {
return inputs.size() > 0;
}
private String buildParamString(List<Parameter> params) {
StringBuilder inputParamsBuf = new StringBuilder();
for (Iterator<Parameter> inIter = params.iterator(); inIter.hasNext();) {
Parameter param = inIter.next();
inputParamsBuf.append(param.getName());
if (inIter.hasNext()) {
inputParamsBuf.append(", ");
}
}
return inputParamsBuf.toString();
}
private String buildJavadocParamString(List<Parameter> params) {
StringBuilder inputParamsBuf = new StringBuilder();
for (Iterator<Parameter> inIter = params.iterator(); inIter.hasNext();) {
Parameter param = inIter.next();
inputParamsBuf.append("\n *@param ");
inputParamsBuf.append(param.getName());
inputParamsBuf.append(" template parameter");
}
return inputParamsBuf.toString();
}
private String buildSignitureString(List<Parameter> params) {
StringBuilder inputParamSignitureBuf = new StringBuilder();
for (Iterator<Parameter> inIter = params.iterator(); inIter.hasNext();) {
Parameter param = inIter.next();
inputParamSignitureBuf.append(param.getJavaType(false));
inputParamSignitureBuf.append(" ");
inputParamSignitureBuf.append(param.getName());
if (inIter.hasNext()) {
inputParamSignitureBuf.append(", ");
}
}
return inputParamSignitureBuf.toString();
}
private String buildExceptionSignitureString(List<Parameter> params) {
StringBuilder inputParamSignitureBuf = new StringBuilder();
for (Iterator<Parameter> inIter = params.iterator(); inIter.hasNext();) {
Parameter param = inIter.next();
if (param.isPrimitive()) {
inputParamSignitureBuf.append("\"" + param.getName() + "=\"+(" + param.getName() + ")");
} else {
inputParamSignitureBuf.append("\"" + param.getName() + "=\"+((");
inputParamSignitureBuf.append(param.getName());
inputParamSignitureBuf.append("!=null)?");
inputParamSignitureBuf.append(param.getName());
inputParamSignitureBuf.append(".toString():\"null\")");
}
if (inIter.hasNext()) {
inputParamSignitureBuf.append(" + \",\" +");
}
}
return inputParamSignitureBuf.toString();
}
/**
* Return true if this statement expects results
*
* @return true if this statement expects results
*/
public boolean hasReturn() {
return !getReturnType().equals("void");
}
/**
* Get the return type for this statement
*
* @param box
* should this type be boxed
* @return the return type for this statement
*/
public String getValueReturnType(boolean box) {
Parameter param = getFirstOutput();
return param.getJavaType(box);
}
/**
* get the resultset property
*
* @return resultset property
*/
public String getResultSetProperty() {
Parameter param = getFirstOutput();
return param.getResultSetProperty();
}
/**
* Get the javatype for this statement
*
* @param box
* should the type be boxed
* @return the javatype for this statement
*/
public String getJavaType(boolean box) {
return getFirstOutput().getJavaType(box);
}
/**
* Get the jdbc type for this statement
*
* @param box
* should the type be boxed
*
* @return the jdbc type for this statement
*/
public String getJdbcType(boolean box) {
Parameter firstOutput = getFirstOutput();
return firstOutput.getJdbcType();
}
/**
*
* @return true if the result type is primitive
*/
public boolean isPrimitive() {
return getFirstOutput().isPrimitive();
}
private Parameter getFirstOutput() {
Iterator<Parameter> iter = outputs.iterator();
if (!iter.hasNext())
throw new InvalidParameterException("No outputs specified");
return iter.next();
}
/**
* Get the result object for the statement
*
* @return the result object for the statement
*/
public Result getResults() {
return results;
}
/**
* Class the contains an input/output/template parameter
*/
public static class Parameter {
static HashMap<String, String> toPrimitive = new HashMap<String, String>();
static {
toPrimitive.put("Long", "long");
toPrimitive.put("Integer", "int");
toPrimitive.put("Byte", "byte");
toPrimitive.put("Character", "char");
toPrimitive.put("Short", "short");
toPrimitive.put("Float", "float");
toPrimitive.put("Boolean", "boolean");
toPrimitive.put("Double", "double");
}
final String name;
final ParameterType type;
final boolean canBeNull;
/**
* Create a new parameter with the given type
*
* @param name
* name of the parameter
* @param type
* type of the parameter
* @param canBeNull
* can this parameter take null values
*/
public Parameter(String name, ParameterType type, boolean canBeNull) {
this.name = name;
this.type = type;
this.canBeNull = canBeNull;
}
/**
* Get the name of the parameter
*
* @return the name of the parameter
*/
public String getName() {
return name;
}
/**
* Get the JavaType for the parameter
*
* @param box
* should primitives be boxed
* @return the JavaType for the parameter
*/
public String getJavaType(boolean box) {
if (!box && !canBeNull) {
String jt = toPrimitive.get(type.getJavaType());
if (jt == null) {
jt = type.getJavaType();
}
return jt;
} else {
return type.getJavaType();
}
}
/**
* Get the JdbcType for the parameter
*
* @return the JdbcType for the parameter
*/
public String getJdbcType() {
return type.getJdbcType();
}
/**
* Get the result set property
*
* @return the result set property
*/
public String getResultSetProperty() {
return type.getResultSetType();
}
/**
* Get the RDB property
*
* @return the RDB property
*/
public String getRdbProperty() {
return org.apache.commons.lang.StringUtils.capitalize(name);
}
/**
* Get whether or not this parameter can be bull
*
* @return whether or not this parameter can be bull
*/
public boolean canBeNull() {
return canBeNull;
}
/**
* Is this parameter a primitive
*
* @return true if primitive
*/
public boolean isPrimitive() {
if (!canBeNull) {
String jt = toPrimitive.get(type.getJavaType());
return (jt != null);
} else {
return false;
}
}
}
}