/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.gws.p.router.web;
import com.sun.xml.ws.transport.http.HttpAdapter;
import ru.codeinside.gws.p.adapter.ProviderEntry;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.TreeSet;
import java.util.logging.Logger;
final public class Chain {
final HttpServletRequest req;
final HttpServletResponse resp;
final ServletAdapterRegistrar registrar;
final long startAt = System.currentTimeMillis();
final Registry registry = Registry.REGISTRY.get();
public Chain(final HttpServletRequest req, final HttpServletResponse resp, final ServletAdapterRegistrar registrar) {
this.req = req;
this.resp = resp;
this.registrar = registrar;
}
final static class Result {
final Cmd cmd;
final boolean sleep;
Result(final Cmd cmd, final boolean sleep) {
this.cmd = cmd;
this.sleep = sleep;
}
}
interface Cmd {
Result process() throws IOException;
}
public void process() throws IOException {
Cmd cmd = new GetInfoCmd();
while (cmd != null) {
final Result result = cmd.process();
if (result == null) {
cmd = null;
} else {
cmd = result.cmd;
if (result.sleep) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
timeOut();
cmd = null;
}
if (cmd != null && System.currentTimeMillis() - startAt > 20000L) {
timeOut();
cmd = null;
}
}
}
}
}
private void timeOut() throws IOException {
//TODO: если SOAP запрос, вернуть SOAP ошибку!
resp.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT);
}
private void notFound(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//TODO: если SOAP запрос, вернуть SOAP ошибку!
resp.sendError(HttpServletResponse.SC_NOT_FOUND, req.getPathInfo());
}
final class RegistrarCmd implements Cmd {
final String service;
public RegistrarCmd(String service) {
this.service = service;
}
@Override
public Result process() throws IOException {
final ProviderEntry entry = registry.getProviderEntry(service);
if (entry == null || entry.wsService == null) {
return new Result(this, true);
}
registrar.createEndpoint(service, entry);
return new Result(new ProcessCmd(service), false);
}
}
final class ProcessCmd implements Cmd {
final String service;
ProcessCmd(String service) {
this.service = service;
}
@Override
public Result process() throws IOException {
final ProviderEntry entry = registry.getProviderEntry(service);
if (entry == null || entry.servletAdapter == null) {
return new Result(new RegistrarCmd(service), true);
}
if (!"get".equalsIgnoreCase(req.getMethod())) {
// Ждём только SOAP
if (entry.protocol == null || entry.declarant == null) {
return new Result(this, true);
}
}
entry.servletAdapter.invokeAsync(registrar.context, req, resp, new HttpAdapter.CompletionCallback() {
@Override
public void onCompletion() {
}
});
return null;
}
}
final class CheckProviderCmd implements Cmd {
@Override
public Result process() throws IOException {
final String service = getService(req);
if (registry == null || null == registry.getProviderEntry(service)) {
notFound(req, resp);
return null;
}
return new Result(new WsdlCmd(service), false);
}
}
static String getService(HttpServletRequest req) {
final String pathInfo = req.getPathInfo();
int slash = pathInfo.indexOf('/', 1);
if (slash < 0) {
slash = pathInfo.length();
}
return pathInfo.substring(1, slash);
}
final class WsdlCmd implements Cmd {
final String service;
public WsdlCmd(String service) {
this.service = service;
}
@Override
public Result process() throws IOException {
final ProviderEntry entry = registry.getProviderEntry(service);
if (entry == null || entry.wsService == null) {
return new Result(this, true);
}
if ("get".equalsIgnoreCase(req.getMethod())) {
final String pathInfo = req.getPathInfo();
if (pathInfo.endsWith(".xsd")) {
int slash = pathInfo.indexOf('/', 1);
final String xsd = pathInfo.substring(slash);
try {
String baseUri = entry.wsdl.toURI().toString();
baseUri = baseUri.substring(0, baseUri.lastIndexOf('/'));
resp.setContentType("text/xml;charset=utf-8");
InputStream input = new URL(baseUri + xsd).openStream();
ServletOutputStream output = resp.getOutputStream();
byte[] buffer = new byte[1024];
int n;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
input.close();
output.close();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
return new Result(new RegistrarCmd(service), false);
}
}
final class GetInfoCmd implements Cmd {
@Override
public Result process() throws IOException {
final String pathInfo = req.getPathInfo();
if (pathInfo == null || pathInfo.equals("/")) {
if ("get".equalsIgnoreCase(req.getMethod())) {
resp.setContentType("text/html; charset=utf8");
final PrintWriter writer = resp.getWriter();
writer.println("<html><body><h1>Web Service Registry</h1><ul>");
TreeSet<String> names = new TreeSet<String>(registry.names());
for (String name : names) {
writer.println("<li><a href=\"" + name + "/\">" + name + "</a></li>");
}
writer.println("</ul></body></html>");
writer.close();
} else {
Logger.getLogger(getClass().getName()).warning("Не найден '" + pathInfo + "' /" + req.getMethod());
notFound(req, resp);
}
return null;
}
return new Result(new CheckProviderCmd(), false);
}
}
}