001: //=============================================================================
002: //=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
003: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
004: //=== and United Nations Environment Programme (UNEP)
005: //===
006: //=== This program is free software; you can redistribute it and/or modify
007: //=== it under the terms of the GNU General Public License as published by
008: //=== the Free Software Foundation; either version 2 of the License, or (at
009: //=== your option) any later version.
010: //===
011: //=== This program is distributed in the hope that it will be useful, but
012: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
013: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: //=== General Public License for more details.
015: //===
016: //=== You should have received a copy of the GNU General Public License
017: //=== along with this program; if not, write to the Free Software
018: //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
019: //===
020: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
021: //=== Rome - Italy. email: geonetwork@osgeo.org
022: //==============================================================================
023:
024: package org.wfp.vam.intermap.kernel.map.mapServices.wms;
025:
026: import org.wfp.vam.intermap.kernel.map.mapServices.wms.schema.type.*;
027:
028: import java.util.HashMap;
029: import java.util.Map;
030: import java.util.Set;
031: import java.util.StringTokenizer;
032: import java.util.Vector;
033: import org.jdom.CDATA;
034: import org.jdom.Element;
035: import org.jdom.Text;
036: import org.wfp.vam.intermap.kernel.map.mapServices.BoundingBox;
037: import org.wfp.vam.intermap.kernel.map.mapServices.HttpClient;
038: import org.wfp.vam.intermap.kernel.map.mapServices.MapService;
039: import org.wfp.vam.intermap.kernel.map.mapServices.constants.MapServices;
040: import org.wfp.vam.intermap.kernel.map.mapServices.wms.dimensions.Extents;
041: import org.wfp.vam.intermap.kernel.map.mapServices.wms.schema.impl.WMSFactory;
042: import org.wfp.vam.intermap.util.Util;
043:
044: public class WmsService extends MapService {
045: public static final int TYPE = 2;
046:
047: private boolean visible; // Not used yet => not degugged
048: private BoundingBox bb = new BoundingBox();
049:
050: private final WMSLayer _wmsLayer; // the part of the getCapabilities response regarding the layer
051: private final WMSCapabilities _wmscapa;
052:
053: private String _styleName; // WMS style for this layer
054: private final WMSCapabilities.WMSVer _wmsVer; // Version of the WMS server
055: private String imageType;
056:
057: private Element errorElement;
058:
059: private Map<String, String> htExtents = new HashMap<String, String>();
060: private HashMap hmVsp = new HashMap();
061:
062: public WmsService(String mapServerUrl, String serviceName,
063: Element capabilities) throws Exception {
064: super (mapServerUrl, serviceName);
065:
066: this .info = capabilities;
067: _wmscapa = WMSFactory.parseCapabilities(capabilities);
068: _wmsVer = _wmscapa.getVersion();
069:
070: imageType = getImageType(_wmscapa);
071:
072: _wmsLayer = _wmscapa.getCapability().getLayer().getLayer(
073: serviceName);
074:
075: WMSStyle wmsstyle = _wmsLayer.getStyle(0);
076: if (wmsstyle != null)
077: _styleName = _wmsLayer.getStyle(0).getName();
078: }
079:
080: /**
081: * Returns LayerDoc
082: */
083: public WMSLayer getWmsLayer() {
084: return _wmsLayer;
085: }
086:
087: /**
088: * Method setExtent
089: */
090: public void setExtent(String name, String value) {
091: htExtents.put(name, value);
092: // System.out.println(htExtents); // TEST
093: }
094:
095: // Sets the vendor specific parameters
096: public void setVendorSpecificParams(HashMap hmVspars) {
097: hmVsp = hmVspars; // TEST
098: }
099:
100: /** Returns 2 (-> WMS) */
101: public int getType() {
102: return TYPE;
103: }
104:
105: /**
106: * Method getImageUrl
107: */
108: public String getImageUrl(BoundingBox bBox, int width, int height) {
109: return getImageUrl(bBox, width, height, name);
110: }
111:
112: /** Returns the image request URL with many image names (utility method) */
113: public String getImageUrl(BoundingBox bBox, int width, int height,
114: String name) {
115: bb = bBox;
116: String request;
117:
118: String getMapHref = _wmscapa.getCapability().getRequest()
119: .getGetMap().getDCPType(0).getHttpGetHref();
120: String prefix = setPrefix(getMapHref);
121:
122: if (_wmsVer == WMSCapabilities.WMSVer.V100) {
123: // WMTVER is deprecated but needed for older map servers
124: // SERVICE should not be required, but servers were found to give errors without it if I remember. FIXME
125: request = prefix + "SERVICE=WMS&WMTVER=" + _wmsVer
126: + "&REQUEST=map";
127: } else {
128: /* Dec 15, 2004 - ticheler - Changed the REQUEST=map to REQUEST=GetMap according to specs because the
129: * REQUEST=map seems to trigger exceptions (non-compliant behaviour)*/
130: request = prefix + "SERVICE=WMS&VERSION=" + _wmsVer
131: + "&REQUEST=GetMap";
132: }
133:
134: request += "&LAYERS=" + name + "&SRS=EPSG:4326" + "&BBOX="
135: + bb.getWest() + "," + bb.getSouth() + ","
136: + bb.getEast() + "," + bb.getNorth() + "&WIDTH="
137: + width + "&HEIGHT=" + height + "&FORMAT=" + imageType
138: + "&TRANSPARENT=TRUE";
139:
140: // set extents
141: for (String key : htExtents.keySet()) {
142: String value = htExtents.get(key);
143: request += "&" + key + "=" + value;
144: }
145:
146: // System.out.println("\n\n\nrequest\n\n\n" + request); // TEST
147:
148: // Set style
149: if (_styleName != null)
150: request += "&STYLES=" + _styleName;
151: else
152: request += "&STYLES=";
153:
154: System.out.println("request: " + request);
155:
156: return request;
157: }
158:
159: private static String setPrefix(String prefix) {
160: if (prefix.indexOf("?") == -1)
161: return prefix + "?";
162: else if (!prefix.endsWith("?"))
163: return prefix + "&";
164: else
165: return prefix;
166: }
167:
168: public int getActiveLayer() {
169: return 1;
170: }
171:
172: public void identify(int layer, int x, int y, int width,
173: int height, int tolerance, String reqFormat)
174: throws Exception {
175: WMSOperationType gfi = _wmscapa.getCapability().getRequest()
176: .getGetFeatureInfo(); // Optional request
177: String getFeatureInfoHref = gfi.getDCPType(0).getHttpGetHref();
178:
179: String prefix = setPrefix(getFeatureInfoHref);
180: // System.out.println("Requested format: " + reqFormat); // DEBUG
181: if (reqFormat == null)
182: reqFormat = ""; //DEBUG
183: WMSFormat infoFormat = strFormat(reqFormat);
184: // System.out.println("Accepted format: " + infoFormat); // DEBUG
185: // String infoFormat = isGml() ? "application/vnd.ogc.gml" : "text/plain"; //TEST
186: // FIXME Changed to ensure compatability with WMS 1.1.1 and 1.1.0
187: String url;
188:
189: if (_wmsVer == WMSCapabilities.WMSVer.V100) {
190: url = prefix + "WMTVER=" + _wmsVer
191: + "&REQUEST=GetFeatureInfo";
192: } else {
193: url = prefix + "SERVICE=WMS&VERSION=" + _wmsVer
194: + "&REQUEST=GetFeatureInfo";
195: }
196:
197: url += "&LAYERS=" + name + "&SRS=EPSG:4326" + "&BBOX="
198: + bb.getWest() + "," + bb.getSouth() + ","
199: + bb.getEast() + "," + bb.getNorth() + "&WIDTH="
200: + width + "&HEIGHT=" + height + "&FORMAT=" + imageType
201: + "&QUERY_LAYERS=" + name + "&X=" + x + "&Y=" + y
202: + "&INFO_FORMAT=" + infoFormat + "&STYLES="
203: + _styleName;
204:
205: lastResponse = new Element("url").setText(url);
206:
207: // Use the following code if you need to proxy the WMS server response.
208:
209: // HttpClient h = new HttpClient(url);
210: //
211: // if(infoFormat == WMSFormat.APP_GML
212: // || infoFormat == WMSFormat.TEXT_XHTML //.equals(Constants.FORMAT_GML) || infoFormat.equals(Constants.FORMAT_XHTML)) {
213: // || infoFormat == WMSFormat.v100_GML1 // TODO test me
214: // || infoFormat == WMSFormat.v100_GML2 // TODO test me
215: // || infoFormat == WMSFormat.v100_GML3) // TODO test me
216: // {
217: // lastResponse = new Element("gml").addContent(h.getElement());
218: //// System.out.println("lastResponse element, " + infoFormat + ": " + Xml.getString(lastResponse)); // DEBUG
219: // }
220: // else if (infoFormat == WMSFormat.TEXT_HTML) // infoFormat.equals(Constants.FORMAT_HTML)) {
221: // {
222: // String strResult = h.getString();
223: //// System.out.println("Server response: " + strResult); // DEBUG
224: // lastResponse = new Element("html").addContent(new CDATA(strResult)); //Add the html as content to an <html> element
225: // }
226: // else {
227: // lastResponse = new Element("text").addContent(new CDATA(h.getString()));
228: // }
229: //// System.out.println("lastResponse element, "+infoFormat+": " + Xml.getString(lastResponse)); // DEBUG
230: }
231:
232: /**
233: * Returns the available format to be requested.
234: * The method checks out if the requested Format is available in the capabilities document.
235: * If requested format is not found, another format among the available ones will be used,
236: * choosing one according to this priority list: HTML, XHTML, GML and finally PLAIN
237: */
238: private WMSFormat strFormat(String reqFormat) {
239: WMSOperationType gfi = _wmscapa.getCapability().getRequest()
240: .getGetFeatureInfo();
241: Set<WMSFormat> availableFormats = gfi.getFormats();
242: WMSFormat req = WMSFormat.parse(reqFormat);
243: if (req == null)
244: return WMSFormat.TEXT_PLAIN;
245:
246: if (availableFormats.contains(req))
247: return req; //return format that was requested, should normally suffice, rest is only to trap faulty requests
248: else if (availableFormats.contains(WMSFormat.TEXT_HTML))
249: return WMSFormat.TEXT_HTML;
250: else if (availableFormats.contains(WMSFormat.TEXT_XHTML))
251: return WMSFormat.TEXT_XHTML;
252: else if (availableFormats.contains(WMSFormat.APP_GML))
253: return WMSFormat.APP_GML;
254: else
255: return WMSFormat.TEXT_PLAIN;
256: }
257:
258: /** Not used yet */
259: public void setLayerVisible(String id, boolean visible) {
260: this .visible = visible;
261: }
262:
263: /** Returns the default bounding box, as in LatLonBoundingBox */
264: public BoundingBox getDefBoundingBox() {
265: WMSEX_GeographicBoundingBox gbb = _wmsLayer.getGeoBB();
266: if (gbb != null)
267: return Util.getBB(gbb);
268: else
269: // it should not happen, because layers must always have a geobb according to WMS specs
270: return new BoundingBox();
271: }
272:
273: /** Returns the current BoundingBox */
274: public BoundingBox getBoundingBox() {
275: return bb;
276: }
277:
278: /** Not used yet */
279: public Vector getVisibleLayers() {
280: Vector v = new Vector();
281: if (visible)
282: v.add(new Integer(1));
283: return v;
284: }
285:
286: /** Returns the legend for the currently selected style, as in the Style element */
287: public String getLegendUrl() {
288: // if (_wmsVer != WMSCapabilities.WMSVer.V100)//.startsWith("1.1")) // 1.0 documentation was no clear for the legend URL
289: // {
290: WMSStyle wstyle = _wmsLayer.getStyle(_styleName);
291: if (wstyle != null) {
292: WMSLegendURL wlegurl = wstyle.getLegendURL(0);
293: if (wlegurl != null)
294: return wlegurl.getOnlineResource().getHref();
295: }
296: // }
297:
298: return null;
299: }
300:
301: /** Converts this service into a Jdom Element, to be used by the Jeeves Map service */
302: public Element toElement() {
303: Element elService = new Element("service").setAttribute("type",
304: "WMS").setAttribute("name", getName()).addContent(
305: getInfo()).addContent(
306: new Element(MapServices.LAST_RESPONSE_TAG)
307: .addContent(getLastResponse()));
308:
309: if (_styleName != null)
310: elService.setAttribute("style", _styleName);
311:
312: // add selected extents information
313: Element extents = new Element("selectedExtents");
314: for (String key : htExtents.keySet()) {
315: String value = htExtents.get(key);
316: extents.addContent(new Element(key).setText(value));
317: }
318:
319: elService.addContent(extents);
320:
321: return elService;
322: }
323:
324: /** Useless for WMS layers */
325: public void setActiveLayer(int layer) throws Exception {
326: }
327:
328: /** Sets the style for this service */
329: public void setStyleName(String style) {
330: _styleName = style;
331: }
332:
333: public String getStyleName() {
334: return _styleName;
335: }
336:
337: public String getTitle() {
338: return _wmsLayer.getTitle();
339: }
340:
341: public Element getExtents() {
342: // Extents e = new Extents(layerInfo);
343: Extents e = new Extents(_wmsLayer.getDimensionIterator());
344: return e.getJdom();
345: }
346:
347: /** Returns one of the image types returned by the server choosing
348: * from gif, png and jpeg
349: */
350: private String getImageType(WMSCapabilities wmsc) {
351: Set<WMSFormat> formats = wmsc.getCapability().getRequest()
352: .getGetMap().getFormats();
353: if (WMSCapabilities.WMSVer.V100 == wmsc.getVersion()) {
354: if (formats.contains(WMSFormat.v100_PNG))
355: return WMSFormat.v100_PNG.toString();
356: else if (formats.contains(WMSFormat.v100_GIF))
357: return WMSFormat.v100_GIF.toString();
358: else if (formats.contains(WMSFormat.v100_JPEG))
359: return WMSFormat.v100_JPEG.toString();
360: } else {
361: if (formats.contains(WMSFormat.IMAGE_PNG))
362: return WMSFormat.IMAGE_PNG.toString();
363: else if (formats.contains(WMSFormat.IMAGE_GIF))
364: return WMSFormat.IMAGE_GIF.toString();
365: else if (formats.contains(WMSFormat.IMAGE_JPG))
366: return WMSFormat.IMAGE_JPG.toString();
367: }
368:
369: return formats.iterator().next().toString();
370: }
371:
372: private static Element toHtml(String s) {
373: Vector v = new Vector();
374:
375: for (StringTokenizer t = new StringTokenizer(s, "\r\n"); t
376: .hasMoreTokens();) {
377: Text line = new Text(t.nextToken());
378: v.add(line);
379: v.add(new Element("br"));
380: }
381:
382: return new Element("html").setContent(v);
383: }
384:
385: }
386:
387: //==============================================================================
388: //=== $Log: WmsService.java,v $
389: //=== Revision 1.15 2005/11/09 11:39:31 sgiaccio
390: //=== More fixes to WMS get feature info
391: //===
392: //=== Revision 1.14 2005/11/09 10:38:51 sgiaccio
393: //=== *** empty log message ***
394: //===
395: //=== Revision 1.13 2005/11/08 17:01:35 sgiaccio
396: //=== *** empty log message ***
397: //===
398: //=== Revision 1.12 2005/11/08 17:00:07 sgiaccio
399: //=== Some fix to the identify feature on wms layers.
400: //===
401: //=== Revision 1.11 2005/09/21 08:00:19 sgiaccio
402: //=== Cleaned cache management
403: //===
404: //=== Revision 1.10 2005/09/19 16:39:26 sgiaccio
405: //=== Some code cleaning
406: //===
407: //=== Revision 1.9 2005/09/13 10:18:10 ticheler
408: //=== InterMap version 2.0
409: //===
410: //==============================================================================
|