org.vfny.geoserver.servlets.AbstractService Maven / Gradle / Ivy
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.servlets;
import org.geoserver.ows.ServiceStrategy;
import org.geoserver.ows.util.XmlCharsetDetector;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.WebApplicationContext;
import org.vfny.geoserver.ExceptionHandler;
import org.vfny.geoserver.Request;
import org.vfny.geoserver.Response;
import org.vfny.geoserver.ServiceException;
import org.vfny.geoserver.global.Data;
import org.vfny.geoserver.global.GeoServer;
import org.vfny.geoserver.global.Service;
import org.vfny.geoserver.util.PartialBufferedOutputStream2;
import org.vfny.geoserver.util.requests.readers.KvpRequestReader;
import org.vfny.geoserver.util.requests.readers.XmlRequestReader;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Represents a service that all others extend from. Subclasses should provide
* response and exception handlers as appropriate.
*
*
* It is really important to adhere to the following workflow:
*
*
* -
* get a Request reader
*
* -
* ask the Request Reader for the Request object
*
* -
* Provide the resulting Request with the ServletRequest that generated it
*
* -
* get the appropiate ResponseHandler
*
* -
* ask it to execute the Request
*
* -
* set the response content type
*
* -
* write to the http response's output stream
*
* -
* pending - call Response cleanup
*
*
*
*
*
* If anything goes wrong a ServiceException can be thrown and will be written
* to the output stream instead.
*
*
*
* This is because we have to be sure that no exception have been produced
* before setting the response's content type, so we can set the exception
* specific content type; and that Response.getContentType is called AFTER
* Response.execute, since the MIME type can depend on any request parameter
* or another kind of desission making during the execute process. (i.e.
* FORMAT in WMS GetMap)
*
*
*
* TODO: We need to call Response.abort() if anything goes wrong to allow the
* Response a chance to cleanup after itself.
*
*
* @author Gabriel Rold?n
* @author Chris Holmes
* @author Jody Garnett, Refractions Research
* @version $Id: AbstractService.java 8443 2008-02-25 13:18:59Z groldan $
*/
public abstract class AbstractService extends HttpServlet implements ApplicationContextAware {
/** Class logger */
protected static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.vfny.geoserver.servlets");
/**
* Servivce group (maps to 'SERVICE' parameter in OGC service urls)
*/
String service;
/**
* Request type (maps to 'REQUEST' parameter in OGC service urls)
*/
String request;
/**
* Application context used to look up "Services"
*/
WebApplicationContext context;
/**
* Reference to the global geoserver instnace.
*/
GeoServer geoServer;
/**
* Reference to the catalog.
*/
Data catalog;
/**
* Id of the service strategy to use.
*/
String serviceStrategy;
/**
* buffer size to use when PARTIAL-BUFFER is being used
*/
int partialBufferSize;
/**
* Cached service strategy object
*/
// ServiceStrategy strategy;
/**
* Reference to the service
*/
Service serviceRef;
private String kvpString;
// /** DOCUMENT ME! */
// protected HttpServletRequest curRequest;
/**
* Constructor for abstract service.
*
* @param service The service group the service falls into (WFS,WMS,...)
* @param request The service being requested (GetCapabilities, GetMap, ...)
* @param serviceRef The global service this "servlet" falls into
*/
public AbstractService(String service, String request, Service serviceRef) {
this.service = service;
this.request = request;
this.serviceRef = serviceRef;
}
/**
* @return Returns the "service group" that this service falls into.
*/
public String getService() {
return service;
}
/**
* @return Returns the "request" this service maps to.
*/
public String getRequest() {
return request;
}
/**
* Sets a refeference to the global service instance.
*/
public void setServiceRef(Service serviceRef) {
this.serviceRef = serviceRef;
}
/**
* @return The reference to the global service instance.
*/
public Service getServiceRef() {
return serviceRef;
}
/**
* Sets the application context.
*
* Used to process the {@link Service} extension point.
*
*/
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = (WebApplicationContext) context;
}
/**
* @return The application context.
*/
public WebApplicationContext getApplicationContext() {
return context;
}
/**
* Sets the reference to the global geoserver instance.
*/
public void setGeoServer(GeoServer geoServer) {
this.geoServer = geoServer;
}
/**
* @return the reference to the global geoserver instance.
*/
public GeoServer getGeoServer() {
return geoServer;
}
/**
* @return The reference to the global catalog instance.
*/
public Data getCatalog() {
return catalog;
}
/**
* Sets the reference to the global catalog instance.
*
*/
public void setCatalog(Data catalog) {
this.catalog = catalog;
}
/**
* @return The id used to identify the service strategy to be used.
* @see ServiceStrategy#getId()
*/
public String getServiceStrategy() {
return serviceStrategy;
}
/**
* Sets the id used to identify the service strategy to be used.
*/
public void setServiceStrategy(String serviceStrategy) {
this.serviceStrategy = serviceStrategy;
}
/**
* Determines if the service is enabled.
*
* Subclass should override this method if the service can be turned on/off.
* This implementation returns true
*
*/
protected boolean isServiceEnabled(HttpServletRequest req) {
return true;
}
/**
* Override and use spring set servlet context.
*/
public ServletContext getServletContext() {
//override and use spring
return ((WebApplicationContext) context).getServletContext();
}
/**
* DOCUMENT ME!
*
* @param request DOCUMENT ME!
* @param response DOCUMENT ME!
*
* @throws ServletException DOCUMENT ME!
* @throws IOException DOCUMENT ME!
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// implements the main request/response logic
// this.curRequest = request;
Request serviceRequest = null;
if (!isServiceEnabled(request)) {
sendDisabledServiceError(response);
return;
}
try {
Map requestParams = new HashMap();
String qString = ((this.kvpString != null) ? this.kvpString : request.getQueryString());
LOGGER.fine("reading request: " + qString);
if (this.kvpString != null) {
requestParams = KvpRequestReader.parseKvpSet(qString);
} else {
String paramName;
String paramValue;
for (Enumeration pnames = request.getParameterNames(); pnames.hasMoreElements();) {
paramName = (String) pnames.nextElement();
paramValue = request.getParameter(paramName);
requestParams.put(paramName.toUpperCase(), paramValue);
}
}
KvpRequestReader requestReader = getKvpReader(requestParams);
serviceRequest = requestReader.getRequest(request);
LOGGER.finer("serviceRequest provided with HttpServletRequest: " + request);
//serviceRequest.setHttpServletRequest(request);
} catch (ServiceException se) {
sendError(request, response, se);
return;
} catch (Throwable e) {
sendError(request, response, e);
return;
} finally {
this.kvpString = null;
}
doService(request, response, serviceRequest);
}
/**
* Sends the standard disabled service error message (a 503 error followed by an english description).
* @param response
* @throws IOException
*/
protected void sendDisabledServiceError(HttpServletResponse response)
throws IOException {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
getService() + " service is not enabled. " + "You can enable it in the web admin tool.");
}
/**
* Performs the post method. Simply passes itself on to the three argument
* doPost method, with null for the reader, because the
* request.getReader() will not have been used if this servlet is called
* directly.
*
* @param request DOCUMENT ME!
* @param response DOCUMENT ME!
*
* @throws ServletException DOCUMENT ME!
* @throws IOException DOCUMENT ME!
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response, null);
}
/**
* Performs the post method. Gets the appropriate xml reader and
* determines the request from that, and then passes the request on to
* doService.
*
* @param request The request made.
* @param response The response to be returned.
* @param requestXml A reader of the xml to be read. This is only used by
* the dispatcher, everyone else should just pass in null. This is
* needed because afaik HttpServletRequest.getReader() can not be
* used twice. So in a dispatched case we write it to a temp file,
* which we can then read in twice.
*
* @throws ServletException DOCUMENT ME!
* @throws IOException DOCUMENT ME!
*/
public void doPost(HttpServletRequest request, HttpServletResponse response, Reader requestXml)
throws ServletException, IOException {
// this.curRequest = request;
Request serviceRequest = null;
//TODO: This isn't a proper ogc service response.
if (!isServiceEnabled(request)) {
sendDisabledServiceError(response);
return;
}
// implements the main request/response logic
try {
XmlRequestReader requestReader = getXmlRequestReader();
//JD: GEOS-323, adding support for character encoding detection
// Reader xml = (requestXml != null) ? requestXml : request.getReader();
Reader xml;
if (null != requestXml) {
xml = requestXml;
} else {
/*
* `getCharsetAwareReader` returns a reader which not support
* mark/reset. So it is a good idea to wrap it into BufferedReader.
* In this case the below debug output will work.
*/
xml = new BufferedReader(XmlCharsetDetector.getCharsetAwareReader(
request.getInputStream()));
}
//JD: GEOS-323
//DJB: add support for POST loggin
if (LOGGER.isLoggable(Level.FINE)) {
if (xml.markSupported()) {
// a little protection for large POSTs (ie. updates)
// for FINE, I assume people just want to see the "normal" ones - not the big ones
// for FINER, I assume they would want to see a bit more
// for FINEST, I assume they would want to see even more
int maxChars = 16000;
if (LOGGER.isLoggable(Level.FINER)) {
maxChars = 64000;
}
if (LOGGER.isLoggable(Level.FINEST)) {
maxChars = 640000; // Bill gates says 640k is good enough for anyone
}
xml.mark(maxChars + 1); // +1 so if you read the whole thing you can still reset()
char[] buffer = new char[maxChars];
int actualRead = xml.read(buffer);
xml.reset();
LOGGER.fine("------------XML POST START-----------\n"
+ new String(buffer, 0, actualRead)
+ "\n------------XML POST END-----------");
if (actualRead == maxChars) {
LOGGER.fine("------------XML POST REPORT WAS TRUNCATED AT " + maxChars
+ " CHARACTERS. RUN WITH HIGHER LOGGING LEVEL TO SEE MORE");
}
} else {
LOGGER.fine(
"ATTEMPTED TO LOG POST XML, BUT WAS PREVENTED BECAUSE markSupported() IS FALSE");
}
}
serviceRequest = requestReader.read(xml, request);
serviceRequest.setHttpServletRequest(request);
} catch (ServiceException se) {
sendError(request, response, se);
return;
} catch (Throwable e) {
sendError(request, response, e);
return;
}
doService(request, response, serviceRequest);
}
/**
* Peforms service according to ServiceStrategy.
*
*
* This method has very strict requirements, please see the class
* description for the specifics.
*
*
*
* It has a lot of try/catch blocks, but they are fairly necessary to
* handle things correctly and to avoid as many ugly servlet responses, so
* that everything is wrapped correctly.
*
*
* @param request The httpServlet of the request.
* @param response The response to be returned.
* @param serviceRequest The OGC request to service.
*
* @throws ServletException if the strategy can't be instantiated
*/
protected void doService(HttpServletRequest request, HttpServletResponse response,
Request serviceRequest) throws ServletException {
LOGGER.info("handling request: " + serviceRequest);
if (!isServiceEnabled(request)) {
try {
sendDisabledServiceError(response);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Error writing service unavailable response", e);
}
return;
}
ServiceStrategy strategy = null;
Response serviceResponse = null;
try {
strategy = createServiceStrategy();
LOGGER.fine("strategy is: " + strategy.getId());
serviceResponse = getResponseHandler();
} catch (Throwable t) {
sendError(request, response, t);
return;
}
Map services = context.getBeansOfType(Service.class);
Service s = null;
for (Iterator itr = services.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry) itr.next();
String id = (String) entry.getKey();
Service service = (Service) entry.getValue();
if (id.toLowerCase().startsWith(serviceRequest.getService().toLowerCase().trim())) {
s = service;
break;
}
}
if (s == null) {
String msg = "No service found matching: " + serviceRequest.getService();
sendError(request, response, new ServiceException(msg));
return;
}
try {
// execute request
LOGGER.finer("executing request");
serviceResponse.execute(serviceRequest);
LOGGER.finer("execution succeed");
} catch (ServiceException serviceException) {
LOGGER.warning("service exception while executing request: " + serviceRequest
+ "\ncause: " + serviceException.getMessage());
serviceResponse.abort(s);
sendError(request, response, serviceException);
return;
} catch (Throwable t) {
//we can safelly send errors here, since we have not touched response yet
serviceResponse.abort(s);
sendError(request, response, t);
return;
}
OutputStream strategyOuput = null;
//obtain the strategy output stream
try {
LOGGER.finest("getting strategy output");
strategyOuput = strategy.getDestination(response);
LOGGER.finer("strategy output is: " + strategyOuput.getClass().getName());
String mimeType = serviceResponse.getContentType(s.getGeoServer());
LOGGER.fine("mime type is: " + mimeType);
response.setContentType(mimeType);
String encoding = serviceResponse.getContentEncoding();
if (encoding != null) {
LOGGER.fine("content encoding is: " + encoding);
response.setHeader("Content-Encoding", encoding);
}
String disposition = serviceResponse.getContentDisposition();
if (disposition != null) {
LOGGER.fine("content encoding is: " + encoding);
response.setHeader("Content-Disposition", disposition);
}
} catch (SocketException socketException) {
LOGGER.fine("it seems that the user has closed the request stream: "
+ socketException.getMessage());
// It seems the user has closed the request stream
// Apparently this is a "cancel" and will quietly go away
//
// I will still give strategy and serviceResponse
// a chance to clean up
//
serviceResponse.abort(s);
strategy.abort();
return;
} catch (IOException ex) {
serviceResponse.abort(s);
strategy.abort();
sendError(request, response, ex);
return;
}
try {
// gather response
serviceResponse.writeTo(strategyOuput);
strategyOuput.flush();
strategy.flush(response);
} catch (java.net.SocketException sockEx) { // user cancel
LOGGER.info("Stream abruptly closed by client, response aborted");
serviceResponse.abort(s);
strategy.abort();
return;
} catch (IOException ioException) { // strategyOutput error
response.setHeader("Content-Disposition", ""); // reset it so we get a proper XML error returned
LOGGER.info("Stream abruptly closed by client, response aborted");
LOGGER.log(Level.FINE, "Error writing out " + ioException.getMessage(), ioException);
serviceResponse.abort(s);
strategy.abort();
return;
} catch (ServiceException writeToFailure) { // writeTo Failure
response.setHeader("Content-Disposition", ""); // reset it so we get a proper XML error returned
serviceResponse.abort(s);
strategy.abort();
sendError(request, response, writeToFailure);
return;
} catch (Throwable help) { // This is an unexpected error(!)
response.setHeader("Content-Disposition", ""); // reset it so we get a proper XML error returned
help.printStackTrace();
serviceResponse.abort(s);
strategy.abort();
sendError(request, response, help);
return;
}
// Finish Response
// I have moved closing the output stream out here, it was being
// done by a few of the ServiceStrategy
//
// By this time serviceResponse has finished successfully
// and strategy is also finished
//
try {
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (SocketException sockEx) { // user cancel
LOGGER.warning("Could not send completed response to user:" + sockEx);
return;
} catch (IOException ioException) {
// This is bad, the user did not get the completed response
LOGGER.warning("Could not send completed response to user:" + ioException);
return;
}
LOGGER.info("Service handled");
}
/**
* Gets the response class that should handle the request of this service.
* All subclasses must implement.
*
* This method is not abstract to support subclasses that use the
* request-response mechanism.
*
*
* @return The response that the request read by this servlet should be
* passed to.
*/
protected Response getResponseHandler() {
return null;
}
/**
* This method was added in order to adapt the old style servlet services
* to the new ows dispatching interface, without having to modify the
* services themselves.
*
* @return A call to {@link #getResponseHandler()}.
*/
public final Response getResponse() {
return getResponseHandler();
}
/**
* Gets a reader that will figure out the correct Key Vaule Pairs for this
* service.
*
* Subclasses should override to supply a specific kvp reader. Default
* implementation returns null
*
* @param params A map of the kvp pairs.
*
* @return An initialized KVP reader to decode the request.
*/
protected KvpRequestReader getKvpReader(Map params) {
return null;
}
/**
* Gets a reader that will handle a posted xml request for this servlet.
*
* Subclasses should override to supply a specific xml reader. Default
* implementation returns null
*
* @return An XmlRequestReader appropriate to this service.
*/
protected XmlRequestReader getXmlRequestReader() {
return null;
}
/**
* Gets the exception handler for this service.
*
* @return The correct ExceptionHandler
*/
protected abstract ExceptionHandler getExceptionHandler();
/**
* Gets the strategy for outputting the response. This method gets the
* strategy from the serviceStrategy param in the web.xml file. This is
* sort of odd behavior, as all other such parameters are set in the
* services and catalog xml files, and this param may move there. But as
* it is much more of a programmer configuration than a user
* configuration there is no rush to move it.
*
*
* Subclasses may choose to override this method in order to get a strategy
* more suited to their response. Currently only Transaction will do
* this, since the commit is only called after writeTo, and it often
* messes up, so we want to be able to see the error message (SPEED writes
* the output directly, so errors in writeTo do not show up.)
*
*
*
* Most subclasses should not override, this method will most always return
* the SPEED strategy, since it is the fastest response and should work
* fine if everything is well tested. FILE and BUFFER should be used when
* there are errors in writeTo methods of child classes, set by the
* programmer in the web.xml file.
*
*
* @return The service strategy found in the web.xml serviceStrategy
* parameter. The code that finds this is in the init method
*
* @throws ServiceException If the service strategy set in #init() is not
* valid.
*
* @see #init() for the code that sets the serviceStrategy.
*/
protected ServiceStrategy createServiceStrategy() throws ServiceException {
// If verbose exceptions is on then lets make sure they actually get the
// exception by using the file strategy.
ServiceStrategy theStrategy = null;
if (geoServer.isVerboseExceptions()) {
theStrategy = (ServiceStrategy) context.getBean("fileServiceStrategy");
} else {
if (serviceStrategy == null) {
// none set, look up in web applicatino context
serviceStrategy = getServletContext().getInitParameter("serviceStrategy");
}
// do a lookup
if (serviceStrategy != null) {
Map strategies = context.getBeansOfType(ServiceStrategy.class);
for (Iterator itr = strategies.values().iterator(); itr.hasNext();) {
ServiceStrategy bean = (ServiceStrategy) itr.next();
if (bean.getId().equals(serviceStrategy)) {
theStrategy = bean;
break;
}
}
}
}
if (theStrategy == null) {
// default to buffer
theStrategy = (ServiceStrategy) context.getBean("bufferServiceStrategy");
}
// clone the strategy since at the moment the strategies are marked as singletons
// in the web.xml file.
try {
theStrategy = (ServiceStrategy) theStrategy.clone();
} catch (CloneNotSupportedException e) {
LOGGER.log(Level.SEVERE,
"Programming error found, service strategies should be cloneable, " + e, e);
throw new RuntimeException("Found a strategy that does not support cloning...", e);
}
// TODO: this hack should be removed once modules have their own config
if (theStrategy instanceof PartialBufferStrategy2) {
if (partialBufferSize == 0) {
String size = getServletContext().getInitParameter("PARTIAL_BUFFER_STRATEGY_SIZE");
if (size != null) {
try {
partialBufferSize = Integer.valueOf(size).intValue();
if (partialBufferSize <= 0) {
LOGGER.warning("Invalid partial buffer size, defaulting to "
+ PartialBufferedOutputStream2.DEFAULT_BUFFER_SIZE + " (was "
+ partialBufferSize + ")");
partialBufferSize = 0;
}
} catch (NumberFormatException nfe) {
LOGGER.warning("Invalid partial buffer size, defaulting to "
+ PartialBufferedOutputStream2.DEFAULT_BUFFER_SIZE + " (was "
+ partialBufferSize + ")");
partialBufferSize = 0;
}
}
}
((PartialBufferStrategy2) theStrategy).setBufferSize(partialBufferSize);
}
return theStrategy;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
protected String getMimeType() {
ServletContext servContext = getServletContext();
try {
return ((GeoServer) servContext.getAttribute("GeoServer")).getMimeType();
} catch (NullPointerException e) {
return "text/xml; charset=" + Charset.forName("UTF-8").name();
}
}
/**
* DOCUMENT ME!
*
* @param response DOCUMENT ME!
* @param content DOCUMENT ME!
*/
protected void send(HttpServletResponse response, CharSequence content) {
send(response, content, getMimeType());
}
/**
* DOCUMENT ME!
*
* @param response DOCUMENT ME!
* @param content DOCUMENT ME!
* @param mimeType DOCUMENT ME!
*/
protected void send(HttpServletResponse response, CharSequence content, String mimeType) {
try {
response.setContentType(mimeType);
response.getWriter().write(content.toString());
} catch (IOException ex) { //stream closed by client, do nothing
LOGGER.info("Stream abruptly closed by client, response aborted");
LOGGER.fine(ex.getMessage());
} catch (IllegalStateException ex) { //stream closed by client, do nothing
LOGGER.info("Stream abruptly closed by client, response aborted");
LOGGER.fine(ex.getMessage());
}
}
/**
* Send error produced during getService opperation.
*
*
* Some errors know how to write themselves out WfsTransactionException for
* instance. It looks like this might be is handled by
* getExceptionHandler().newServiceException( t, pre, null ). I still
* would not mind seeing a check for ServiceConfig Exception here.
*
*
*
* This code says that it deals with UNCAUGHT EXCEPTIONS, so I think it
* would be wise to explicitly catch ServiceExceptions.
*
*
* @param response DOCUMENT ME!
* @param t DOCUMENT ME!
*/
protected void sendError(HttpServletRequest request, HttpServletResponse response, Throwable t) {
if (t instanceof ServiceException) {
sendError(request, response, (ServiceException) t);
return;
}
LOGGER.info("Had an undefined error: " + t.getMessage());
//TODO: put the stack trace in the logger.
//t.printStackTrace();
//String pre = "UNCAUGHT EXCEPTION";
ExceptionHandler exHandler = getExceptionHandler();
ServiceException se = exHandler.newServiceException(t);
sendError(request, response, se);
//GeoServer geoServer = (GeoServer) this.getServletConfig()
// .getServletContext().getAttribute(GeoServer.WEB_CONTAINER_KEY);
//send(response, se.getXmlResponse(geoServer.isVerboseExceptions()));
}
/**
* Send a serviceException produced during getService opperation.
*
* @param response DOCUMENT ME!
* @param se DOCUMENT ME!
*/
protected void sendError(HttpServletRequest request, HttpServletResponse response,
ServiceException se) {
// first log the exception
LOGGER.log(Level.SEVERE, "Service exception occurred", se);
String mimeType = se.getMimeType(geoServer);
send(response, se.getXmlResponse(geoServer.isVerboseExceptions(), request, geoServer),
mimeType);
}
/**
* DOCUMENT ME!
*
* @param response DOCUMENT ME!
* @param result DOCUMENT ME!
*/
protected void send(HttpServletRequest httpRequest, HttpServletResponse response,
Response result) {
OutputStream responseOut = null;
try {
responseOut = response.getOutputStream();
} catch (IOException ex) { //stream closed, do nothing.
LOGGER.info("apparently client has closed stream: " + ex.getMessage());
}
OutputStream out = new BufferedOutputStream(responseOut);
ServletContext servContext = getServletContext();
response.setContentType(result.getContentType(
(GeoServer) servContext.getAttribute("GeoServer")));
try {
result.writeTo(out);
out.flush();
responseOut.flush();
} catch (IOException ioe) {
//user just closed the socket stream, do nothing
LOGGER.fine("connection closed by user: " + ioe.getMessage());
} catch (ServiceException ex) {
sendError(httpRequest, response, ex);
}
}
/**
* Checks if the client requests supports gzipped responses by quering it's
* 'accept-encoding' header.
*
* @param request the request to query the HTTP header from
*
* @return true if 'gzip' if one of the supported content encodings of
* request
, false otherwise.
*/
protected boolean requestSupportsGzip(HttpServletRequest request) {
boolean supportsGzip = false;
String header = request.getHeader("accept-encoding");
if ((header != null) && (header.indexOf("gzip") > -1)) {
supportsGzip = true;
}
if (LOGGER.isLoggable(Level.CONFIG)) {
LOGGER.config("user-agent=" + request.getHeader("user-agent"));
LOGGER.config("accept=" + request.getHeader("accept"));
LOGGER.config("accept-encoding=" + request.getHeader("accept-encoding"));
}
return supportsGzip;
}
public String getKvpString() {
return kvpString;
}
public void setKvpString(String kvpString) {
this.kvpString = kvpString;
}
}