package center.app.common;
import ru.vassaev.core.Pool;
import ru.vassaev.core.PrmInterface;
import ru.vassaev.core.io.CloseableOutputStream;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.xml.XMLMsg;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.exception.SysRuntimeException;
import center.system.InfoBase;
import center.task.Context;
import center.task.AProcessor;
import center.task.State;
import center.task.TaskException;
import center.task.api.ITaskAPI;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
/**
* Процессор запросов к внешней системе
* <p/>
* Используюет протокол XML, соединение не сохраняет, соединение обрубает по достижении timeout.
* Параметры:
* Входные: in.{name}* - параметры сообщения (запроса)
* key - ключ сообщения (если не задан, то формируется процессором)
* timeout - время ожидания ответа в миллисекундах
* (0 или не задано - временем не ограничено)
* host - host внешней системы
* port - port на хосте внешней системы
* Результат: out.{name}* - ответ
* ERR - текст ошибки, если статус DONE_ERR
* ERR_EX - дополнительный текст ошибки, если статус DONE_ERR
*
* @author Vassaev Andrey
* @version 1.0
* Date: 26.12.2007
* Time: 13:53:43
*/
public class QueryProcessor extends AProcessor {
private static long id = 0;
private static String getStan() {
long stan = System.currentTimeMillis() << 4;
stan = stan + ((id++) % 16);
String stan_str = Long.toString(stan);
return stan_str.substring(stan_str.length() - 6);
}
private static Pool<XMLMsg> pool = new Pool<XMLMsg>(XMLMsg.class);
public static XMLMsg getMsg() {
try {
return pool.occupyWait();
} catch (SysRuntimeException e) {
return null;
}
}
public static void freeMsg(XMLMsg m) {
m.reset();
pool.free(m);
}
private static class Reader extends Thread {
public final InputStream is;
public final String key;
public final InfoBase<XMLMsg, XMLMsg> ib;
public final XMLMsg m;
public final long id_task;
public final ITaskAPI ta;
public boolean isRun = false;
public boolean isWait = false;
public Exception err = null;
public Reader(InputStream is, InfoBase<XMLMsg, XMLMsg> ib, XMLMsg m, String key, ITaskAPI ta, long id_task) {
this.is = is;
this.key = key;
this.ta = ta;
this.id_task = id_task;
this.ib = ib;
this.m = m;
}
public void run() {
XMLMsg r = null;
try {
CloseableOutputStream oss = m.getOutputStream();
int b;
while ((b = is.read()) != -1) {
oss.write(b);
if (oss.isClosed()) {
String k = (m.isCalcKey()?m.getCalcKey():m.getKey());
if (!key.equals(k))
throw new SysException("An expected response is invalid");
r = m;
break;
}
}
} catch (IOException ex) {
err = ex;
} catch (SysException ex) {
err = ex;
} finally {
try {
ib.giveResponse(r, key);
} catch (SysException e) {
err = e;
}
}
}
}
public State process(Context cntx) throws SysException, TaskException {
try {
String host = cntx.getPrmString("host");
int port = Integer.parseInt(cntx.getPrmString("port"));
Socket s = new Socket(host, port);
String timeout_s = cntx.getPrmString("timeout");
long timeout = 0;
if ((timeout_s != null) && (timeout_s.length() > 0)) {
try {
timeout = Long.parseLong(timeout_s);
} catch (NumberFormatException ex) {
throw new SysException(ex);
}
}
//Socket s = new Socket("localhost", 8897);
XMLMsg m = null;
InputStream is = null;
OutputStream os = s.getOutputStream();
try {
m = getMsg();
String key = cntx.getPrmString("key");
if ((key == null) || (key.length() == 0))
key = getStan();
m.setKey(key);
cntx.ta.setParamObject(cntx.id_task, "key", key);
String keyNames = cntx.getPrmString("keyNames");
m.setKeyNames(keyNames);
Map<String, Object> prms_in = cntx.getGroupParams("in");
PrmInterface prm = m.getPrmInterface();
for (String n : prms_in.keySet()) {
Object v = prms_in.get(n);
n = n.substring("in/".length());
if (v != null)
prm.setField(n, v.toString());
else
prm.setField(n, null);
}
boolean isCalcKey = m.isCalcKey();
key = (isCalcKey ? m.getCalcKey() : m.getKey());
cntx.ta.setParamObject(cntx.id_task, "calcKey", key);
is = m.getInputStream();
int b = -1;
while ((b = is.read()) != -1)
os.write(b);
os.flush();
is = s.getInputStream();
InfoBase<XMLMsg, XMLMsg> ib = new InfoBase<XMLMsg, XMLMsg>();
ib.makeQuery(m, key);
m.reset();
Reader th = new Reader(is, ib, m, key, cntx.ta, cntx.id_task);
try {
th.start();
//====================================
cntx.log(false, "Start waiting (", timeout, ")");
XMLMsg r = ib.takeResponseWithWait(key, timeout); //, id_task, ta, id_processor);
cntx.log(false, "End waiting");
if (r == null) {
throw new TaskException(State.DONE_TOUT, "An expected response was not received on time");
}
PrmInterface r_prm = r.getPrmInterface();
StringList flds = r_prm.getFieldNames();
for (int j = 0; j < flds.size(); j++) {
String k = flds.get(j).toString();
cntx.ta.setParamObject(cntx.id_task, "out." + k, r_prm.getField(k));
}
} finally {
th.interrupt();
}
} finally {
if (is != null)
is.close();
s.close();
freeMsg(m);
}
return State.DONE_OK;
} catch (UnknownHostException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (IOException e) {
throw new TaskException(State.DONE_ERR, e);
}
}
public Set<String> dependentOn() {
return null;
}
public Set<String> loopDependentOn() {
return null;
}
}