teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5993: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5993: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.server; ingo@1400: teichmann@5859: import com.google.gwt.user.server.rpc.RemoteServiceServlet; teichmann@5859: aheinecke@5818: import java.io.ByteArrayOutputStream; ingo@1400: import java.io.IOException; teichmann@5859: import java.io.InputStream; teichmann@5859: import java.io.UnsupportedEncodingException; teichmann@5859: ingo@1400: import java.net.URL; ingo@1400: import java.net.URLConnection; teichmann@5859: ingo@1402: import java.util.ArrayList; ingo@1400: import java.util.List; ingo@1402: ingo@1400: import org.apache.log4j.Logger; ingo@1400: teichmann@5835: import org.dive4elements.artifacts.common.utils.XMLUtils; ingo@1400: teichmann@5859: import org.dive4elements.river.client.client.services.GFIService; teichmann@5859: teichmann@5835: import org.dive4elements.river.client.shared.exceptions.ServerException; teichmann@5859: teichmann@5835: import org.dive4elements.river.client.shared.model.AttributedTheme; teichmann@5835: import org.dive4elements.river.client.shared.model.FeatureInfo; teichmann@5835: import org.dive4elements.river.client.shared.model.FeatureInfoResponse; teichmann@5835: import org.dive4elements.river.client.shared.model.Theme; ingo@1400: teichmann@5859: import org.w3c.dom.Document; teichmann@5859: import org.w3c.dom.Node; teichmann@5859: import org.w3c.dom.NodeList; ingo@1400: ingo@1400: /** ingo@1400: * @author Ingo Weinzierl ingo@1400: */ ingo@1400: public class GFIServiceImpl ingo@1400: extends RemoteServiceServlet ingo@1400: implements GFIService ingo@1400: { ingo@1400: public static final String ERR_NO_VALID_GFI_URL = ingo@1400: "error_no_valid_gfi_url"; ingo@1400: ingo@1400: public static final String ERR_GFI_REQUEST_FAILED = ingo@1400: "error_gfi_req_failed"; ingo@1400: ingo@1400: public static final String ERR_PARSING_RESPONSE_FAILED = ingo@1400: "error_gfi_parsing_failed"; ingo@1400: ingo@1400: teichmann@8203: private static final Logger log = ingo@1400: Logger.getLogger(GFIServiceImpl.class); ingo@1400: ingo@1400: ingo@1400: /** aheinecke@5794: * @param theme ingo@1400: * @param format ingo@1400: * @param bbox ingo@1400: * @param height ingo@1400: * @param width ingo@1400: * @param x ingo@1400: * @param y ingo@1400: * ingo@1400: * @return ingo@1400: */ aheinecke@5818: public FeatureInfoResponse query( aheinecke@5794: Theme theme, ingo@1400: String format, ingo@1400: String bbox, ingo@1400: String projection, ingo@1400: int height, ingo@1400: int width, ingo@1400: int x, ingo@1400: int y ingo@1400: ) throws ServerException ingo@1400: { teichmann@8203: log.info("GFIServiceImpl.query"); ingo@1400: ingo@1400: String path = createGetFeautureInfoURL( aheinecke@5794: theme, format, bbox, projection, height, width, x, y); ingo@1402: teichmann@8203: log.debug("URL=" + path); ingo@1400: ingo@1400: try { ingo@1400: URL url = new URL(path); ingo@1400: ingo@1400: URLConnection conn = url.openConnection(); ingo@1400: conn.connect(); ingo@1400: ingo@1400: InputStream is = conn.getInputStream(); ingo@1400: ingo@1402: return parseResponse(is); ingo@1400: ingo@1400: } ingo@1400: catch (IOException ioe) { teichmann@8203: log.warn(ioe, ioe); ingo@1400: } ingo@1400: ingo@1400: throw new ServerException(ERR_GFI_REQUEST_FAILED); ingo@1400: } ingo@1400: ingo@1400: ingo@1400: /** ingo@1400: * @param map aheinecke@5794: * @param theme ingo@1400: * @param format ingo@1400: * @param x ingo@1400: * @param y ingo@1400: * ingo@1400: * @return ingo@1400: */ ingo@1400: protected String createGetFeautureInfoURL( aheinecke@5794: Theme theme, ingo@1400: String infoFormat, ingo@1400: String bbox, ingo@1400: String projection, ingo@1400: int height, ingo@1400: int width, ingo@1400: int x, ingo@1400: int y ingo@1400: ) throws ServerException ingo@1400: { aheinecke@5794: String url = getUrl(theme); ingo@1400: ingo@1400: if (url == null || url.length() == 0) { ingo@1400: throw new ServerException(ERR_NO_VALID_GFI_URL); ingo@1400: } ingo@1400: aheinecke@5794: String layers = ((AttributedTheme)theme).getAttr("layers"); ingo@1400: ingo@1400: StringBuilder sb = new StringBuilder(); ingo@1400: sb.append(url); ingo@1400: ingo@1400: if (url.indexOf("?") < 0) { ingo@1400: sb.append("?SERVICE=WMS"); ingo@1400: } ingo@1400: else { ingo@1400: sb.append("&SERVICE=WMS"); ingo@1400: } ingo@1400: ingo@1400: sb.append("&VERSION=1.1.1"); ingo@1400: sb.append("&REQUEST=GetFeatureInfo"); ingo@1400: sb.append("&LAYERS=" + layers); ingo@1400: sb.append("&QUERY_LAYERS=" + layers); ingo@1400: sb.append("&BBOX=" + bbox); ingo@1400: sb.append("&HEIGHT=" + height); ingo@1400: sb.append("&WIDTH=" + width); ingo@1400: sb.append("&FORMAT=image/png"); ingo@1400: sb.append("&INFO_FORMAT=" + infoFormat); ingo@1400: sb.append("&SRS=" + projection); ingo@1400: sb.append("&X=" + String.valueOf(x)); ingo@1400: sb.append("&Y=" + String.valueOf(y)); ingo@1400: ingo@1400: return sb.toString(); ingo@1400: } ingo@1400: ingo@1400: aheinecke@5794: protected String getUrl(Theme theme) { aheinecke@5794: AttributedTheme attr = (AttributedTheme) theme; aheinecke@5818: return attr.getAttr("url"); ingo@1400: } ingo@1402: ingo@1402: aheinecke@5818: protected FeatureInfoResponse parseResponse(InputStream is) { teichmann@8203: log.debug("GFIServiceImpl.parseResponse"); ingo@1402: aheinecke@5818: ByteArrayOutputStream baos = new ByteArrayOutputStream(); aheinecke@5818: byte [] buf = new byte[1024]; ingo@1402: aheinecke@5818: int r = -1; aheinecke@5818: try { aheinecke@5818: while ((r = is.read(buf)) >= 0) { aheinecke@5818: baos.write(buf, 0, r); aheinecke@5818: } aheinecke@5818: } catch (IOException ex) { teichmann@8203: log.warn("GetFeatureInfo response could not be read: ", ex); aheinecke@5818: return new FeatureInfoResponse(); aheinecke@5818: } ingo@1402: aheinecke@5818: String content; aheinecke@5818: try { aheinecke@5818: content = baos.toString("UTF-8"); aheinecke@5818: } aheinecke@5818: catch (UnsupportedEncodingException uee) { aheinecke@5818: content = baos.toString(); aheinecke@5818: } ingo@1402: aheinecke@5818: Document response = XMLUtils.parseDocument(content); aheinecke@5818: if (response != null) { aheinecke@5818: List features = new ArrayList(); aheinecke@5818: parseFeatureInfos(response, features); aheinecke@5818: return new FeatureInfoResponse(features, null); aheinecke@5818: } aheinecke@5818: // Unable to parse just return the response as is aheinecke@5818: return new FeatureInfoResponse(new ArrayList(), content); ingo@1402: } ingo@1402: ingo@1402: ingo@1402: protected void parseFeatureInfos(Node node, List features) { teichmann@8203: log.debug("GFIServiceImpl.parseFeatureInfos"); ingo@1402: ingo@1402: String name = node.getNodeName(); ingo@1402: ingo@1402: if (name.endsWith("_layer")) { ingo@1402: features.add(parseFeature(node)); ingo@1402: ingo@1402: return; ingo@1402: } ingo@1402: ingo@1402: NodeList children = node.getChildNodes(); ingo@1402: ingo@1402: if (children != null && children.getLength() > 0) { ingo@1402: for (int i = 0, n = children.getLength(); i < n; i++) { ingo@1402: parseFeatureInfos(children.item(i), features); ingo@1402: } ingo@1402: } ingo@1402: } ingo@1402: ingo@1402: ingo@1402: protected FeatureInfo parseFeature(Node node) { teichmann@8203: log.debug("GFIServiceImpl.parseFeature"); ingo@1402: ingo@1402: String layername = node.getNodeName(); ingo@1402: ingo@1402: FeatureInfo f = new FeatureInfo(layername); ingo@1402: ingo@1402: NodeList children = node.getChildNodes(); ingo@1402: int numChildren = children != null ? children.getLength() : 0; ingo@1402: teichmann@8203: log.debug("Feature '" + layername + "' has " + numChildren + " nodes."); ingo@1402: ingo@1402: for (int i = 0; i < numChildren; i++) { ingo@1402: Node tmp = children.item(i); ingo@1402: String nodeName = tmp.getNodeName(); ingo@1402: teichmann@8203: log.debug(" node name: '" + nodeName + "'"); ingo@1402: ingo@1402: if (nodeName.equals("gml:name")) { tom@8856: log.debug("NAME node has child: " tom@8856: + tmp.getFirstChild().getNodeValue()); ingo@1402: f.setLayername(tmp.getFirstChild().getNodeValue()); ingo@1402: } ingo@1402: else if (nodeName.endsWith("_feature")) { ingo@1402: parseFeatureAttributes(tmp, f); ingo@1402: } ingo@1402: } ingo@1402: ingo@1402: return f; ingo@1402: } ingo@1402: ingo@1402: ingo@1402: protected void parseFeatureAttributes(Node node, FeatureInfo f) { teichmann@8203: log.debug("GFIServiceImpl.parseFeatureAttributes"); ingo@1402: ingo@1402: NodeList children = node.getChildNodes(); ingo@1402: int numChildren = children != null ? children.getLength() : 0; ingo@1402: teichmann@8203: log.debug("Has " + numChildren + " attributes."); ingo@1402: ingo@1402: for (int i = 0; i < numChildren; i++) { ingo@1402: Node tmp = children.item(i); ingo@1402: String name = tmp.getNodeName(); ingo@1402: teichmann@8203: log.debug(" tmp attribute name: '" + name + "'"); ingo@1402: ingo@1402: if (name.equals("gml:boundedBy")) { ingo@1402: // TODO ingo@1402: } ingo@1402: else { ingo@1402: Node child = tmp.getFirstChild(); ingo@1402: if (child != null) { ingo@1402: f.addAttr(name, child.getNodeValue()); ingo@1402: } ingo@1402: } ingo@1402: } ingo@1402: } ingo@1400: } ingo@1400: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :