svn-gvsig-desktop / tags / v1_0_2_Build_908 / libraries / libRemoteServices / src / org / gvsig / remoteClient / wcs / WCSProtocolHandler.java @ 11054
History | View | Annotate | Download (13.8 KB)
1 | 3483 | jaume | /* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
---|---|---|---|
2 | *
|
||
3 | * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
|
||
4 | *
|
||
5 | * This program is free software; you can redistribute it and/or
|
||
6 | * modify it under the terms of the GNU General Public License
|
||
7 | * as published by the Free Software Foundation; either version 2
|
||
8 | * of the License, or (at your option) any later version.
|
||
9 | *
|
||
10 | * This program is distributed in the hope that it will be useful,
|
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
13 | * GNU General Public License for more details.
|
||
14 | *
|
||
15 | * You should have received a copy of the GNU General Public License
|
||
16 | * along with this program; if not, write to the Free Software
|
||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
18 | *
|
||
19 | * For more information, contact:
|
||
20 | *
|
||
21 | * Generalitat Valenciana
|
||
22 | * Conselleria d'Infraestructures i Transport
|
||
23 | * Av. Blasco Ib??ez, 50
|
||
24 | * 46010 VALENCIA
|
||
25 | * SPAIN
|
||
26 | *
|
||
27 | * +34 963862235
|
||
28 | * gvsig@gva.es
|
||
29 | * www.gvsig.gva.es
|
||
30 | *
|
||
31 | * or
|
||
32 | *
|
||
33 | * IVER T.I. S.A
|
||
34 | * Salamanca 50
|
||
35 | * 46005 Valencia
|
||
36 | * Spain
|
||
37 | *
|
||
38 | * +34 963163400
|
||
39 | * dac@iver.es
|
||
40 | */
|
||
41 | package org.gvsig.remoteClient.wcs; |
||
42 | |||
43 | 4924 | jaume | import java.io.ByteArrayInputStream; |
44 | 3483 | jaume | import java.io.File; |
45 | 4493 | jaume | import java.io.FileInputStream; |
46 | import java.io.IOException; |
||
47 | 3483 | jaume | import java.net.URL; |
48 | 4493 | jaume | import java.nio.ByteBuffer; |
49 | import java.nio.channels.FileChannel; |
||
50 | 4427 | jaume | import java.util.ArrayList; |
51 | 4222 | jaume | import java.util.HashMap; |
52 | 4427 | jaume | import java.util.Hashtable; |
53 | 4222 | jaume | import java.util.Vector; |
54 | 3483 | jaume | |
55 | import org.gvsig.remoteClient.OGCProtocolHandler; |
||
56 | 4493 | jaume | import org.gvsig.remoteClient.exceptions.ServerErrorException; |
57 | import org.gvsig.remoteClient.exceptions.WCSException; |
||
58 | 4924 | jaume | import org.gvsig.remoteClient.utils.ExceptionTags; |
59 | 4493 | jaume | import org.gvsig.remoteClient.utils.Utilities; |
60 | 5409 | jaume | import org.gvsig.remoteClient.wms.ICancellable; |
61 | 4924 | jaume | import org.kxml2.io.KXmlParser; |
62 | import org.xmlpull.v1.XmlPullParserException; |
||
63 | 3483 | jaume | /**
|
64 | 7010 | jaume | *
|
65 | 3483 | jaume | * @author jaume
|
66 | *
|
||
67 | */
|
||
68 | public abstract class WCSProtocolHandler extends OGCProtocolHandler{ |
||
69 | 4500 | jaume | /**
|
70 | * Encoding used to parse different xml documents.
|
||
71 | */
|
||
72 | protected String encoding = "UTF-8"; |
||
73 | 4427 | jaume | protected Hashtable layerPool = new Hashtable(); |
74 | 7010 | jaume | |
75 | 4924 | jaume | /**
|
76 | 3483 | jaume | * WCS metadata
|
77 | */
|
||
78 | 4222 | jaume | protected ServiceInformation serviceInfo = new ServiceInformation(); |
79 | 7010 | jaume | |
80 | 3483 | jaume | /**
|
81 | 4924 | jaume | * <p>
|
82 | * Builds a GetCapabilities request that is sent to the WCS
|
||
83 | 3483 | jaume | * the response will be parse to extract the data needed by the
|
84 | 4924 | jaume | * WCS client.
|
85 | * </p>
|
||
86 | 9048 | jaume | * @param override, if true the cache is ignored
|
87 | 3483 | jaume | */
|
88 | 9048 | jaume | public void getCapabilities(WCSStatus status, boolean override, ICancellable cancel) { |
89 | 3483 | jaume | URL request = null; |
90 | 4427 | jaume | try {
|
91 | request = new URL(buildCapabilitiesRequest(status)); |
||
92 | 3483 | jaume | } |
93 | 4427 | jaume | catch(Exception e) { |
94 | 3483 | jaume | e.printStackTrace(); |
95 | } |
||
96 | 4427 | jaume | try {
|
97 | 9048 | jaume | if (override)
|
98 | Utilities.removeURL(request);
|
||
99 | 5409 | jaume | File f = Utilities.downloadFile(request,"wcs_capabilities.xml", cancel); |
100 | if (f!=null) |
||
101 | parseCapabilities(f); |
||
102 | 4427 | jaume | } catch(Exception e) { |
103 | e.printStackTrace(); |
||
104 | 3483 | jaume | } |
105 | } |
||
106 | 7010 | jaume | |
107 | 3483 | jaume | /**
|
108 | 4924 | jaume | * Builds a complete URL-string that can be used to send a GetCapabilities request.
|
109 | * @return String
|
||
110 | 3483 | jaume | */
|
111 | 4427 | jaume | private String buildCapabilitiesRequest(WCSStatus status) { |
112 | StringBuffer req = new StringBuffer(); |
||
113 | String symbol = null; |
||
114 | 7010 | jaume | |
115 | 4427 | jaume | String onlineResource;
|
116 | if (status == null || status.getOnlineResource() == null) |
||
117 | onlineResource = getHost(); |
||
118 | 7010 | jaume | else
|
119 | 4427 | jaume | onlineResource = status.getOnlineResource(); |
120 | symbol = getSymbol(onlineResource); |
||
121 | 7010 | jaume | |
122 | 4427 | jaume | req.append(onlineResource).append(symbol).append("REQUEST=GetCapabilities&SERVICE=WCS&");
|
123 | req.append("VERSION=").append(getVersion()).append("&EXCEPTIONS=XML"); |
||
124 | return req.toString();
|
||
125 | 3483 | jaume | } |
126 | 4427 | jaume | |
127 | 4924 | jaume | /**
|
128 | * Builds a complete URL-string that can be used to send a DescribeCoverage request.
|
||
129 | * If status is null, then default settings are used.
|
||
130 | * @param WCSStatus
|
||
131 | * @return String
|
||
132 | */
|
||
133 | 4427 | jaume | private String buildDescribeCoverageRequest(WCSStatus status) { |
134 | StringBuffer req = new StringBuffer(); |
||
135 | String symbol = null; |
||
136 | 7010 | jaume | |
137 | 4427 | jaume | String onlineResource;
|
138 | if (status == null || status.getOnlineResource() == null) |
||
139 | onlineResource = getHost(); |
||
140 | 7010 | jaume | else
|
141 | 4427 | jaume | onlineResource = status.getOnlineResource(); |
142 | 7010 | jaume | |
143 | |||
144 | 4427 | jaume | symbol = getSymbol(onlineResource); |
145 | 7010 | jaume | |
146 | 4427 | jaume | req.append(onlineResource).append(symbol).append("REQUEST=DescribeCoverage&SERVICE=WCS&");
|
147 | 7010 | jaume | if (status != null && status.getCoverageName()!= null) |
148 | req.append("COVERAGE="+status.getCoverageName()+"&"); |
||
149 | 4427 | jaume | req.append("VERSION=").append(getVersion()).append("&EXCEPTIONS=XML"); |
150 | return req.toString();
|
||
151 | } |
||
152 | |||
153 | 3483 | jaume | /**
|
154 | * parses the data retrieved by the DescribeCoverage XML document
|
||
155 | */
|
||
156 | 4222 | jaume | public abstract boolean parseDescribeCoverage(File f); |
157 | 7010 | jaume | |
158 | 4924 | jaume | /**
|
159 | * Send a DescribeCoverage request using the settings passed in the status argument.
|
||
160 | * If status is null, then default settings are used.
|
||
161 | 9048 | jaume | * @param override
|
162 | 4924 | jaume | * @return String
|
163 | */
|
||
164 | 9048 | jaume | public void describeCoverage(WCSStatus status, boolean override, ICancellable cancel) { |
165 | 4427 | jaume | URL request = null; |
166 | try {
|
||
167 | request = new URL(buildDescribeCoverageRequest(status)); |
||
168 | } |
||
169 | catch(Exception e) { |
||
170 | e.printStackTrace(); |
||
171 | } |
||
172 | try {
|
||
173 | 9048 | jaume | if (override)
|
174 | Utilities.removeURL(request);
|
||
175 | 5409 | jaume | File f = Utilities.downloadFile(request, "wcs_describeCoverage.xml", cancel); |
176 | if (f!=null) |
||
177 | parseDescribeCoverage(f); |
||
178 | 4427 | jaume | } catch(Exception e) { |
179 | e.printStackTrace(); |
||
180 | } |
||
181 | 3483 | jaume | } |
182 | 7010 | jaume | |
183 | 4924 | jaume | /**
|
184 | * Send a GetCoverage request using the settings passed in the status.
|
||
185 | * @return String
|
||
186 | */
|
||
187 | 5409 | jaume | public File getCoverage(WCSStatus status, ICancellable cancel) throws ServerErrorException, WCSException { |
188 | 4493 | jaume | URL request = null; |
189 | try
|
||
190 | { |
||
191 | //TODO:
|
||
192 | //pass this buildXXXRequest to the WCSProtocolHandlerXXX: The request can depend on the WCS version.
|
||
193 | request = new URL(buildCoverageRequest(status)); |
||
194 | 7010 | jaume | |
195 | File f = Utilities.downloadFile(request, "wcsGetCoverage", cancel); |
||
196 | |||
197 | 5409 | jaume | if (f!=null && Utilities.isTextFile(f)) { |
198 | 4493 | jaume | FileInputStream fis = new FileInputStream(f); |
199 | FileChannel fc = fis.getChannel();
|
||
200 | byte[] data = new byte[(int)fc.size()]; // fc.size returns the size of the file which backs the channel |
||
201 | ByteBuffer bb = ByteBuffer.wrap(data); |
||
202 | fc.read(bb); |
||
203 | 7010 | jaume | |
204 | 4493 | jaume | WCSException wcsEx = null;
|
205 | 7010 | jaume | |
206 | 4493 | jaume | String exceptionMessage = parseException(data);
|
207 | if (exceptionMessage==null) |
||
208 | { |
||
209 | String error = new String(data); |
||
210 | int pos = error.indexOf("<?xml"); |
||
211 | if (pos!= -1) |
||
212 | { |
||
213 | String xml = error.substring(pos,error.length());
|
||
214 | exceptionMessage = parseException(xml.getBytes()); |
||
215 | 7010 | jaume | } |
216 | 4493 | jaume | if (exceptionMessage == null) |
217 | exceptionMessage = new String(data); |
||
218 | 7010 | jaume | |
219 | 4493 | jaume | } |
220 | wcsEx = new WCSException(exceptionMessage);
|
||
221 | wcsEx.setWCSMessage(new String(data)); |
||
222 | 7010 | jaume | |
223 | 4493 | jaume | // Since it is an error file, It must be deleted from the cache
|
224 | 5409 | jaume | Utilities.removeURL(request);
|
225 | 4493 | jaume | throw wcsEx;
|
226 | } |
||
227 | 7010 | jaume | return f;
|
228 | 4493 | jaume | } |
229 | catch(IOException e) |
||
230 | { |
||
231 | e.printStackTrace(); |
||
232 | throw new ServerErrorException(); |
||
233 | } |
||
234 | 7010 | jaume | } |
235 | |||
236 | |||
237 | 4924 | jaume | /**
|
238 | * Parses the WCS Exception document.
|
||
239 | * @param bytes, byte[]
|
||
240 | * @return
|
||
241 | */
|
||
242 | private String parseException(byte[] data) { |
||
243 | // TODO: a?? est? fusilat del WMS, comprovar que funciona.
|
||
244 | ArrayList errors = new ArrayList(); |
||
245 | KXmlParser kxmlParser = new KXmlParser();
|
||
246 | try
|
||
247 | { |
||
248 | 7010 | jaume | kxmlParser.setInput(new ByteArrayInputStream(data), encoding); |
249 | 4924 | jaume | kxmlParser.nextTag(); |
250 | int tag;
|
||
251 | 7010 | jaume | if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
|
252 | { |
||
253 | kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);
|
||
254 | 4924 | jaume | tag = kxmlParser.nextTag(); |
255 | while(tag != KXmlParser.END_DOCUMENT)
|
||
256 | { |
||
257 | switch(tag)
|
||
258 | { |
||
259 | case KXmlParser.START_TAG:
|
||
260 | if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){ |
||
261 | String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE); |
||
262 | errorCode = (errorCode != null) ? "["+errorCode+"] " : ""; |
||
263 | String errorMessage = kxmlParser.nextText();
|
||
264 | errors.add(errorCode+errorMessage); |
||
265 | } |
||
266 | break;
|
||
267 | 7010 | jaume | case KXmlParser.END_TAG:
|
268 | 4924 | jaume | break;
|
269 | 7010 | jaume | |
270 | 4924 | jaume | } |
271 | tag = kxmlParser.nextTag(); |
||
272 | } |
||
273 | //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
|
||
274 | } |
||
275 | } |
||
276 | 7010 | jaume | catch(XmlPullParserException parser_ex){
|
277 | 4924 | jaume | parser_ex.printStackTrace(); |
278 | } |
||
279 | 7010 | jaume | catch (IOException ioe) { |
280 | ioe.printStackTrace(); |
||
281 | 4924 | jaume | } |
282 | String message = errors.size()>0? "" : null; |
||
283 | for (int i = 0; i < errors.size(); i++) { |
||
284 | message += (String) errors.get(i)+"\n"; |
||
285 | } |
||
286 | return message;
|
||
287 | 4493 | jaume | } |
288 | |||
289 | /**
|
||
290 | * Builds the GetMapRequest according to the OGC WCS Specifications
|
||
291 | */
|
||
292 | private String buildCoverageRequest(WCSStatus status) |
||
293 | 7010 | jaume | { |
294 | 4493 | jaume | StringBuffer req = new StringBuffer(); |
295 | String symbol = null; |
||
296 | String onlineResource = null; |
||
297 | 7010 | jaume | |
298 | 4493 | jaume | if (status.getOnlineResource() == null) |
299 | onlineResource = getHost(); |
||
300 | 7010 | jaume | else
|
301 | 4493 | jaume | onlineResource = status.getOnlineResource(); |
302 | symbol = getSymbol(onlineResource); |
||
303 | 7010 | jaume | |
304 | 4606 | jaume | req.append(onlineResource + symbol + "service=WCS&version=").append(getVersion()).append("&request=GetCoverage&"); |
305 | 4493 | jaume | req.append(getPartialQuery(status)); |
306 | 4606 | jaume | if (status.getExceptionFormat() != null) { |
307 | req.append("&EXCEPTIONS=" + status.getExceptionFormat());
|
||
308 | } else {
|
||
309 | req.append("&EXCEPTIONS=XML");
|
||
310 | } |
||
311 | 4493 | jaume | return req.toString().replaceAll(" ", "%20"); |
312 | 3483 | jaume | } |
313 | 7010 | jaume | |
314 | 4293 | jaume | /**
|
315 | 4493 | jaume | * Gets the part of the OGC request that share GetMap and GetFeatureInfo
|
316 | * @return String request
|
||
317 | */
|
||
318 | public String getPartialQuery(WCSStatus status) |
||
319 | 7010 | jaume | { |
320 | 4493 | jaume | StringBuffer req = new StringBuffer(); |
321 | 4606 | jaume | req.append( (status.getTime() != null) ? "TIME="+status.getTime() : "" ) |
322 | .append( "&COVERAGE=" + status.getCoverageName())
|
||
323 | 8765 | jjdelcerro | .append( "&CRS=" + status.getSrs())
|
324 | 4606 | jaume | .append( "&FORMAT=" + status.getFormat() )
|
325 | .append( "&HEIGHT=" + status.getHeight())
|
||
326 | .append( "&WIDTH=" + status.getWidth())
|
||
327 | 4925 | jaume | .append( (status.getDepth() != null) ? "&DEPTH="+status.getDepth() : "" ) |
328 | 4606 | jaume | .append( "&BBOX=" + status.getExtent().getMinX()+ "," ) |
329 | .append( status.getExtent().getMinY()+ ",")
|
||
330 | .append( status.getExtent().getMaxX()+ ",")
|
||
331 | .append( status.getExtent().getMaxY()) |
||
332 | 4493 | jaume | .append( (status.getParameters() != null) ? "&"+status.getParameters() : ""); |
333 | 7010 | jaume | |
334 | 4493 | jaume | return req.toString();
|
335 | } |
||
336 | 7010 | jaume | |
337 | 4493 | jaume | /**
|
338 | 4427 | jaume | * Builds the GetCapabilitiesRequest according to the OGC WCS Specifications
|
339 | * without a VERSION, to get the highest version than a WCS supports.
|
||
340 | 4293 | jaume | */
|
341 | public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version) { |
||
342 | 7010 | jaume | String req = new String(); |
343 | 4293 | jaume | String symbol = getSymbol(_host);
|
344 | 7010 | jaume | req = req + _host + symbol + "REQUEST=GetCapabilities&SERVICE=WCS&";
|
345 | 4293 | jaume | if((_version != null) && (_version.length()>0 )) { |
346 | req += ("&VERSION=" + _version);
|
||
347 | } |
||
348 | req += ("&EXCEPTIONS=XML");
|
||
349 | 7010 | jaume | return req.toString().replaceAll(" ", "%20"); |
350 | 4293 | jaume | } |
351 | 7010 | jaume | |
352 | |||
353 | 4293 | jaume | /**
|
354 | * Just for not repeat code. Gets the correct separator according to the server URL
|
||
355 | * @param h
|
||
356 | * @return
|
||
357 | */
|
||
358 | private static String getSymbol(String h) { |
||
359 | String symbol;
|
||
360 | 7010 | jaume | if (h.indexOf("?")==-1) |
361 | 4293 | jaume | symbol = "?";
|
362 | else if (h.indexOf("?")!=h.length()-1) |
||
363 | symbol = "&";
|
||
364 | else
|
||
365 | symbol = "";
|
||
366 | return symbol;
|
||
367 | } |
||
368 | 7010 | jaume | |
369 | 4931 | jaume | public ArrayList getFormats() { |
370 | return new ArrayList(serviceInfo.formats); |
||
371 | } |
||
372 | |||
373 | 4222 | jaume | public class ServiceInformation { |
374 | |||
375 | public String online_resource = null; |
||
376 | public String version; |
||
377 | public String name; |
||
378 | public String scope; |
||
379 | public String title; |
||
380 | public String abstr; |
||
381 | public String keywords; |
||
382 | public String fees; |
||
383 | public String operationsInfo; |
||
384 | public String personname; |
||
385 | public String organization; |
||
386 | public String function; |
||
387 | public String addresstype; |
||
388 | public String address; |
||
389 | public String place; |
||
390 | public String province; |
||
391 | public String postcode; |
||
392 | public String country; |
||
393 | public String phone; |
||
394 | public String fax; |
||
395 | public String email; |
||
396 | public Vector formats; |
||
397 | 4241 | jaume | public HashMap operations; // operations that WCS supports |
398 | 7010 | jaume | |
399 | 4222 | jaume | public ServiceInformation()
|
400 | 7010 | jaume | { |
401 | 4222 | jaume | version = new String(); |
402 | name = new String(); |
||
403 | scope = new String(); |
||
404 | title = new String(); |
||
405 | abstr = new String(); |
||
406 | keywords = new String(); |
||
407 | fees = new String(); |
||
408 | operationsInfo = new String(); |
||
409 | personname = new String(); |
||
410 | organization = new String(); |
||
411 | function = new String(); |
||
412 | addresstype = new String(); |
||
413 | address = new String(); |
||
414 | place = new String(); |
||
415 | province = new String(); |
||
416 | postcode = new String(); |
||
417 | country = new String(); |
||
418 | phone = new String(); |
||
419 | fax = new String(); |
||
420 | email = new String(); |
||
421 | 7010 | jaume | operations = new HashMap(); |
422 | 4222 | jaume | } |
423 | 4241 | jaume | |
424 | 4427 | jaume | } |
425 | |||
426 | public Hashtable getLayers() { |
||
427 | return layerPool;
|
||
428 | 7010 | jaume | } |
429 | 3483 | jaume | } |