/*******************************************************************************
* Copyright © 2012, 2013 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.gen.java.templates.eglx.persistence.sql;
import java.util.List;
import org.eclipse.edt.gen.java.Context;
import org.eclipse.edt.gen.java.templates.StatementTemplate;
import org.eclipse.edt.mof.codegen.api.TabbedWriter;
import org.eclipse.edt.mof.egl.AccessKind;
import org.eclipse.edt.mof.egl.Annotation;
import org.eclipse.edt.mof.egl.ArrayType;
import org.eclipse.edt.mof.egl.Assignment;
import org.eclipse.edt.mof.egl.Classifier;
import org.eclipse.edt.mof.egl.EGLClass;
import org.eclipse.edt.mof.egl.Expression;
import org.eclipse.edt.mof.egl.Field;
import org.eclipse.edt.mof.egl.FixedPrecisionType;
import org.eclipse.edt.mof.egl.Function;
import org.eclipse.edt.mof.egl.LHSExpr;
import org.eclipse.edt.mof.egl.Member;
import org.eclipse.edt.mof.egl.MemberAccess;
import org.eclipse.edt.mof.egl.MemberName;
import org.eclipse.edt.mof.egl.Name;
import org.eclipse.edt.mof.egl.Statement;
import org.eclipse.edt.mof.egl.Type;
import org.eclipse.edt.mof.egl.utils.TypeUtils;
import org.eclipse.edt.mof.eglx.persistence.sql.DummyExpression;
import org.eclipse.edt.mof.eglx.persistence.sql.SqlActionStatement;
import org.eclipse.edt.mof.eglx.persistence.sql.SqlPrepareStatement;
import org.eclipse.edt.mof.eglx.persistence.sql.ext.Utils;
import org.eclipse.edt.mof.eglx.persistence.sql.impl.DummyExpressionDynamicImpl;
public abstract class SqlActionStatementTemplate extends StatementTemplate implements org.eclipse.edt.gen.java.templates.eglx.persistence.Constants{
public static final String sqlStmtKey = "org.eclipse.edt.gen.java.sql.stmtkey";
public static final String genClause = "genClause";
public static final String genSQLAnnotation = "genSQLAnnotation";
protected static final String genStatementOptions = "genStatementOptions";
protected static final String AnnotationSQLResultSetControl = "eglx.persistence.sql.SQLResultSetControl";
public static final String AnnotationSQLGeneratedValue = "eglx.persistence.sql.GeneratedValue";
public static final String genSelectClause = "genSelectClause";
public static final String var_connection = "ezeConn";
public static final String var_statement = "ezeStatement";
public static final String var_listElement = "ezeElement";
public static final String expr_getConnection = "getConnection()";
public static final String class_PreparedStatement = "java.sql.PreparedStatement";
public static final String class_CallableStatement = "java.sql.CallableStatement";
public static final String class_ResultSet = "java.sql.ResultSet";
public static final String err_noSqlGenerated = "<no SQL generated>";
public String quoted(String value) {
StringBuilder out = new StringBuilder();
out.append('"');
out.append(value);
out.append('"');
return out.toString();
}
public void genStatementBody(Statement stmt, Context ctx, TabbedWriter out ) {
// TODO Auto-generated method stub
}
public void genStatementEnd(TabbedWriter out) {
// Do nothing as these statements are handled as sets of java code
// that will manage their own blocks of code
}
public void genSqlStatementSetup(SqlActionStatement stmt, Context ctx, TabbedWriter out, String var_stmt) {
String varName = var_statement;
if(stmt.getPreparedStatement() != null){
varName = getExprString(stmt.getPreparedStatement(), ctx);
}
genSqlStatementSetup(stmt, ctx, out, varName, false);
}
/**
* Generate code necessary to retrieve current result set row into target variables
* This method assumes a list of expressions can only be of non entity types, i.e. each
* expression maps directly to one column. An single Entity expression would have the fields
* of the entity map to the given result set columns
* @param targets
* @param dataSource
* @param args
* @param ctx
* @param out
*/
protected void genGetSingleRowFromResultSet(List<Expression> targets, String resultSet, Context ctx, TabbedWriter out) {
int i = 1;
for (Expression target : targets) {
genSetTargetFromResultSet(target, resultSet, i, ctx, out);
i++;
}
}
protected void genGetSingleRowFromResultSet(Expression target, String resultSet, Context ctx, TabbedWriter out) {
EGLClass type = (EGLClass)target.getType().getClassifier();
if (Utils.isMappedSQLType(type)) {
genSetTargetFromResultSet(target, resultSet, 1, ctx, out);
}
else{
if (target.isNullable()) {
out.print("if (");
ctx.invoke(genExpression, target, ctx, out);
out.println(" == null) {");
ctx.invoke(genExpression, target, ctx, out);
out.print(" = ");
ctx.invoke(genInstantiation, type, ctx, out);
out.println(";");
out.println("}");
}
int idx = 1;
for (Field field : type.getFields()) {
if (!field.isStatic() &&
field.getAccessKind()!= AccessKind.ACC_PRIVATE &&
Utils.isReadable(field) &&
Utils.isMappedSQLType((EGLClass)field.getType().getClassifier())) {
genSetTargetFromResultSet(target, field, resultSet, idx++, ctx, out);
}
}
}
}
protected void genGetSingleRowFromResultSet(EGLClass type, String targetVar, String resultSet, Context ctx, TabbedWriter out) {
DummyExpression dummy = DummyExpressionDynamicImpl.newInstance();
dummy.setExpr(targetVar);
dummy.setType(type);
genGetSingleRowFromResultSet(dummy, resultSet, ctx, out);
}
private void genSetTargetFromResultSet(Expression target, String var_resultSet, int columnIndex, Context ctx, TabbedWriter out) {
TabbedWriter newOut = ctx.getTabbedWriter();
genGetColumnValueByIndex(target.getType(), var_resultSet, columnIndex, ctx, newOut);
genSetTargetFromResultSet(target, newOut.getCurrentLine(), var_resultSet, ctx, out);
}
protected void genSetTargetFromResultSet(Expression target, Field field, String var_resultSet, int columnIndex, Context ctx, TabbedWriter out) {
TabbedWriter newOut = ctx.getTabbedWriter();
ctx.invoke(genName, field, ctx, newOut);
MemberAccess expr = ctx.getFactory().createMemberAccess();
expr.setQualifier(target);
expr.setId(newOut.getCurrentLine());
expr.setMember(field);
genSetTargetFromResultSet(expr, var_resultSet, columnIndex, ctx, out);
}
private void genSetTargetFromResultSet(Expression target, String rhsExpr, String resultSetVar, Context ctx, TabbedWriter out) {
Assignment assign = ctx.getFactory().createAssignment();
assign.setLHS((LHSExpr)target);
DummyExpression dummy = DummyExpressionDynamicImpl.newInstance();
dummy.setExpr(rhsExpr);
dummy.setType(target.getType());
assign.setRHS(dummy);
ctx.invoke(genExpression, assign, ctx, out);
out.println(";");
if(target.isNullable()){
out.print("if(");
out.print(resultSetVar);
out.println(".wasNull()){");
assign = ctx.getFactory().createAssignment();
assign.setLHS((LHSExpr)target);
dummy = DummyExpressionDynamicImpl.newInstance();
dummy.setExpr("null");
dummy.setType(target.getType());
assign.setRHS(dummy);
ctx.invoke(genExpression, assign, ctx, out);
out.println(";");
out.println("}");
}
}
public boolean genSqlStatementSetup(SqlActionStatement stmt, Context ctx, TabbedWriter out, String var_stmt, boolean stmtDeclared) {
boolean isCall = Utils.isCallStatement(stmt.getSqlString());
out.println("try {");
if (stmt.getPreparedStatement() == null || stmt instanceof SqlPrepareStatement) {
Integer stmtNumber = getNextStatementKey(ctx);
if (isCall) {
if (!stmtDeclared){
out.print(class_CallableStatement + " ");
}
out.print(var_stmt + " = (" + class_CallableStatement + ")");
}
else {
if (!stmtDeclared){
out.print(class_PreparedStatement + " ");
}
out.print(var_stmt + " = (" + class_PreparedStatement + ")");
}
ctx.invoke(genExpression, stmt.getDataSource(), ctx, out);
ctx.invoke(genGetStatement, stmt, ctx, out, stmtNumber);
out.println("if (" + var_stmt + "== null) {");
out.print("String stmtStr = ");
ctx.invoke(genSQLString, stmt, ctx, out);
out.println(';');
out.print(var_stmt + " = ");
ctx.invoke(genExpression, stmt.getDataSource(), ctx, out);
out.print('.' + expr_getConnection);
if (isCall) {
out.print(".prepareCall(stmtStr");
}
else {
out.print(".prepareStatement(stmtStr");
}
if(getResultSet(stmt) != null){
ctx.invoke(genStatementOptions, stmt, ctx, out, getResultSet(stmt));
}
out.println(");");
ctx.invoke(genExpression, stmt.getDataSource(), ctx, out);
ctx.invoke(genRegisterStatement, stmt, ctx, out, var_stmt, stmtNumber);
out.println("}");
}
if (stmt.getUsingExpressions()!= null) {
if (isCall) {
out.print("java.sql.ParameterMetaData ezeParmData = ");
out.println(var_stmt + ".getParameterMetaData();");
int i = 1;
for (Expression uexpr : stmt.getUsingExpressions()) {
// For each parameter find out if it is an OUT parameter.
// If so register the type of the parameter based on the
// mapping of the input argument expression type to SQL types
out.println("if (ezeParmData.getParameterMode(" + i + ") == java.sql.ParameterMetaData.parameterModeOut) {");
out.print(var_stmt + ".registerOutParameter(");
out.print(i);
out.print(", ");
out.print(Utils.getSQLTypeConstant(uexpr.getType().getClassifier()));
if (uexpr.getType() instanceof FixedPrecisionType) {
out.print(", ");
out.print(((FixedPrecisionType)uexpr.getType()).getDecimals());
}
out.println(");");
out.println("}");
i++;
}
}
if(stmt.getUsingExpressions() != null && stmt.getUsingExpressions().size() > 0 ){
genSetStatementsForUsingClause(stmt, var_stmt, ctx, out);
}
else{
genSetStatementsForForClause(stmt, var_stmt, ctx, out);
}
}
return isCall;
}
public void genSQLString(SqlActionStatement stmt, Context ctx, TabbedWriter out){
out.print(quoted(Utils.removeCRLFs(stmt.getSqlString())));
}
public void genGetStatement(SqlActionStatement stmt, Context ctx, TabbedWriter out, Integer stmtNumber){
String typeSignature = quoted(((Type)((Function)stmt.getContainer()).getContainer()).getTypeSignature());
out.println(".getStatement(" + typeSignature + ", " + stmtNumber + ");");
}
public void genRegisterStatement(SqlActionStatement stmt, Context ctx, TabbedWriter out, String var_stmt, Integer stmtNumber){
String typeSignature = quoted(((Type)((Function)stmt.getContainer()).getContainer()).getTypeSignature());
out.println(".registerStatement(" + typeSignature + ", " + stmtNumber + ", " + var_stmt + ");");
}
protected void genSetStatementsForUsingClause(SqlActionStatement stmt, String var_stmt, Context ctx, TabbedWriter out){
int i = 1;
for (Expression uexpr : stmt.getUsingExpressions()) {
genSetColumnValue(stmt, uexpr, var_stmt, i, ctx, out);
i++;
}
}
protected void genSetStatementsForForClause(SqlActionStatement stmt, String var_stmt, Context ctx, TabbedWriter out){
}
public void genSqlStatementSetup(SqlActionStatement stmt, Context ctx, TabbedWriter out) {
genSqlStatementSetup(stmt, ctx, out, var_statement);
}
public void genStatementOptions(SqlActionStatement stmt, Context ctx, TabbedWriter out, MemberAccess member) {
genStatementOptions(member.getMember().getAnnotation(AnnotationSQLResultSetControl), ctx, out);
}
public void genStatementOptions(SqlActionStatement stmt, Context ctx, TabbedWriter out, MemberName member) {
genStatementOptions(member.getMember().getAnnotation(AnnotationSQLResultSetControl), ctx, out);
}
protected Expression getResultSet(SqlActionStatement stmt){
return stmt.getTarget();
}
private void genStatementOptions(Annotation annot, Context ctx, TabbedWriter out) {
if(annot != null){
ctx.invoke(genSQLAnnotation, annot.getEClass(), ctx, out, annot);
}
}
public void genWhereClauseParameterSettings(SqlActionStatement stmt, String var_statement, int startParmIndex, Context ctx, TabbedWriter out) {
int i = startParmIndex;
if(stmt.getUsingExpressions() == null || stmt.getUsingExpressions().size() == 0){
Expression targetExpr = stmt.getTarget();
EGLClass targetType = getTargetType(stmt);
String varName = getExprString(targetExpr, ctx);
for (Field f : targetType.getFields()) {
if (Utils.isKeyField(f) && Utils.isMappedSQLType((EGLClass)f.getType().getClassifier())) {
genSetColumnValue(f, var_statement, varName, i, ctx, out);
i++;
}
}
}
else{
for (Expression using : stmt.getUsingExpressions()) {
if (Utils.isMappedSQLType((EGLClass)using.getType().getClassifier())) {
genSetColumnValue(stmt, using, var_statement, i, ctx, out);
i++;
}
}
}
}
public void genSqlStatementEnd(SqlActionStatement stmt, Context ctx, TabbedWriter out) {
out.println("}");
out.println("catch(java.sql.SQLException ezeEx) {");
out.println("throw eglx.persistence.sql.SQLUtilities.makeEglException(ezeEx);");
out.println('}');
}
// Handles conversion of EGL values to SQL values in places where the default mapping
// is not sufficient, i.e. dates and timestamps need to become SQL dates and timestamps
public void genConvertValueStart(EGLClass type, Context ctx, TabbedWriter out) {
if (Utils.isWrappedSQLType(type)) {
out.print("new ");
out.print(Utils.getSQLTypeName(type));
out.print('(');
}
}
public void genConvertValueEnd(EGLClass type, Context ctx, TabbedWriter out) {
if (Utils.isWrappedSQLType(type)) {
out.print('.');
out.print(Utils.getConvertToSQLConstructorOptions(type));
out.print(')');
}
}
protected void genGetColumnValueByIndex(Type type, String resultSetName, int columnIndex, Context ctx, TabbedWriter out) {
Classifier typeClassifier = type.getClassifier();
if (typeClassifier.equals(TypeUtils.Type_TIMESTAMP)) {
out.print("org.eclipse.edt.runtime.java.eglx.lang.ETimestamp.asTimestamp(org.eclipse.edt.javart.util.DateTimeUtil.getNewCalendar(");
out.print(resultSetName);
out.print('.');
genSqlGetValueMethodName(typeClassifier, ctx, out);
out.print("(" + columnIndex + "))");
ctx.invoke(genTypeDependentOptions, type, ctx, out);
out.print(")");
}
else if(typeClassifier.equals(TypeUtils.Type_DATE)){
out.print("org.eclipse.edt.runtime.java.eglx.lang.EDate.asDate(org.eclipse.edt.javart.util.DateTimeUtil.getNewCalendar(");
out.print(resultSetName);
out.print('.');
genSqlGetValueMethodName(typeClassifier, ctx, out);
out.print("(" + columnIndex + ")))");
}
else if(typeClassifier.equals(TypeUtils.Type_TIME)){
out.print("org.eclipse.edt.runtime.java.eglx.lang.ETime.asTime(org.eclipse.edt.javart.util.DateTimeUtil.getNewCalendar(");
out.print(resultSetName);
out.print('.');
genSqlGetValueMethodName(typeClassifier, ctx, out);
out.print("(" + columnIndex + ")))");
}
else {
out.print(resultSetName);
out.print('.');
genSqlGetValueMethodName(typeClassifier, ctx, out);
out.print("(" + columnIndex + ")");
}
}
public Boolean isNullable(SqlActionStatement stmt, Context ctx, MemberAccess expr) {
return expr.getMember().isNullable();
}
public Boolean isNullable(SqlActionStatement stmt, Context ctx, Expression expr) {
return Boolean.FALSE;
}
public Boolean isNullable(SqlActionStatement stmt, Context ctx, MemberName expr) {
return expr.getMember().isNullable();
}
protected void genSetColumnValue(SqlActionStatement stmt, Expression expr, String stmt_or_resultSet_var, int columnIndex, Context ctx, TabbedWriter out) {
EGLClass type = (EGLClass)expr.getType().getClassifier();
Boolean isNullable = (Boolean)ctx.invoke("isNullable", stmt, ctx, expr);
if(isNullable != null && isNullable){
out.print("if(null == ");
ctx.invoke(genExpression, expr, ctx, out);
out.println("){");
out.print(stmt_or_resultSet_var);
out.print(".setNull(");
out.print(columnIndex);
out.print(", ");
out.print(Utils.getSQLTypeConstant(type));
out.println(");");
out.println("}");
out.println("else{");
}
out.print(stmt_or_resultSet_var);
out.print('.');
genSqlSetValueMethodName(type, ctx, out);
out.print('(');
out.print(columnIndex);
out.print(", ");
genConvertValueStart(type, ctx, out);
ctx.invoke(genExpression, expr, ctx, out);
genConvertValueEnd(type, ctx, out);
out.println(");");
if(isNullable != null && isNullable){
out.println("}");
}
}
protected void genSetColumnValue(Field field, String stmt_or_resultSet_var, String varName, int columnIndex, Context ctx, TabbedWriter out) {
EGLClass type = (EGLClass)field.getType().getClassifier();
if(field.isNullable()){
out.print("if(null == ");
out.print(varName);
out.print('.');
ctx.invoke(genName, field, ctx, out);
out.println("){");
out.print(stmt_or_resultSet_var);
out.print(".setNull(");
out.print(columnIndex);
out.print(", ");
out.print(Utils.getSQLTypeConstant(field.getType().getClassifier()));
out.println(");");
out.println("}");
out.println("else{");
}
out.print(stmt_or_resultSet_var);
out.print('.');
genSqlSetValueMethodName(type, ctx, out);
out.print('(');
out.print(columnIndex);
out.print(", ");
genConvertValueStart(type, ctx, out);
out.print(varName);
out.print('.');
ctx.invoke(genName, field, ctx, out);
genConvertValueEnd(type, ctx, out);
out.println(");");
if(field.isNullable()){
out.println("}");
}
}
public void genSqlGetValueMethodName(Classifier type, Context ctx, TabbedWriter out) {
String name = "get";
name += Utils.getSqlSimpleTypeName(type);
out.print(name);
}
public void genSqlSetValueMethodName(Classifier type, Context ctx, TabbedWriter out) {
String name = "set";
name += Utils.getSqlSimpleTypeName(type);
out.print(name);
}
public Integer getNextStatementKey(Context ctx) {
Integer key = (Integer)ctx.get(sqlStmtKey);
if (key == null) {
key = 0;
}
else {
key++;
}
ctx.put(sqlStmtKey, key);
return key;
}
public String getCursorNameFromDataSource(Expression datasource, Context ctx) {
Member ds = (Member)((Name)datasource).getNamedElement();
return (String)ctx.getAttribute(ds, "eglx.persistence.sql.CursorName");
}
public EGLClass getTargetType(SqlActionStatement stmt) {
Type type = stmt.getTarget().getType();
return getBaseType(type);
}
public EGLClass getBaseType(Type type) {
if (type instanceof ArrayType) {
return (EGLClass)((ArrayType)type).getElementType();
}
else {
return (EGLClass)type;
}
}
public String getExprString(Expression expr, Context ctx) {
if (expr == null) return "<invalid expression>";
TabbedWriter out = ctx.getTabbedWriter();
ctx.invoke(genExpression, expr, ctx, out);
return out.getCurrentLine();
}
}