/* 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 com.orci.geoserver.wfs.getnearest;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.geotools.filter.Filter;
import org.geotools.filter.FilterHandler;
import org.vfny.geoserver.wfs.Query;
import org.vfny.geoserver.wfs.servlets.WFService;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* Uses SAX to extact a GetFeature query from and incoming GetFeature
* request XML stream.<p>Note that this Handler extension ignores Filters
* completely and must be chained as a parent to the PredicateFilter method in
* order to recognize them. If it is not chained, it will still generate valid
* queries, but with no filtering whatsoever.</p>
*
* @author Rob Hranac, TOPP
* @version $Id: FeatureHandler.java,v 1.7 2004/02/13 19:30:39 dmzwiers Exp $
*/
public class GetNearestHandler extends XMLFilterImpl implements ContentHandler, FilterHandler {
/** Class logger */
private static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.vfny.geoserver.requests.wfs");
/** Service handling the request */
private WFService service;
/** Internal get feature request for construction. */
private GetNearestRequest request = null;
/** Tracks tag we are currently inside: helps maintain state. */
private String insideTag = new String();
/** Boolean to flag whether or not we are inside a query */
private boolean insideQuery = false;
/** Tracks current query */
private Query currentQuery = new Query();
/**
* Collects string chunks in {@link #characters(char[], int, int)}
* callback to be handled at the beggining of {@link #endElement(String,
* String, String)}
*/
private StringBuffer characters = new StringBuffer();
/**
* Empty constructor.
*/
public GetNearestHandler(WFService service) {
super();
this.service = service;
request = new GetNearestRequest(service);
}
/**
* Returns the GetFeature request.
*
* @param req DOCUMENT ME!
*
* @return The request read by this handler.
*/
public GetNearestRequest getRequest(HttpServletRequest req) {
request.setHttpServletRequest(req);
return request;
}
/**
* Notes the start of the element and sets type names and query
* attributes.
*
* @param namespaceURI URI for namespace appended to element.
* @param localName Local name of element.
* @param rawName Raw name of element.
* @param atts Element attributes.
*
* @throws SAXException When the XML is not well formed.
*/
public void startElement(String namespaceURI, String localName, String rawName, Attributes atts)
throws SAXException {
LOGGER.finest("at start element: " + localName);
characters.setLength(0);
// at start of element, set inside flag to whatever tag we are inside
insideTag = localName;
// if at a query element, empty the current query, set insideQuery
// flag, and get query typeNames
if (insideTag.equals("Query")) {
currentQuery = new Query();
insideQuery = true;
for (int i = 0, n = atts.getLength(); i < n; i++) {
String name = atts.getLocalName(i);
String value = atts.getValue(i);
LOGGER.finest("found attribute '" + name + "'=" + value);
if (name.equals("typeName")) {
currentQuery.setTypeName(value);
} else if (name.equals("handle")) {
currentQuery.setHandle(value);
}
}
} else if (insideTag.equals("GetNearestFeature")) {
request = new GetNearestRequest(service);
for (int i = 0; i < atts.getLength(); i++) {
String curAtt = atts.getLocalName(i);
if (curAtt.equals("outputFormat")) {
LOGGER.finest("found outputFormat: " + atts.getValue(i));
request.setOutputFormat(atts.getValue(i));
}
}
}
}
/**
* Notes the end of the element exists query or bounding box.
*
* @param namespaceURI URI for namespace appended to element.
* @param localName Local name of element.
* @param rawName Raw name of element.
*
* @throws SAXException When the XML is not well formed.
*/
public void endElement(String namespaceURI, String localName, String rawName)
throws SAXException {
LOGGER.finer("at end element: " + localName);
handleCharacters();
// as we leave query, set insideTag to "NULL" (otherwise the stupid
// characters method picks up external chars)
insideTag = "NULL";
// set insideQuery flag as we leave the query and add the query to the
// return list
if (localName.equals("Query")) {
LOGGER.finest("adding query: " + currentQuery.toString());
insideQuery = false;
request.addQuery(currentQuery);
} else if (localName.equals("Point")) {
request.setPoint(characters.toString());
} else if (insideTag.equals("MaxRange")) {
request.setMaxRange(characters.toString());
}
}
/**
* Checks if inside parsed element and adds its contents to the
* appropriate variable.
*
* @param ch URI for namespace appended to element.
* @param start Local name of element.
* @param length Raw name of element.
*
* @throws SAXException When the XML is not well formed.
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
characters.append(ch, start, length);
}
/**
* Gets a filter and adds it to the appropriate query (or queries).
*
* @param filter (OGC WFS) Filter from (SAX) filter.
*/
public void filter(Filter filter) {
LOGGER.finest("found filter: " + filter.toString());
if (insideQuery) {
LOGGER.finest("add filter " + filter + " to query: " + currentQuery);
currentQuery.addFilter(filter);
} else {
LOGGER.finest("adding filter to all queries: " + filter);
for (int i = 0, n = request.queries.size(); i < n; i++) {
Query query = (Query) request.queries.get(i);
Filter queryFilter = query.getFilter();
if (queryFilter != null) {
query.addFilter(queryFilter.and(filter));
} else {
query.addFilter(filter);
}
}
}
}
/**
* Handles the string chunks collected in {@link #characters}.
*/
private void handleCharacters() {
if (characters.length() == 0) {
return;
}
// if inside a property element, add the element
if (insideTag.equals("PropertyName")) {
String name = characters.toString().trim();
characters.setLength(0);
LOGGER.finest("found property name: " + name);
currentQuery.addPropertyName(name);
}
}
}