ingo@1400: package de.intevation.flys.client.server;
ingo@1400: 
ingo@1400: import java.io.InputStream;
ingo@1400: import java.io.IOException;
ingo@1400: import java.net.URL;
ingo@1400: import java.net.URLConnection;
ingo@1402: import java.util.ArrayList;
ingo@1400: import java.util.List;
ingo@1400: 
ingo@1402: import org.w3c.dom.Document;
ingo@1402: import org.w3c.dom.Node;
ingo@1402: import org.w3c.dom.NodeList;
ingo@1402: 
ingo@1400: import org.apache.log4j.Logger;
ingo@1400: 
ingo@1400: import com.google.gwt.user.server.rpc.RemoteServiceServlet;
ingo@1400: 
ingo@1402: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@1400: 
ingo@1400: import de.intevation.flys.client.shared.exceptions.ServerException;
ingo@1400: import de.intevation.flys.client.shared.model.AttributedTheme;
ingo@1402: import de.intevation.flys.client.shared.model.FeatureInfo;
ingo@1400: import de.intevation.flys.client.shared.model.Theme;
ingo@1400: 
ingo@1400: import de.intevation.flys.client.client.services.GFIService;
ingo@1400: 
ingo@1400: 
ingo@1400: /**
ingo@1400:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
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: 
ingo@1400:     private static final Logger logger =
ingo@1400:         Logger.getLogger(GFIServiceImpl.class);
ingo@1400: 
ingo@1400: 
ingo@1400:     /**
ingo@1400:      * @param themes
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:      */
ingo@1402:     public List<FeatureInfo> query(
ingo@1400:         List<Theme> themes,
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:     {
ingo@1400:         logger.info("GFIServiceImpl.query");
ingo@1400: 
ingo@1400:         String path = createGetFeautureInfoURL(
ingo@1400:             themes, format, bbox, projection, height, width, x, y);
ingo@1402: 
ingo@1400:         logger.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) {
ingo@1400:             logger.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
ingo@1400:      * @param themes
ingo@1400:      * @param format
ingo@1400:      * @param x
ingo@1400:      * @param y
ingo@1400:      *
ingo@1400:      * @return
ingo@1400:      */
ingo@1400:     protected String createGetFeautureInfoURL(
ingo@1400:         List<Theme> themes,
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:     {
ingo@1400:         String url = getUrl(themes);
ingo@1400: 
ingo@1400:         if (url == null || url.length() == 0) {
ingo@1400:             throw new ServerException(ERR_NO_VALID_GFI_URL);
ingo@1400:         }
ingo@1400: 
ingo@1400:         String layers = createLayersString(themes);
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: 
ingo@1400:     protected String getUrl(List<Theme> themes) {
ingo@1400:         for (Theme t: themes) {
ingo@1400:             AttributedTheme attr = (AttributedTheme) t;
ingo@1400: 
ingo@1400:             if (attr.getAttrAsBoolean("queryable")) {
ingo@1400:                 return attr.getAttr("url");
ingo@1400:             }
ingo@1400:         }
ingo@1400: 
ingo@1400:         return null;
ingo@1400:     }
ingo@1400: 
ingo@1400: 
ingo@1400:     protected String createLayersString(List<Theme> themes) {
ingo@1400:         StringBuilder sb = new StringBuilder();
ingo@1400:         boolean first = true;
ingo@1400: 
ingo@1400:         for (Theme theme: themes) {
ingo@1400:             AttributedTheme layer = (AttributedTheme) theme;
ingo@1400:             if (layer.getAttrAsBoolean("queryable")) {
ingo@2448:                 if (!first) {
ingo@2448:                     sb.append(",");
ingo@2448:                 }
ingo@2448: 
ingo@1400:                 sb.append(layer.getAttr("layers"));
ingo@1400:                 first = false;
ingo@1400:             }
ingo@1400:         }
ingo@1400: 
ingo@1400:         return sb.toString();
ingo@1400:     }
ingo@1402: 
ingo@1402: 
ingo@1402:     protected List<FeatureInfo> parseResponse(InputStream is) {
ingo@1402:         logger.debug("GFIServiceImpl.parseResponse");
ingo@1402: 
ingo@1402:         Document response = XMLUtils.parseDocument(is);
ingo@1402: 
ingo@1402:         List<FeatureInfo> features = new ArrayList<FeatureInfo>();
ingo@1402: 
ingo@1402:         parseFeatureInfos(response, features);
ingo@1402: 
ingo@1402:         return features;
ingo@1402:     }
ingo@1402: 
ingo@1402: 
ingo@1402:     protected void parseFeatureInfos(Node node, List<FeatureInfo> features) {
ingo@1402:         logger.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) {
ingo@1402:         logger.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: 
ingo@1402:         logger.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: 
ingo@1402:             logger.debug("   node name: '" + nodeName + "'");
ingo@1402: 
ingo@1402:             if (nodeName.equals("gml:name")) {
ingo@1402:                 logger.debug("NAME node has child: " + 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) {
ingo@1402:         logger.debug("GFIServiceImpl.parseFeatureAttributes");
ingo@1402: 
ingo@1402:         NodeList children = node.getChildNodes();
ingo@1402:         int numChildren   = children != null ? children.getLength() : 0;
ingo@1402: 
ingo@1402:         logger.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: 
ingo@1402:             logger.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 :