package center.task.prm.alg;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ru.vassaev.core.base.Null;
import ru.vassaev.core.base.WValue;
import ru.vassaev.core.container.ApplicationManager;
import ru.vassaev.core.db.Manager;
import ru.vassaev.core.db.Sttmnt;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.exception.SysRuntimeException;
import ru.vassaev.core.thread.PoolThread;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.types.TimeList;
import ru.vassaev.core.types.TimeList.Type;
import ru.vassaev.core.util.Strings;
import ru.vassaev.core.util.Xml;
import center.task.CalculateException;
import center.task.Context;
import center.task.Record;
import center.task.prm.Alg;
import center.task.prm.Dif;
/**
* Параметр - набор значений по результату Update
*
* @author Vassaev A.V.
* @version 1.0 20/06/2012
*/
public final class Upd extends Alg implements Dif {
private String db;
private class EventForEachRow {
private Map<String, String> into_map = new TreeMap<String, String>();
private String dbfer = null;
private Element update = null;
private Sttmnt stmt = null;
private EventForEachRow(Element fr) throws SysException {
NodeList nl = Xml.getElementsByTagName(fr, "into");
for (int i = 0; i < nl.getLength(); i++) {
Element into = (Element) nl.item(i);
into_map.put(into.getAttribute("from"), into.getTextContent());
}
dbfer = Strings.getXMLValue(fr, "update/db");
if (dbfer == null)
throw new SysException("There is no update/db for-each-row element");
update = (Element) Strings.getXMLObject(fr, "update/sql");
if (update == null)
throw new SysException("There is no update/sql for-each-row element");
stmt = new Sttmnt(dbfer, update, "i", "p", "o");
}
void start() throws SysException {
// if (stmt == null) {
// stmt = new Sttmnt(dbfer, update, "i", "p", "o");
// }
}
void exec(Context cntx) throws SysException {
Connection con = Manager.getConnection(dbfer);
CallableStatement st = null;
try {
st = stmt.getCallStatement(con);
StringList ls = stmt.getBindParamNames();
for (String n : ls) {
String o = Strings.getString(cntx.getPrmByFullName(n));
stmt.setParam(st, n, o, Types.CHAR);
}
try {
st.execute();
Manager.commit(con);
} catch (SQLException e) {
throw new SysException(e);
}
} catch (SysException e) {
stmt.freeStatement(st);
throw e;
} finally {
Manager.freeConnection(con);
}
}
void finish() throws SysException {
// if (stmt != null) {
// stmt.close();
// }
}
public Set<String> depedentOn() {
StringList ls = stmt.getBindParamNames();
Set<String> s = null;
if (ls.size() > 0)
s = new HashSet<String>(ls);
return s;
}
}
private EventForEachRow on_calculate;
private void loadONCalculate(Element e) throws SysException {
Element fr = (Element) Strings.getXMLObject(e, "for-each-row");
if (fr == null)
return;
on_calculate = new EventForEachRow(fr);
}
private void loadON(Element e) throws SysException {
Element on = (Element) Strings.getXMLObject(e, "on");
if (on == null)
return;
NodeList nl = on.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if (Node.ELEMENT_NODE != n.getNodeType())
continue;
Element ne = (Element) n;
String nn = ne.getNodeName();
if ("calculate".equals(nn)) {
loadONCalculate(ne);
}
}
}
private PoolThread prcpool = null;
private Sttmnt st;
private int parallel_max;
public Upd(center.task.prm.Type tp, String owner, Element e) throws SysException {
super(tp, owner);
// Загрузить обработчики событий
loadON(e);
// Работа с базой
db = Strings.getXMLValue(e, "db");
// DQL
Element update = (Element) Strings.getXMLObject(e, "update");
if (update == null)
return;
st = new Sttmnt(db, update, "i", "p", "o");
String sprcpool = Strings.getXMLValue(e, "parallel#prcpool");
if (sprcpool != null) {
prcpool = (PoolThread) ApplicationManager.getPoolByName(sprcpool, ru.vassaev.core.thread.Process.class);
String max = Strings.getXMLValue(e, "parallel#max");
this.parallel_max = Strings.parseIntegerNvl(max, 0);
}
}
public Object calculate(TimeList tl, Context cntx) throws CalculateException {
//System.out.println("Calculate owner=" + owner);
try {
tl.addPointTime(Type.START);
Set<String> sl = st.getInParamNames();
HashMap<String, Object> param_values = new HashMap<String, Object>();
for (String n : sl) {
Object x;
tl.addPointTime(TimeList.Type.WAIT);
if (prcpool == null)
x = cntx.getPrmByFullName(n);
else
x = cntx.getPrmAsync(prcpool, n);
tl.addPointTime(TimeList.Type.END_WAIT);
if (x == null)
x = Null.NULL;
param_values.put(n, x);
}
Connection con = Manager.getConnection(db);
CallableStatement stm = null;
int attempt = 2;
try {
while (true)
try {
stm = st.getCallStatement(con);
if (tp.getLog())
System.out.println(st.getSQLExpression());
tl.addPointTime(TimeList.Type.WAIT);
for (Entry<String, Object> n : param_values.entrySet()) {
String k = n.getKey();
Object o = n.getValue();
if (o instanceof WValue)
try {
st.setParam(stm, k, ((WValue)o).getValueWait());
} catch (Throwable e) {
throw new CalculateException(getOwner(), e);
}
else
st.setParam(stm, k, o);
}
tl.addPointTime(TimeList.Type.END_WAIT);
Record result = new Record();
stm.execute();
con.commit();
StringList slist = st.getOutParamNames();
for(int i = 0; i < slist.size(); i++) {
String name = slist.get(i);
Object value = st.getParam(stm, name);
result.setObject(name, value);
}
return result;
} catch (SQLException e) {
e.printStackTrace();
attempt--;
if (attempt > 0) {
con = Manager.reInitConnection(con);
} else
throw new CalculateException(owner, e);
} catch (CalculateException ex) {
throw ex;
} catch (Exception ex) {
throw new CalculateException(owner, ex);
} finally {
st.closeStatement(stm);
}
} finally {
Manager.freeConnection(con);
}
} catch(SysException ex) {
throw new CalculateException(owner, ex);
} finally {
tl.addPointTime(Type.END);
}
}
public Object getValueByIndex(Object v, String index) {
try {
int i = Integer.parseInt(index);
LinkedList<?> list = ((Record) v).value;
if (list.size() <= i)
return null;
return list.get(i);
} catch (NumberFormatException e) {
LinkedList<?> list = ((Record) v).value;
Integer i = ((Record) v).name.get(index);
if (i == null)
return null;
return list.get(i);
}
}
public Set<String> depedentOn() {
Set<String> s = null;
Set<String> params = st.getInParamNames();
if ((params != null) && params.size() > 0)
s = new HashSet<String>(params);
if (on_calculate != null) {
s = Strings.addAllToSet(s, on_calculate.depedentOn());
}
return s;
}
public Set<String> depedentOnParent() {
return null;
}
}