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.arcims;
025:
026: import java.util.Enumeration;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Vector;
030: import jeeves.utils.Xml;
031: import org.jdom.Element;
032: import org.wfp.vam.intermap.kernel.map.mapServices.BoundingBox;
033: import org.wfp.vam.intermap.kernel.map.mapServices.MapService;
034: import org.wfp.vam.intermap.kernel.map.mapServices.ServiceException;
035: import org.wfp.vam.intermap.kernel.map.mapServices.constants.MapServices;
036: import org.wfp.vam.intermap.util.XmlUtil;
037:
038: public class ArcIMSService extends MapService {
039:
040: /**
041: * Method getGroupImageUrl
042: */
043: public String getGroupImageUrl(BoundingBox bBox, int width,
044: int height, List imageNames) {
045: // TODO
046: return null;
047: }
048:
049: public static final int TYPE = 1;
050:
051: private BoundingBox bb;
052: private int activeLayer = 0;
053: private String errorStr;
054:
055: private static final double METERS_IN_DEGREE = 111195.0;
056: private static final double FEET_IN_DEGREE = 364813.0;
057:
058: // private Hashtable htLayerInfo; // Used to fasten the access to the getServiceInfo response
059:
060: /**
061: * Sets the ArcIMS map server URL and the service name.
062: * <p>Also sends a GET_SERVICE_INFO request to the map server and sets the
063: * starting visibility for the layers as specified in the response.
064: * <p>The GET_SERVICE_INFO response can be retrieved using the toElement
065: * method.
066: *
067: * @param url the map server url
068: * @param name the map service name
069: *
070: */
071: public ArcIMSService(String url, String name) throws Exception {
072: super (url, name);
073:
074: // Send the request to the map server
075: Element axlRequest = AxlRequestBuilder
076: .getRequest("getServiceInfo.xml");
077: ArcIMSClient client = new ArcIMSClient(url, name, axlRequest);
078: Element response = client.getElement();
079:
080: // Get the LAYERINFO elements
081: List lLayers = response.getChild("RESPONSE").getChild(
082: "SERVICEINFO").getChildren("LAYERINFO");
083:
084: // Set the internal id for each layer in the service. We can't use the
085: // layer name because it maight contain spaces, and Jeeves would throw
086: // an exception in converting them from HTTP paramerets to elements
087: int internalId = 1;
088: for (Iterator i = lLayers.iterator(); i.hasNext();) {
089: Element elLayerInfo = (Element) i.next();
090: if (activeLayer == 0
091: && elLayerInfo.getAttributeValue("type").equals(
092: "featureclass"))
093: activeLayer = internalId;
094: elLayerInfo.setAttribute("internalId", "" + internalId++);
095: // htLayerInfo.put(new Integer(internalId), elLayerInfo);
096: }
097:
098: // Fills the layers Hashtable with the service's layers as key, and
099: // set set the visible property for each one
100: for (Iterator i = lLayers.iterator(); i.hasNext();) {
101: Element elLayerInfo = (Element) i.next();
102: boolean show = elLayerInfo.getAttributeValue("visible")
103: .equals("true");
104: setLayerVisible(
105: elLayerInfo.getAttributeValue("internalId"), show);
106: }
107:
108: info = new Element(MapServices.INFO_TAG).addContent(response);
109: bb = getDefBoundingBox(); // Get the default bounding box
110: }
111:
112: public int getType() {
113: return TYPE;
114: }
115:
116: /**
117: * Builds a Bounding Box from the envelope tag in the GET_SERVICE_INFO
118: * response.
119: *
120: * @return The default service envelope
121: *
122: */
123: public BoundingBox getDefBoundingBox() throws Exception {
124: Element elBb = XmlUtil
125: .getElement(info,
126: "/info/ARCXML/RESPONSE/SERVICEINFO/PROPERTIES/ENVELOPE");
127:
128: float maxy = Float.parseFloat(elBb.getAttributeValue("maxy"));
129: float miny = Float.parseFloat(elBb.getAttributeValue("miny"));
130: float maxx = Float.parseFloat(elBb.getAttributeValue("maxx"));
131: float minx = Float.parseFloat(elBb.getAttributeValue("minx"));
132:
133: // Convert map units
134: String units = XmlUtil
135: .getElement(info,
136: "/info/ARCXML/RESPONSE/SERVICEINFO/PROPERTIES/MAPUNITS")
137: .getAttributeValue("units");
138: if (units.equals("meters")) {
139: // Meters to decimal degrees
140: maxy /= METERS_IN_DEGREE;
141: miny /= METERS_IN_DEGREE;
142: maxx /= METERS_IN_DEGREE;
143: minx /= METERS_IN_DEGREE;
144: }
145: if (units.equals("feet")) {
146: // Feet to decimal degrees
147: maxy /= FEET_IN_DEGREE;
148: miny /= FEET_IN_DEGREE;
149: maxx /= FEET_IN_DEGREE;
150: minx /= FEET_IN_DEGREE;
151: }
152:
153: BoundingBox bb = new BoundingBox(maxy, miny, maxx, minx);
154:
155: return bb;
156: }
157:
158: public BoundingBox getBoundingBox() {
159: return bb;
160: }
161:
162: /**
163: * Sends a GET_IMAGE request to the map server.
164: *
165: * @param bBox a BoundingBox
166: *
167: * @return the URL of the image on the server
168: *
169: * @throws Exception
170: *
171: */
172: public String getImageUrl(BoundingBox bBox, int width, int height)
173: throws Exception, ServiceException {
174: this .bb = bBox;
175:
176: // Build the request for the map server
177: Element elService = this
178: .toElement()
179: .addContent(
180: new Element("imageWidth").setText(width + ""))
181: .addContent(
182: new Element("imageHeight").setText(height + ""));
183: Element request = AxlRequestBuilder.getRequest(elService,
184: "getImage.xsl");
185:
186: // Send the request and get the response as an Element
187: ArcIMSClient client = new ArcIMSClient(serverUrl, name, request);
188: lastResponse = client.getElement();
189:
190: // Check if an error was generated on the server
191: checkArcImsError();
192:
193: // Set the current bounding box from the response
194: Element elEnvelope = lastResponse.getChild("RESPONSE")
195: .getChild("IMAGE").getChild("ENVELOPE");
196: bb = new BoundingBox(Float.parseFloat(elEnvelope
197: .getAttributeValue("maxy")), Float
198: .parseFloat(elEnvelope.getAttributeValue("miny")),
199: Float.parseFloat(elEnvelope.getAttributeValue("maxx")),
200: Float.parseFloat(elEnvelope.getAttributeValue("minx")));
201:
202: // Get the image URL from the ArcXML response
203: return XmlUtil.getElement(lastResponse,
204: "/ARCXML/RESPONSE/IMAGE/OUTPUT").getAttributeValue(
205: "url");
206: }
207:
208: /**
209: * Sends a GET_EXTRACT request to the map server.
210: *
211: * @param bBox a BoundingBox
212: *
213: * @return the URL of the image on the server
214: *
215: * @throws Exception
216: *
217: */
218: public String getShapefileUrl(BoundingBox bBox, int width,
219: int height) throws Exception, ServiceException {
220: this .bb = bBox;
221:
222: // Build the request for the map server
223: Element elService = this
224: .toElement()
225: .addContent(
226: new Element("imageWidth").setText(width + ""))
227: .addContent(
228: new Element("imageHeight").setText(height + ""));
229: Element request = AxlRequestBuilder.getRequest(elService,
230: "getShape.xsl");
231:
232: // Send the request and get the response as an Element
233: ArcIMSClient client = new ArcIMSClient(serverUrl, name,
234: "Extract", request);
235: lastResponse = client.getElement();
236:
237: // Check if an error was generated on the server
238: checkArcImsError();
239:
240: // Get the image URL from the ArcXML response
241: return XmlUtil.getElement(lastResponse,
242: "/ARCXML/RESPONSE/EXTRACT/OUTPUT").getAttributeValue(
243: "url");
244: }
245:
246: /**
247: * Sends a GET_IMAGE request to the map server to get the legend.
248: *
249: * @param bBox a BoundingBox
250: *
251: * @return the URL of the image on the server
252: *
253: * @throws Exception
254: *
255: */
256: public String getLegendUrl() throws Exception, ServiceException {
257: // Build the request for the map server
258: Element request = AxlRequestBuilder.getRequest(
259: this .toElement(), "getLegend.xsl");
260:
261: // Send the request and get the response as an Element
262: ArcIMSClient client = new ArcIMSClient(serverUrl, name, request);
263: Element lastResponse = client.getElement();
264:
265: checkArcImsError();
266:
267: // Get the image URL from the ArcXML response
268: return XmlUtil.getElement(lastResponse,
269: "/ARCXML/RESPONSE/IMAGE/LEGEND").getAttributeValue(
270: "url");
271: }
272:
273: public void identify(int layer, int x, int y, int width,
274: int height, int tolerance, String reqFormat)
275: throws Exception, ServiceException {
276: float mapX = bb.getWest() + (bb.getEast() - bb.getWest()) * x
277: / width;
278: float mapY = bb.getNorth() - (bb.getNorth() - bb.getSouth())
279: * y / height;
280: float deltax = (bb.getEast() - bb.getWest()) / width
281: * tolerance / 2;
282: float deltay = (bb.getNorth() - bb.getSouth()) / height
283: * tolerance / 2;
284:
285: // Build the request for the map server
286: Element request = AxlRequestBuilder.getRequest(this .toElement()
287: .addContent(
288: new Element("activeLayer").setText(layer + ""))
289: .addContent(
290: new BoundingBox(mapY + deltay, mapY - deltay,
291: mapX + deltax, mapX - deltax)
292: .toElement()), "identify.xsl");
293:
294: // Send the request and get the response as an Element
295: ArcIMSClient client = new ArcIMSClient(serverUrl, name,
296: "Query", request);
297: lastResponse = client.getElement();
298:
299: checkArcImsError();
300: }
301:
302: public void setActiveLayer(int layer) throws Exception {
303: // if (!layers.contains(new Integer(layer)))
304: // throw new Exception();
305: activeLayer = layer;
306: }
307:
308: public int getActiveLayer() {
309: return activeLayer;
310: }
311:
312: /**
313: * Sets layer visibility
314: *
315: * @param id layer id
316: * @param visible layer visibility
317: *
318: */
319: public void setLayerVisible(String id, boolean visible) {
320: if (visible)
321: layers.put(id, "show");
322: else
323: layers.put(id, "hide");
324: }
325:
326: /**
327: * Returns an array of all visible layers
328: *
329: * @return a Vector
330: *
331: */
332: public Vector getVisibleLayers() {
333: Vector show = new Vector();
334: for (Enumeration e = layers.keys(); e.hasMoreElements();) {
335: Object key = e.nextElement();
336: if (layers.get(key) == "show")
337: show.add(key);
338: }
339: return show;
340: }
341:
342: /**
343: * Returns an element represenation of the status of the map service
344: *
345: * @return an Element
346: *
347: */
348: public Element toElement() {
349: // Visible layers
350: Element elVisible = new Element("visibleLayers");
351: for (Enumeration e = layers.keys(); e.hasMoreElements();) {
352: Object key = e.nextElement();
353: if (layers.get(key) == "show")
354: elVisible.addContent(new Element("layer").setAttribute(
355: "internalId", (String) key).setAttribute(
356: "visible", "true"));
357: else
358: elVisible.addContent(new Element("layer").setAttribute(
359: "internalId", (String) key).setAttribute(
360: "visible", "false"));
361: }
362:
363: return new Element("service").setAttribute("type", "ArcIMS")
364: .setAttribute("name", this .getName()).addContent(
365: this .getInfo()).addContent(
366: new Element(MapServices.LAST_RESPONSE_TAG)
367: .addContent(this .getLastResponse()))
368: .addContent(elVisible).addContent(
369: new Element("envelope")
370: .addContent(getBoundingBox()
371: .toElement()));
372: }
373:
374: public String getErrorMsg() {
375: return errorStr;
376: }
377:
378: /**
379: * Sets the error string and throws a ServiceException if
380: * an error messaged received from the image server
381: *
382: * @throws ServiceException if an error messaged received from the image
383: * server
384: *
385: */
386: private void checkArcImsError() throws Exception {
387: Element error = XmlUtil.getElement(lastResponse,
388: "/ARCXML/RESPONSE/ERROR");
389: if (error != null) {
390: errorStr = error.getText();
391: throw new ServiceException();
392: }
393: }
394:
395: }
|