de.tsl2.nano.h5.expression.Query Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.h5 Show documentation
Show all versions of tsl2.nano.h5 Show documentation
TSL2 Framework Html5 Extensions (WebServer, Html5Presentation, RuleCover, BeanConfigurator, LogicTable-Sheet, Expression-Descriptors for Actions, Rules, URLs, Queries)
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Tom, Thomas Schneider
* created on: 25.02.2014
*
* Copyright: (c) Thomas Schneider 2014, all rights reserved
*/
package de.tsl2.nano.h5.expression;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementMap;
import de.tsl2.nano.bean.BeanContainer;
import de.tsl2.nano.core.ENV;
import de.tsl2.nano.core.log.LogFactory;
import de.tsl2.nano.core.util.StringUtil;
import de.tsl2.nano.core.util.Util;
import de.tsl2.nano.execution.IPRunnable;
import de.tsl2.nano.service.util.ServiceUtil;
import de.tsl2.nano.specification.AbstractRunnable;
import de.tsl2.nano.specification.IPrefixed;
/**
* class to execute sql statements. not an inheritance of AbstractRunnable in cause of not having constraints in its
* parameter map.
*
* @author Tom, Thomas Schneider
* @version $Revision$
*/
public class Query implements IPRunnable>, IPrefixed {
/** serialVersionUID */
private static final long serialVersionUID = -9199837113877884921L;
private static final Log LOG = LogFactory.getLog(Query.class);
/** full column expression for one column */
private static final String SQL_COL = "(^|\\,)\\s*([^,]+)(\\s+[Aa][Ss]\\s+(\\w+))?";
/** sql parameter */
private static final String SQL_PAR = "[:]([\\w._-]+)";
/** sql function */
private static final String SQL_FCT = "(\\w+)\\([^\\(\\)]+\\)";
/** column name */
private static final String SQL_NAM = ".*(\\w+)";
/** string literal */
private static final String SQL_LIT = "['\"][^'\"]*['\"]";
/** one or more concatenations */
private static final String SQL_CON = "[^,]+[|]{2}";
/** column path (if schema, etc. where given) */
private static final String SQL_PAT = "(\\w+[.])+";
@Attribute
String name;
@Element(data = true)
String operation;
@Attribute
boolean nativeQuery;
@ElementMap(entry = "parameter", attribute = true, inline = true, keyType = String.class, key = "name", value = "type", required = false)
Map parameter;
private transient ArrayList columnNames;
/**
* constructor
*/
public Query() {
}
public Query(String name, String query) {
this(name, query, null);
}
public Query(String name, String query, Map parameter) {
this(name, query, true, parameter);
}
/**
* constructor
*
* @param name
* @param query
* @param parameter
*/
public Query(String name, String query, boolean nativeQuery, Map parameter) {
super();
this.name = name;
this.operation = query;
this.nativeQuery = nativeQuery;
this.parameter = parameter;
}
@SuppressWarnings("unchecked")
@Override
public RESULT run(Map context, Object... extArgs) {
//workaround for hibernate/query not allowing parameter with dots
Set pars = getParameter().keySet();
String op = operation.replaceAll("--.*", "");
Map args = checkedArguments(context, ENV.get("app.mode.strict", false));
String sqlvar;
for (String p : pars) {
sqlvar = p.replace('.', 'X');
if (parameter.get(p) != null) {
args.put(sqlvar, parameter.get(p));
if (!context.containsKey(p))
context.put(p, parameter.get(p));
} else if (context.containsKey(p))
args.put(sqlvar, context.get(p));
op = op.replace(":" + p, ":" + sqlvar);
}
//do the job
return (RESULT) (ServiceUtil.isExcecutionStatement(op) ? BeanContainer.instance().executeStmt(op, nativeQuery, args.values().toArray())
: BeanContainer.instance().getBeansByQuery(op, nativeQuery, args));
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getQuery() {
return operation;
}
public void setQuery(String query) {
operation = query;
columnNames = null;
parameter = null;
}
@Override
public Map getParameter() {
if (parameter == null) {
parameter = new LinkedHashMap();
String p;
//remove temporary all comments
String op = operation.replaceAll("--.*", "");
//we allow both: the named query syntax and the most java used ant-like-variables
op = operation.replace("${", ":").replace("}", "");
//redundant: persist the cleaned sql-query-parameter
operation = operation.replace("${", ":").replace("}", "");
StringBuilder q = new StringBuilder(op);
while ((!Util.isEmpty(p = StringUtil.extract(q, SQL_PAR, "")))) {
parameter.put(p.substring(1), null);
}
}
return parameter;
}
/**
* evaluates the query's column names through the select-columns having an 'as' expression.
*
* e.g. 'select name, type as Type from...
* will have the column 'Type'.
*
* @return
*/
public List getColumnNames() {
if (columnNames == null) {
columnNames = new ArrayList();
String p;
//get the full selection header and eliminate literals, functions and concatenations
String select = StringUtil.substring(operation, "select ", "from ");
select = select.replaceAll(SQL_LIT, "");
select = select.replaceAll(SQL_PAT, "");
select = select.replaceAll(SQL_CON, "");
//TODO: capturing group 1 is not used! why?
select = select.replaceAll(SQL_FCT, "$1");
StringBuilder q = new StringBuilder(select);
while ((!Util.isEmpty(p = StringUtil.extract(q, SQL_COL, "", 0, 0)))) {
String as = StringUtil.extract(p, "\\s+[Aa][Ss]\\s+");
columnNames.add(!Util.isEmpty(as) && p.contains(as)
? StringUtil.substring(p, as, null).trim()
: StringUtil.substring(StringUtil.substring(p, ",", null), ".", null, true).trim());
}
if (LOG.isDebugEnabled())
LOG.debug(Arrays.toString(columnNames.toArray()));
}
return columnNames;
}
@Override
public Map checkedArguments(Map arguments, boolean strict) {
boolean asSequence = AbstractRunnable.asSequence(arguments);
Map args = new LinkedHashMap();
if (parameter.isEmpty()) //only defined parameters are allowed - otherwise we get an exception by jpa query implementation
return args;
Set keySet = arguments.keySet();
Set parameterKeys = parameter.keySet();
Iterator