package center.task.prm.alg;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;
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.container.ApplicationManager;
import ru.vassaev.core.db.Manager;
import ru.vassaev.core.db.Sttmnt;
import ru.vassaev.core.thread.*;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.exception.SysRuntimeException;
import ru.vassaev.core.io.OutputByteBuffer;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.types.TimeList;
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;
/**
* Параметр - набор значений по SELECT
*
* @author Vassaev A.V.
* @version 1.1 03/08/2011
*/
public final class Sel extends Alg implements Dif {
// private Map<String, ArrayList<Integer>> param_positions;
// private ArrayList<Object> query;
private String db;
/*
private void addPosition(String name, int pos) {
if (param_positions == null)
param_positions = new HashMap<String, ArrayList<Integer>>();
ArrayList<Integer> list = param_positions.get(name);
if (list == null) {
list = new ArrayList<Integer>();
param_positions.put(name, list);
}
list.add(pos);
}
*/
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;
/*
* TODO пока не используется
*/
private int parallel_max;
public Sel(center.task.prm.Type tp, String owner, Element e) throws SysException {
super(tp, owner);
// Загрузить обработчики событий
loadON(e);
// Работа с базой
db = Strings.getXMLValue(e, "db");
// DQL
Element select = (Element) Strings.getXMLObject(e, "select");
if (select == null)
return;
st = new Sttmnt(db, select, "i", "p", "o");
/*
query = new ArrayList<Object>();
NodeList nl = select.getChildNodes();
StringBuffer sb = new StringBuffer();
int pos = 1;
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
short t = n.getNodeType();
if (t == Node.ELEMENT_NODE) {
Element el = (Element) n;
String name = el.getTextContent();
if (el.getNodeName().equals("p")) {
sb.append('?');
addPosition(name, pos);
pos++;
} else if (el.getNodeName().equals("i")) {
if (sb.length() > 0) {
query.add(sb.toString());
sb = new StringBuffer();
}
query.add(new Inline(name));
}
} else if (t == Node.TEXT_NODE) {
Text txt = (Text) n;
sb.append(txt.getData());
}
}
if (sb.length() > 0)
query.add(sb.toString());
*/
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 {
try {
tl.addPointTime(TimeList.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);
}
tl.addPointTime(TimeList.Type.WAIT);
for (Entry<String, Object> n : param_values.entrySet()) {
String k = n.getKey();
Object o = n.getValue();
if (o instanceof Context.WaitValue)
try {
st.setParam(k, ((Context.WaitValue)o).getValueWait(), java.sql.Types.OTHER);
} catch (Throwable e) {
throw new CalculateException(getOwner(), e);
}
else
st.setParam(k, o, java.sql.Types.OTHER);
}
tl.addPointTime(TimeList.Type.END_WAIT);
Connection con = Manager.getConnection(db);
PreparedStatement stm = null;
try {
try {
stm = st.getStatement(con);
} catch (Exception ex) {
con = Manager.reInitConnection(con);
stm = st.getStatement(con);
}
Record result;
ResultSet rs = stm.executeQuery();
if (rs.next()) {
ResultSetMetaData md = stm.getMetaData(); // TODO надо оптимизировать
result = new Record();
for (int i = 1; i <= md.getColumnCount(); i++) {
result.name.put(md.getColumnName(i), i - 1);
Object x = rs.getObject(i);
if (x == null)
result.value.addLast(Null.NULL);
else {
if (x instanceof Blob) {
InputStream r = ((Blob)x).getBinaryStream();
OutputByteBuffer wr = ru.vassaev.core.thread.Process
.getByteBuffer(8000);
byte[] buf = new byte[1024];
int l;
try {
while ((l = r.read(buf)) > 0) {
wr.write(buf, 0, l);
}
wr.close();
r.close();
} catch (IOException e) {
throw new CalculateException(owner, e);
}
x = wr;
}
result.value.addLast(x);
}
}
// обработка события
if (on_calculate != null) {
on_calculate.start();
do {
// Регестрируем переменные в памяти потока
for (int i = 1; i <= md.getColumnCount(); i++) {
Object obj = rs.getObject(i);
String nm = on_calculate.into_map.get(md.getColumnName(i));
ru.vassaev.core.thread.Process.currentProcess()
.regResourceName(obj, nm);
}
on_calculate.exec(cntx);
} while (rs.next());
on_calculate.finish();
}
} else
result = null;
rs.close();
return result;
} catch (SQLException e) {
e.printStackTrace();
return null;
} finally {
st.closeStatement(stm);
Manager.freeConnection(con);
}
} catch(SysException ex) {
throw new SysRuntimeException(ex);
} finally {
tl.addPointTime(TimeList.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;
}
}