Friday, January 8, 2010

Extend GeoServer with customized OWS service :: part 3

In previous post of this series, I created the application context for “ags-ows” service project and also register a java bean of type org.geoserver.platform.Service in it (a bean instance of ArcGISServerOWSService along with the service name ‘ags-ows’ and version ‘1.0.0’ are passed in into constructor) so that GeoServer’s ows dispatcher can be reused to redirect requests to “ags-ows” service. A set of KvpParsers were also created and registered in application context to parse request parameters. So in this post, I will move onto AgsOwsExportRequest which is the request bean class for “ags-ows” service, and AgsOwsExportRequestKvpReader (a subclass of KvpRequestReader) which is used to to create request bean from parsed objects of request parameters.

Request bean and KvpRequestReader

A request bean is basically a java object carrying all parsed parameter key-value pairs (as well as their getter and setter methods) of a specific service operation’s request. For example GeoServer’s WMS service has GetMap operation so which uses GetMapRequest (org.vfny.geoserver.wms.requests.GetMapRequest) bean, and same idea GetCapabilities operation has WMSCapabilitiesRequest bean. Now for “ags-ows” service, since “export” is the only operation declared in ArcGISServerOWSService, I will create one request bean class and call it AgsOwsExportRequest (below is a sample implementation that omits getters and setters):
1: public class AgsOwsExportRequest {
3:   private LayerInfo[] layers;
4:   private Envelope bbox;
5:   private AgsOwsExportSize size;  
6:   private CoordinateReferenceSystem imageSR;  
7:   private CoordinateReferenceSystem bboxSR;
8:   private boolean transparent;
9:   private Color bgColor = Color.WHITE;
11:         public AgsOwsExportRequest() {}
12:        /*
13:         * omitted getter and setter methods
14:         * you need to add getter and setter in your own code 
15:         */
16: }
you probably notice that each request bean parameter represents one request parameter of “ags-ows” service, and the type of the parameter matches the binding class of parameter’s kvp parser. (e.g. AgsOwsKvpLayersParser binds to List<LayerInfo>, AgsOwsKvpSizeParser binds to AgsOwsExportSize class etc.)

Usually an OWS service’s operation logic takes its own request bean as input parameter (that’s why you saw AgsOwsExportRequest in previous post which I didn’t explain much then). Before the dispatcher redirects request the a service operation logic for further processing, it will create an instance of appropriate type of request bean and pass it in, and it’s actually a KvpRequestReader subclass’s job to create such request bean and populate it with parsed parameter objects from kvp parsers. So I created AgsOwsExportRequestKvpReader as below, which extends KvpRequestReader:
1: public class AgsOwsExportRequestKvpReader extends KvpRequestReader {
4:   public AgsOwsExportRequestKvpReader() {
5:     super(AgsOwsExportRequest.class);    
6:   }
8:   @Override
9:   public Object createRequest() throws Exception {
10:     AgsOwsExportRequest requestBean = new AgsOwsExportRequest();    
11:     return requestBean;
12:         }
14:   @Override
15:   public Object read(Object request, Map kvp, Map rawKvp) throws Exception {
16:     AgsOwsExportRequest exportRequest = (AgsOwsExportRequest), kvp, rawKvp);
17:     /*
18:      * do any specific setting for AgsOwsExportRequest request bean instance - 
19:      * - based on kvp and rawKvp 
20:      */
21:     // TODO: here shall I set default value for certain parameters -
22:     // - if they are missing from kvp?    
23:     return exportRequest;
24:   }
25: }
To extend KvpRequestReader, you basically override its createRequest() and read() method, and optionally set attribute “filter”.
  • createRequest() creates and returns a new instance of appropriate request bean object. Default creatRequest() does that by creating the new instance reflectively using KvpRequestReader.requestBean class (you set that class in constructor), but if you need to set extra attribute of request bean object then you should probably override it.
  • read() is usually called in ows dispather, and it takes a request bean instance created by createReques() as well as kvp (java.util.Map) parsed by KvpParsers and unparsed raw kvp (java.util.Map), and it is suppose to loop through each key-value pair of parsed kvp map and set the applicable value in request bean instance if there is a setter defined for the key.
  • filter” is an optional attribute (through setFilter(Set<String> filter)) you can set so that certain keys in kvp can be filtered out without setting the its value to request bean instance.
Finally as always, you need register your KvpRequestReader subclass in application context (but you don’t need do so for request bean class):
1:   <bean id="agsOwsExportKvpRequestReader" 
2:     class="org.geoserver.ows.argisserver.kvp.AgsOwsExportRequestKvpReader">
3:   </bean>
Now it’s time to validate what I’ve added in “ags-ows” service project in this post so far. Restart GeoServer in debug mode, and set a break point in org.geoserver.ows.Dispatcher’s parseRequestKvp method (see highlighted line below), and send a “ags-ows” service request:

1:     Object parseRequestKVP(Class type, Request request)
2:         throws Exception {
3:         KvpRequestReader kvpReader = findKvpRequestReader(type);
5:         if (kvpReader != null) {
6:             //check for http request awareness
7:             if (kvpReader instanceof HttpServletRequestAware) {
8:                 ((HttpServletRequestAware) kvpReader).setHttpRequest(request.httpRequest);
9:             }
11:             Object requestBean = kvpReader.createRequest();
13:             if (requestBean != null) {
14:                 requestBean =, request.kvp, request.rawKvp);
15:             }
17:             return requestBean;
18:         }
20:         return null;
21:     }
when it stops at the break point, check if variable “requestBean” is of class AgsOwsExportRequest, and also check if those attributes of AgsOwsExportRequest (e.g. “layers”, “bbox”, “imageSR” etc.) are populated with correct type of object values from kvp parsers. If so, it means AgsOwsExportRequest and AgsOwsExportRequestKvpReader are working as expected.

By now enough logics and functions have been added into “ags-ows” service to enable it to parse the request from client,  in next post of this series, I will discuss more on the whole picture of how an ows request is processed by GeoServer OWS dispatcher, which is also a good half-way summary of what I've done so far.

No comments:

Post a Comment