OGCFrontController
Status: alpha (2008/09/15)
Design and implementation documentation for the deegree3 OGCFrontController for deegree3/OGCWebServices.
1. Requirements
- Acts as the single http communication entry point to deegree web services (WPS, WMS, WFS, CSW,...)
- Each service has a specific subcontroller, that is responsible for a service-specific protocol.
- Determines the service type (WPS, WPVS, WMS, WFS, ...) and dispatches the request to the appropriate subcontroller.
Problem: How do we determine the responsible subcontroller?
- Handle KVP (GET), KVP (POST), XML (POST), SOAP (POST)
- Streaming: Necessary to enable the processing of arbitrary large XML documents with a constant memory footprint
Buffering: Output may be buffered before it is returned, to allow changes to the response. This allows to set header like Content-Length after the response is generated, or to change the whole response e.g after an exception.
- DCP determination strategy must not rely on the information in "content-type" header. Problematic are POST requests. OGC specifies "text/xml" for XML and "application/x-www-form-urlencoded" for KVP, but we want to cope with buggy clients as well that don't respect this.
A subcontroller must have access to every information sent in the HttpServletRequest object. This allows the processing of Multipart messages.
- Some services need to send multipart responses (like WCS 1.1).
- Services need to store files that can be accessed by a client later.
1.1. Multipart
Some OGC specifications require MIME multipart requests and/or responses. To process these requests or generate these responses a subcontoller needs access to the HTTP headers. Since there are different subtypes of the Multipart MIME-type (mixed, Related, etc.) a general support for multiparts in the HttpServlet{Request,Response}Wrapper may not be feasible. A generic wrapper or utility class that can be extended would still be useful, though, since they all share the same boundary encoding (a randomized token to separate each part, content-length based encoding is not possible).
MIME (incl. Multipart) Multipart/Related (required for WCS 1.1)
2. Wishlist
3. Current status
This subsystem is in alpha status.
4. Roadmap
5. Design decisions / implementation
5.1. Frontcontroller/service interaction
In deegree 3, we will follow a separation of the service functionality and the processing of http requests.
Responsibilites of the frontcontroller (http layer) component:
- Acts as the single http communication entry point to deegree web services (WPS, WMS, WFS, CSW,...)
- Each service has a specific subcontroller, that is responsible for a service-specific protocol.
- Determines the service type (WPS, WPVS, WMS, WFS, ...) and dispatches the request to the appropriate subcontroller.
Problem: How do we determine the responsible subcontroller?
Possible solutions:
1. For an incoming request, each subcontroller is queried if it is responsible for handling the request.
- Pro:
- Very flexible. Each controller can implement its own mechanism to determine if it is responsible.
- In the worst-case, each subcontroller must analyze a request.
- Not very convenient.
- What does the controller actually do?
2. The frontcontroller determines the responsible subcontroller using a fixed strategy. KVP: service-attribute, XML (OGC): namespace of root element, XML (SOAP): namespace of child element of SOAP body.
- Pro:
- Simple central implementation. Map service identifiers to subcontrollers.
- What if one of the determination strategies is not applicable?
The latter option is quite well defined for OGC services. However, it restricts the frontcontroller to a fixed strategy for determining the responsible service. In order to cope with special determination strategies for non OGC-services, we suggest that such services should implement their own servlet.
To emphasize that the generic frontcontroller will only work for OGC-style communications, the frontcontroller will be named OGCFrontController.
5.2. Architecture
It seems that the frontcontroller has to implement a specific strategy for determing the responsible service for each protocol supported by OGC-webservices:
- KVP: Evaluate 'service' parameter
- XML: Evaluate namespace of root element
- SOAP: Evaluate namespace of soap body child element
In order to apply the corresponding strategy, the frontcontroller has to determine the protocol-type first. To avoid code duplication and to ease implementing of service subcontrollers, it seems appropriate to define protocol specific methods in the subcontroller interface:
public interface Subcontroller {
/**
* Called by the {@link OGCFrontController} to allow this <code>Subcontroller</code> to handle a KVP request.
*
* @param request
* KVP request to the corresponding OGC service
* @param response
* response that is sent to the client
* @throws ServletException
* @throws IOException
*/
public void doKVP( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException;
/**
* Called by the {@link OGCFrontController} to allow this <code>Subcontroller</code> to handle an XML request.
*
* @param request
* XML request to the corresponding OGC service
* @param response
* response that is sent to the client
* @throws ServletException
* @throws IOException
*/
public void doXML( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException;
/**
* Called by the {@link OGCFrontController} to allow this <code>Subcontroller</code> to handle a SOAP request.
*
* @param request
* SOAP request to the corresponding OGC service
* @param response
* response that is sent to the client
* @throws ServletException
* @throws IOException
*/
public void doSOAP( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException;
}
If the subcontroller needs to distinguish between POST and GET requests, it can do so by calling #getMethod() on the request parameter.
Basic architectural layout:
Following UML diagram shows the structural layout of the FrontController and it's sub controllers.
5.3. Dispatching algorithm
The dispatching algorithm is shown in the following activity diagram.
Basic structure of package org.deegree.services:
org.deegree.services.controller: Contains the FrontController classes.
org.deegree.services.controller.[ServiceName]: Containing the subcontroller for service [ServiceName] as well as XMLAdapters needed to parse the service specific requests.
5.4. Configuration
The services as well as the FrontController (and it's subcontrollers) need to be configured. To realize this, we would like to propose, the separatation between the frontcontroller configuration and the service (not it's controller) configuration. The following schematic overview clarifies our design.
The web.xml (needed by the serlvet container) only defines the location of the servlet (FrontController) and optionally the location of it's configuration. We would like to relieve the web.xml to define which services actually are adressable, and instead put this information in the FrontController configuration.
The FrontController configuration will contain the standard provider/contact values (which are often common to all webservices, but can be overwritten if necessary) as well as the configuration of each subcontroller.
The service configuration does not need to know about it's subcontroller configuration and thus needs it's own configuration file, located inside the org.deegree.[ServiceName] package. For a wms this file could for example contain the layers and their datasources.
5.5. HTTPRequestWrapper/HTTPResponseWrapper
The servlet requests and response objects will be wrapped to allow some deegree extensions like buffering. See deegree3/HTTPRequestResponseWrapper for a discussion on the requirements and implementation.
5.6. Handling of Credentials
deegree is able to handle different kinds of user credentials (e.g. username/password) in order to facilitate authentication against secured services. Since requirements to credential management may change over time (e.g. by including Webservice Security mechanisms, Shibboleth, OpenID, et.al.), the deegree-internal mechanisms do not rely on the specifics of the security mechanisms. Credentials will be extracted from a request by the OGCFrontController and stored inside a org.deegree.services.controller.RequestContext object. RequestContext is a Java Bean providing getters and setters for username, password, tokenID, and requestedBaseURL. OGCFrontController initializes a RequestContext as an java.lang.InheritedThreadLocal instance, thus providing thread-based access to credentials.
Each instance interested in those information can obtain the RequestContext from the OGCFrontController by accessing the getContext() method.
The relevant classes and their interdependencies are illustrated in this figure.
Access and initialization of the RequestContext object is illustrated using the deegree3/ProcessingService as an example.