package center.app.common;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.w3c.dom.Element;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import ru.vassaev.core.base.Null;
import ru.vassaev.core.container.ApplicationManager;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.exception.SysRuntimeException;
import ru.vassaev.core.io.OutputByteBuffer;
import ru.vassaev.core.thread.PoolThread;
import ru.vassaev.core.thread.Process;
import ru.vassaev.core.util.Strings;
import ru.vassaev.core.xml.XMLFileWaiter;
import center.task.AProcessor;
import center.task.CalculateException;
import center.task.Context;
import center.task.State;
import center.task.TaskException;
import center.task.TypeOfState;
import center.task.prm.IDependentParam;
/**
* Процессор обработки http запросов
* @author Vassaev A.V.
* @version 1.0 29/10/2012
*/
public class HTTPXResponseProcessor extends AProcessor {
private SSLParameters sslp = null;
private boolean https = false;
private HttpServer server = null;
private Integer port;
private String story_file = null;
private char[] story_pwd = null;
private char[] key_pwd = null;
private String path = null;
private PoolThread executor = null;
public void paramsValidateAndPrepare(Context cntx) throws SysException {
port = Strings.parseInteger(cntx.getPrmString("port"));
if (port == null)
throw new SysException("Parameter port isn't set");
https = Strings.parseBooleanNvl(cntx.getPrmString("https"), false);
if (https) {
story_file = cntx.getPrmString("story_file");
if (story_file == null)
throw new SysException("Parameter story_file isn't set");
if (File.separatorChar != '\\')
story_file = story_file.replace('\\', File.separatorChar);
if (File.separatorChar != '/')
story_file = story_file.replace('/', File.separatorChar);
File sf = new File(story_file);
try {
story_file = sf.getCanonicalPath();
} catch (IOException e) {
throw new SysException(e);
}
String story_pwd = cntx.getPrmString("story_pwd");
if (story_pwd == null)
throw new SysException("Parameter story_pwd isn't set");
this.story_pwd = story_pwd.toCharArray();
String key_pwd = cntx.getPrmString("key_pwd");
if (key_pwd == null)
throw new SysException("Parameter key_pwd isn't set");
this.key_pwd = key_pwd.toCharArray();
}
path = cntx.getPrmString("path");
if (path == null)
path = "/";
String poolProcessName = cntx.getPrmString("process_pool");
if (Null.equ(poolProcessName))
throw new SysException("Parameter process_pool isn't set");
executor = (PoolThread) ApplicationManager.getPoolByName(poolProcessName, Process.class);
}
private Thread main_thread;
public State process(Context cntx) throws TaskException, SysException, InterruptedException {
paramsValidateAndPrepare(cntx);
main_thread = Process.currentProcess().getParent();
try {
//*
if (https)
try {
server = HttpsServer.create(new InetSocketAddress(port), 0);
HttpsServer ss = (HttpsServer) server;
// Получить экземпляр хранилища ключей.
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(story_file);
keyStore.load(fis, story_pwd);
// Получить диспетчеры ключей базовой реализации для заданного хранилища ключей.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, key_pwd);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// Получить доверенные диспетчеры базовой реализации.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
// Получить защищенное случайное число.
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
// Создание SSL контекста
SSLContext sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(keyManagers, trustManagers, secureRandom);
sslp = sslContext.getSupportedSSLParameters();
boolean needClientAuth = Strings.parseBoolean(cntx.getPrmNvl("needClientAuth", "false"));
sslp.setNeedClientAuth(needClientAuth);
boolean wantClientAuth = Strings.parseBoolean(cntx.getPrmNvl("wantClientAuth", "false"));
sslp.setWantClientAuth(wantClientAuth);
HttpsConfigurator conf = new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
params.setSSLParameters(sslp);
}
};
ss.setHttpsConfigurator(conf);
System.setProperty("javax.net.ssl.trustStore", story_file);
System.setProperty("javax.net.ssl.keyStore", story_file);
String trustStore = System.getProperty("javax.net.ssl.trustStore");
if (trustStore == null)
System.out.println("javax.net.ssl.trustStore is not defined");
else
System.out.println("javax.net.ssl.trustStore = " + trustStore);
String keyStore1 = System.getProperty("javax.net.ssl.keyStore");
if (keyStore1 == null)
System.out.println("javax.net.ssl.keyStore is not defined");
else
System.out.println("javax.net.ssl.keyStore = " + keyStore1);
} catch (NoSuchProviderException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (NoSuchAlgorithmException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (KeyManagementException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (CertificateException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (UnrecoverableKeyException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (KeyStoreException e) {
throw new TaskException(State.DONE_ERR, e);
}
else
server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext(path, new XMLHttpHandler(cntx));
server.setExecutor(executor);
server.start();
Process prc = Process.currentProcess();
while (true) {
try {
if (prc.isWillBreak())
return State.BROKEN;
State st = cntx.ta.getState(cntx.id_task);
if (st.getType().equals(TypeOfState.LAST))
return st;
if (st.equals(State.BREAKING))
return State.BROKEN;
} catch (SysException ex) {
ex.printStackTrace();
}
Thread.sleep(2000);//!!!
}
} catch (IOException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (InterruptedException e) {
throw new TaskException(State.DONE_ERR, e);
} finally {
if (server != null)
server.stop(0);
}
}
public final class XMLHttpHandler implements HttpHandler {
private void setPrms(Process cp, Map<String, Object> prms, String key, Object value) {
cp.regResourceName(value, "msg." + key);
prms.put(key, value);
System.out.println("msg." + key + " = " + value);
}
private Context cntx;
public XMLHttpHandler(Context cntx) {
this.cntx = cntx;
}
public void handle(HttpExchange httpExchange) throws IOException {
Process.currentProcess().setParent(main_thread);
try {
InetSocketAddress ra = httpExchange.getRemoteAddress();
Process cp = Process.currentProcess();
Map<String, Object> prms = new HashMap<String, Object>();
setPrms(cp, prms, "protocol", httpExchange.getProtocol());
setPrms(cp, prms, "method", httpExchange.getRequestMethod());
//setPrms(cp, prms, "remote.hostName", ra.getHostName());
setPrms(cp, prms, "remote.port", ra.getPort());
setPrms(cp, prms, "remote.ip", ra.getAddress().getHostAddress());
setPrms(cp, prms, "query.path", httpExchange.getRequestURI().getPath());
String query = httpExchange.getRequestURI().getQuery();
if (query != null) {
String[] eqs = Strings.parseXVSLine(query, '/', '&');
for (int i = 0; i < eqs.length; i++) {
String eq = eqs[i];
int j = eq.indexOf('=');
if (j >= 0)
setPrms(cp, prms, "get." + eq.substring(0, j), eq.substring(j + 1));
}
setPrms(cp, prms, "query", query);
}
String ct = null;
for (Map.Entry<String, List<String>> e : httpExchange.getRequestHeaders().entrySet()) {
Object v = e.getValue();
String k = e.getKey();
if ("Content-type".equals(k))
ct = v.toString();
setPrms(cp, prms, "hdrs." + k, v.toString());
}
InputStream is = httpExchange.getRequestBody();
try {
OutputByteBuffer obb = Process.getByteBuffer(8000, is);
setPrms(cp, prms, "body", obb);
if ("POST".equals(httpExchange.getRequestMethod()) &&
ct != null &&
ct.indexOf("application/x-www-form-urlencoded") >= 0) {
String enc;
try {
enc = cntx.getPrmNvl("request.encoding", "UTF-8");
if (enc == null || enc.trim().length() == 0)
enc = "UTF-8";
} catch (SysException e2) {
enc = "UTF-8";
}
StringBuffer sb = Strings.getStringBuffer(obb.getIS(), enc);
setPrms(cp, prms, "postquery", sb);
String[] eqs = Strings.parseXVSLine(sb.toString(), '/', '&');
for (String eq : eqs) {
int j = eq.indexOf('=');
if (j >= 0)
setPrms(cp, prms, "post." + eq.substring(0, j), eq.substring(j + 1));
}
}
} catch (IOException e) {
e.printStackTrace();
throw new SysRuntimeException(e);
}
String enc;
try {
enc = cntx.getPrmNvl("response.encoding", "UTF-8");
if (enc == null || enc.trim().length() == 0)
enc = "UTF-8";
} catch (SysException e2) {
enc = "UTF-8";
}
try {
String grp_in = cntx.getPrmNvl("grp_in", "in");
String grp_out = cntx.getPrmNvl("grp_out", "out");
setPrms(cp, prms, "out.result", cntx.getPrmByFullName("update"));
Object res = cntx.getPrmByFullName(cntx.getFullName(grp_out, "body"));
if (res != null) {
long l = 0;
if (res instanceof FileInputStream) {
FileInputStream f = (FileInputStream) res;
is = f;
l = f.getChannel().size();
} else if (res instanceof Element) {
Element el = (Element)res;
OutputByteBuffer obb = new OutputByteBuffer(8000);
XMLFileWaiter.putStream(el, obb, "utf-8");
try {
obb.close();
l = obb.getLength();
} catch (IOException e1) {
e1.printStackTrace();
}
is = obb.getIS();
} else if (res instanceof OutputByteBuffer) {
is = ((OutputByteBuffer)res).getIS();
l = ((OutputByteBuffer)res).getLength();
} else if (res instanceof File) {
File f = (File)res;
cntx.log(false, "source file name = ", f.getCanonicalPath());
try {
is = new FileInputStream(f.getCanonicalPath());
l = f.length();
} catch (Throwable e) {
System.out.println(e.getMessage());
e.getStackTrace();
throw new IOException(e);
}
} else {
byte[] buf = res.toString().getBytes(enc);
is = new ByteArrayInputStream(buf);
l = buf.length;
}
Headers hd = httpExchange.getResponseHeaders();
hd.put("Content-Type", Arrays.asList("text/plain; charset=" + enc));
hd.put("Content-Length", Arrays.asList(Long.toString(l)));
String h = cntx.getFullName(grp_out, "hdrs.");
Map<String, Object> result = cntx.getGroupParams(grp_out);
for (Map.Entry<String, Object> e : result.entrySet()) {
String k = e.getKey();
if (k.indexOf(h) == 0) {
k = k.substring(h.length());
Object o = e.getValue();
String v;
if (o != null && o instanceof IDependentParam) {
IDependentParam idp = (IDependentParam)o;
try {
o = idp.getValue(cntx);
} catch (CalculateException e1) {
e1.printStackTrace();
}
}
if (o == null)
continue;
v = Strings.getString(o);
hd.put(k, Arrays.asList(v));
}
}
httpExchange.sendResponseHeaders(200, l);
OutputStream w = httpExchange.getResponseBody();
byte[] buf = new byte[8 * 1024];
int len;
while ((len = is.read(buf)) > 0) {
w.write(buf, 0, len);
}
is.close();
w.close();
} else {
httpExchange.sendResponseHeaders(503, 0);
}
} catch (SysException e) {
e.printStackTrace();
} finally {
try {
cntx.getPrmByFullName("finish", 1000);
} catch (SysException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}//!!!
}
} finally {
httpExchange.close();
}
}
}
@Override
public Set<String> dependentOn() {
// TODO Auto-generated method stub
return null;
}
@Override
public Set<String> loopDependentOn() {
// TODO Auto-generated method stub
return null;
}
}