package de.unioninvestment.eai.portal.portlet.crud.scripting.category;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.StringWriterIOException;
import groovy.sql.Sql;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import org.codehaus.groovy.runtime.GStringImpl;
import org.codehaus.groovy.runtime.InvokerHelper;
/**
* Extensions for GStrings.
*
* @author carsten.mjartan
*/
public class GStringCategory {
/**
* Creates a new GString, with nested GStrings pulled to the top Level. This
* can be used in combination with {@link Sql} to execute nested Statements.
* Sub-GStrings are NOT flattened recursively.
*
* @param root
* the GString to flatten
* @return the flattened result
*/
public static GString flatten(GString root) {
Object[] values = root.getValues();
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof GString) {
GString head = head(root, i);
GString sub = (GString) values[i];
GString tail = tail(root, i);
return head.plus(sub).plus(flatten(tail));
}
}
return root;
}
private static GString head(GString root, int valueIndex) {
String[] headStrings = new String[valueIndex + 1];
Object[] headValues = new Object[valueIndex];
System.arraycopy(root.getStrings(), 0, headStrings, 0, valueIndex + 1);
System.arraycopy(root.getValues(), 0, headValues, 0, valueIndex);
return new GStringImpl(headValues, headStrings);
}
private static GString tail(GString root, int valueIndex) {
String[] strings = root.getStrings();
Object[] values = root.getValues();
int tailStringLength = strings.length - valueIndex - 1;
int tailValueLength = values.length - valueIndex - 1;
String[] tailStrings = new String[tailStringLength];
Object[] tailValues = new Object[tailValueLength];
System.arraycopy(strings, valueIndex + 1, tailStrings, 0,
tailStringLength);
System.arraycopy(values, valueIndex + 1, tailValues, 0, tailValueLength);
return new GStringImpl(tailValues, tailStrings);
}
/**
* This Method tries to convert an SQL GString to an SQL Statement for
* easier readability (of the audit log).
*
* Functionality mostly copied from GString.toString(). Currently only
* String Parameters are encapsulated
*
* @param gs
* the input GString
* @return a String of what an SQL could look like.
*/
public static String toSqlString(GString gs) {
StringWriter out = new StringWriter();
try {
String[] s = gs.getStrings();
int numberOfValues = gs.getValueCount();
for (int i = 0, size = s.length; i < size; i++) {
out.write(s[i]);
if (i < numberOfValues) {
final Object value = gs.getValue(i);
if (value instanceof Closure) {
final Closure c = (Closure) value;
if (c.getMaximumNumberOfParameters() == 0) {
writeSqlParameter(out, c.call());
} else if (c.getMaximumNumberOfParameters() == 1) {
c.call(out);
} else {
throw new GroovyRuntimeException(
"Trying to evaluate a GString containing a Closure taking "
+ c.getMaximumNumberOfParameters()
+ " parameters");
}
} else {
writeSqlParameter(out, value);
}
}
}
} catch (IOException e) {
throw new StringWriterIOException(e);
}
return out.toString();
}
private static void writeSqlParameter(StringWriter out, Object value)
throws IOException {
if (value instanceof String || value instanceof GString
|| value instanceof Reader) {
out.write("'");
InvokerHelper.write(out, value);
out.write("'");
} else {
InvokerHelper.write(out, value);
}
}
}