package com.iwebpp.middleware;
import java.util.LinkedList;
import java.util.List;
import com.iwebpp.node.EventEmitter2;
import com.iwebpp.node.http.HttpServer.requestListener;
import com.iwebpp.node.http.IncomingMessage;
import com.iwebpp.node.http.ServerResponse;
public class Connect
extends EventEmitter2
implements requestListener {
private static final String TAG = "Connect";
private String parent;
private class stack_b {
private String path;
private requestListener cb;
protected stack_b(String path, requestListener cb) {
this.path = path;
this.cb = cb;
}
}
private List<stack_b> stack;
public Connect() {
parent = null;
stack = new LinkedList<stack_b>();
}
public Connect(String path) {
parent = path;
stack = new LinkedList<stack_b>();
}
public Connect setParent(String path) {
parent = path;
return this;
}
public String getParent() {
return parent!=null? parent : "";
}
/*
* @description
* append callback on default path /
* */
public Connect use(requestListener cb) throws Exception {
return use("/", cb);
}
/*
* @description
* append callback on path
* */
public Connect use(String path, requestListener cb) throws Exception {
debug(TAG, "added request cb:"+cb+" on "+path);
// normalize
if (path == null)
path = "/";
else if (path.charAt(0) != '/')
path = "/" + path;
// queue request handler
stack.add(new stack_b(path, cb));
this.emit("add:"+path, cb);
return this;
}
/*
* @description
* take out callback on default path /
* */
public Connect unuse(requestListener cb) throws Exception {
return unuse("/", cb);
}
/*
* @description
* take out callback on path
* */
public Connect unuse(String path, requestListener cb) throws Exception {
debug(TAG, "removed request cb:"+cb+" on "+path);
// normalize
if (path == null)
path = "/";
else if (path.charAt(0) != '/')
path = "/" + path;
// cost operation
for (stack_b b : stack)
if (b.path.equalsIgnoreCase(path) && b.cb == cb)
stack.remove(b);
this.emit("del:"+path, cb);
return this;
}
/*
* @description
* take out all callback on path
* */
public Connect unuse(String path) throws Exception {
debug(TAG, "removed request on "+path);
// normalize
if (path == null)
path = "/";
else if (path.charAt(0) != '/')
path = "/" + path;
// cost operation
for (stack_b b : stack)
if (b.path.equalsIgnoreCase(path))
stack.remove(b);
this.emit("del:"+path+":all");
return this;
}
/*
* @description
* take out all callback on all path
* */
public Connect unuse() throws Exception {
debug(TAG, "removed all requests");
stack.clear();
this.emit("del:/any:all");
return this;
}
@Override
public void onRequest(IncomingMessage req, ServerResponse res)
throws Exception {
String path = req.url();
debug(TAG, "request on "+path);
// check if embedded stack
if (parent != null && !parent.equals("/")) {
if (path.startsWith(parent)) {
path = path.substring(parent.length());
debug(TAG, "child path: "+path);
} else
return;
}
// run stack until response header sent out
for (stack_b b : stack) {
// check embedded path
if (b.cb instanceof Connect) {
debug(TAG, "embedded path handle");
Connect embedded = (Connect)b.cb;
// set parent path
String ppath = null;
if (!b.path.equals("/")) ppath = b.path;
if (parent!=null && !parent.equals("/")) ppath = ppath!=null ? parent+ppath : parent;
embedded.setParent(ppath);
embedded.onRequest(req, res);
// check if res.sent
if (res.headersSent()) {
debug(TAG, "embedded response sent done, stop stack");
break;
}
} else {
// check absolute path
if (path.startsWith(b.path)) {
debug(TAG, "absolute path handle");
// override req.url ???
String temp = req.url(); req.url(path);
b.cb.onRequest(req, res);
// restore req.url ???
req.url(temp);
// check if res.sent
if (res.headersSent()) {
debug(TAG, "absolute response sent done, stop stack");
break;
}
}
}
}
}
}