The new APIs proposed for servlet 3.0 included in 7.0.0pre0 are:
- ServletContext:
- addServlet, addServletMapping, addFilter, addFilterMapping
- Cookie:
- setHttpOnly, isHttpOnly
- ServletRequest:
- getServletContext, getServletResponse, suspend, resume, complete, isSuspended, isResumed, isTimeout, isInitial
- ServletResponse:
- disable, enable, isDisabled
- ServletRequestListener:
- requestSuspended, requestResumed, requestCompleted
The following 4 use-cases show some of the diverse ways this API can greatly improve your web-1.0 and web-2.0 applications.
Ajax Cometd
Quality of Service Filter
With the QoSFilter in 7.0.0pre0, this is taken a step further, so that requests may be assigned a priority based on extensible criteria (eg authenticated user or type of user), and higher priority users get preferential access to the protected resource.
Requests that enter the filter for the first time try to acquire the _passes semaphore, which limits the number of requests that can simultaneously acquire it:
if (request.isInitial())
{
accepted=_passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS);
if (accepted)
chain.doFilter(request,response);
if (!accepted)
{
request.suspend();
int priority = getPriority(request);
_queue[priority].add(request);
return;
}
finally
{
if (accepted)
{
for (int p=_queue.length;p-->0;)
{
ServletRequest req=_queue[p].poll();
if (req!=null)
{
req.resume();
break;
}
}
_passes.release();
}
}
isInitial()
and thus forcefully acquire the semaphore and proceed to call the filter chain: if (request.isInitial())
{
...
}
else if (request.isResumed())
{
_passes.acquire();
accepted=true;
}
...
if (accepted)
chain.doFilter(request,response);
Asynchronous Web Services
threadful waiting for the responses:
It get’s even better if multiple ws calls are required. The synchronous approach must do them in series, so the total time and thread hold time blows out to 2700ms for 3 requests. With the asynchronous API, the three ws requests are sent in parallel and the total time is 890ms, almost the same for a single request, and the thread is only held for 8ms. Again the thread could be used to service many other requests, rather than waiting idly wasting resources!
Asynchronous Web Proxy
The request to be proxied is copied into a HttpExchange, with a little bit of process (deleted here) for standard proxy stuff:
HttpExchange exchange = new HttpExchange()
{
...
};
exchange.setMethod(request.getMethod());
exchange.setURI(uri);
...
Enumeration enm = request.getHeaderNames();
while (enm.hasMoreElements())
{
String hdr=(String)enm.nextElement();
...
Enumeration vals = request.getHeaders(hdr);
while (vals.hasMoreElements())
{
String val = (String)vals.nextElement();
exchange.setRequestHeader(lhdr,val);
}
}
if (hasContent)
exchange.setRequestContentSource(in);
Once the HttpExchange has been constructed and configured it is asynchronously sent and the current requests is suspended while a responses is waited for:
_client.send(exchange);
request.suspend();
The processing of the proxy response is all done in call back methods supplied to the construction of the HttpExchange (not shown above):
HttpExchange exchange = new HttpExchange()
{
protected void onResponseStatus(Buffer version,
int status,
Buffer reason)
{
if (reason!=null && reason.length()>0)
response.setStatus(status,reason.toString());
else
response.setStatus(status);
}
protected void onResponseHeader(Buffer name,
Buffer value)
{
...
String s = name.toString().toLowerCase();
if (!_DontProxyHeaders.contains(s))
response.addHeader(name.toString(),value.toString());
}
protected void onResponseContent(Buffer content)
{
content.writeTo(out);
}
protected void onResponseComplete() throws IOException
{
request.complete();
}
}
The callbacks allow the real response status to be set, the headers to be copied over (with some more hidden processing), the content to be written and eventually the original response is completed.
Because the response has already been given a status, headers and content, there is no need to resume the request in order to generate a response.
This approach will allow scalable proxies to be implemented as standard java servlets, which will in turn allow some arbitrary fancy business logic to be incorporated into these proxies.