gvsig-raster / org.gvsig.raster.wmts / trunk / org.gvsig.raster.wmts / org.gvsig.raster.wmts.ogc / org.gvsig.raster.wmts.ogc.impl / src / main / java / org / gvsig / raster / wmts / ogc / impl / base / WMTSProtocolHandler.java @ 2613
History | View | Annotate | Download (24 KB)
1 | 2485 | nbrodin | /* gvSIG. Geographic Information System of the Valencian Government
|
---|---|---|---|
2 | *
|
||
3 | * Copyright (C) 2007-2008 Infrastructures and Transports Department
|
||
4 | * of the Valencian Government (CIT)
|
||
5 | *
|
||
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | * as published by the Free Software Foundation; either version 2
|
||
9 | * of the License, or (at your option) any later version.
|
||
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | */
|
||
22 | package org.gvsig.raster.wmts.ogc.impl.base; |
||
23 | |||
24 | import java.io.BufferedOutputStream; |
||
25 | import java.io.ByteArrayInputStream; |
||
26 | import java.io.DataInputStream; |
||
27 | import java.io.DataOutputStream; |
||
28 | import java.io.File; |
||
29 | import java.io.FileInputStream; |
||
30 | import java.io.FileOutputStream; |
||
31 | import java.io.FileReader; |
||
32 | import java.io.IOException; |
||
33 | import java.net.HttpURLConnection; |
||
34 | import java.net.MalformedURLException; |
||
35 | import java.net.URL; |
||
36 | import java.nio.ByteBuffer; |
||
37 | import java.nio.channels.FileChannel; |
||
38 | import java.security.KeyManagementException; |
||
39 | import java.security.NoSuchAlgorithmException; |
||
40 | import java.util.ArrayList; |
||
41 | import java.util.Hashtable; |
||
42 | import java.util.List; |
||
43 | import java.util.StringTokenizer; |
||
44 | import java.util.prefs.Preferences; |
||
45 | |||
46 | import javax.net.ssl.HttpsURLConnection; |
||
47 | import javax.net.ssl.SSLContext; |
||
48 | import javax.net.ssl.TrustManager; |
||
49 | import javax.net.ssl.X509TrustManager; |
||
50 | |||
51 | import org.gvsig.compat.CompatLocator; |
||
52 | import org.gvsig.compat.net.Downloader; |
||
53 | import org.gvsig.compat.net.ICancellable; |
||
54 | import org.gvsig.raster.wmts.ogc.WMTSStatus; |
||
55 | import org.gvsig.raster.wmts.ogc.exception.DownloadException; |
||
56 | import org.gvsig.raster.wmts.ogc.exception.ServerErrorException; |
||
57 | import org.gvsig.raster.wmts.ogc.exception.WMTSException; |
||
58 | import org.gvsig.raster.wmts.ogc.impl.Tags; |
||
59 | import org.gvsig.raster.wmts.ogc.impl.Utilities; |
||
60 | import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetCapabilitiesRequest; |
||
61 | import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetFeatureInfoRequest; |
||
62 | import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetTileRequest; |
||
63 | import org.gvsig.raster.wmts.ogc.struct.WMTSLayer; |
||
64 | import org.gvsig.raster.wmts.ogc.struct.WMTSOperationsMetadata; |
||
65 | import org.gvsig.raster.wmts.ogc.struct.WMTSStyle; |
||
66 | import org.kxml2.io.KXmlParser; |
||
67 | import org.xmlpull.v1.XmlPullParserException; |
||
68 | |||
69 | /**
|
||
70 | * <p> Abstract class that represents handlers to comunicate via WMS protocol.</p>
|
||
71 | *
|
||
72 | * @author Nacho Brodin (nachobrodin@gmail.com)
|
||
73 | */
|
||
74 | public abstract class WMTSProtocolHandler { |
||
75 | protected static final Downloader downloader = CompatLocator.getDownloader(); |
||
76 | /**
|
||
77 | * Encoding used to parse different xml documents.
|
||
78 | */
|
||
79 | protected String encoding = "UTF-8"; |
||
80 | private static int count = 0; |
||
81 | final String tempDirectoryPath = System.getProperty("java.io.tmpdir")+"/tmp-andami"; |
||
82 | 2613 | nbrodin | protected boolean forceChangeAxisOrder = false; |
83 | 2485 | nbrodin | protected String name; |
84 | protected String version; |
||
85 | protected String host; |
||
86 | protected String port; |
||
87 | private WMTSServerDescription serverDescription = null; |
||
88 | |||
89 | protected abstract WMTSGetFeatureInfoRequest createGetFeatureInfoRequest(WMTSStatusImpl status, int x, int y); |
||
90 | |||
91 | protected abstract WMTSGetTileRequest createGetTileRequest(WMTSStatusImpl status); |
||
92 | |||
93 | protected abstract WMTSGetCapabilitiesRequest createGetCapabilitiesRequest(); |
||
94 | |||
95 | /**
|
||
96 | * parses the data retrieved by the Capabilities XML document
|
||
97 | */
|
||
98 | public abstract boolean parseCapabilities(File f); |
||
99 | |||
100 | public WMTSServerDescription getServerDescription() {
|
||
101 | if(serverDescription == null) { |
||
102 | serverDescription = new WMTSServerDescription(getVersion());
|
||
103 | } |
||
104 | return this.serverDescription; |
||
105 | } |
||
106 | |||
107 | /**
|
||
108 | * @return Returns the host.
|
||
109 | */
|
||
110 | public String getHost() { |
||
111 | return host;
|
||
112 | } |
||
113 | /**
|
||
114 | * @param host The host to set.
|
||
115 | */
|
||
116 | public void setHost(String host) { |
||
117 | this.host = host;
|
||
118 | } |
||
119 | /**
|
||
120 | * @return Returns the name.
|
||
121 | */
|
||
122 | public String getName() { |
||
123 | return name;
|
||
124 | } |
||
125 | /**
|
||
126 | * @param name The name to set.
|
||
127 | */
|
||
128 | public void setName(String name) { |
||
129 | this.name = name;
|
||
130 | } |
||
131 | /**
|
||
132 | * @return Returns the port.
|
||
133 | */
|
||
134 | public String getPort() { |
||
135 | return port;
|
||
136 | } |
||
137 | /**
|
||
138 | * @param port The port to set.
|
||
139 | */
|
||
140 | public void setPort(String port) { |
||
141 | this.port = port;
|
||
142 | } |
||
143 | /**
|
||
144 | * @return Returns the version.
|
||
145 | */
|
||
146 | public String getVersion() { |
||
147 | return version;
|
||
148 | } |
||
149 | /**
|
||
150 | * @param version The version to set.
|
||
151 | */
|
||
152 | public void setVersion(String version) { |
||
153 | this.version = version;
|
||
154 | } |
||
155 | |||
156 | /**
|
||
157 | * Just for not repeat code. Gets the correct separator according
|
||
158 | * to the server URL
|
||
159 | * @param h
|
||
160 | * @return
|
||
161 | */
|
||
162 | public String getSymbol(String h) { |
||
163 | String symbol;
|
||
164 | if (h.indexOf("?")==-1) |
||
165 | symbol = "?";
|
||
166 | else if (h.indexOf("?")!=h.length()-1) |
||
167 | symbol = "&";
|
||
168 | else
|
||
169 | symbol = "";
|
||
170 | return symbol;
|
||
171 | } |
||
172 | |||
173 | /**
|
||
174 | * Copy the file in a byte array
|
||
175 | * @param file
|
||
176 | * The file to copy
|
||
177 | * @return
|
||
178 | * An array of bytes
|
||
179 | * @throws IOException
|
||
180 | */
|
||
181 | protected byte[] fileToBytes(File file) throws IOException { |
||
182 | FileInputStream fis = null; |
||
183 | byte[] bytes = null; |
||
184 | try{
|
||
185 | fis = new FileInputStream(file); |
||
186 | |||
187 | //long length = file.length();
|
||
188 | bytes = new byte[(int)file.length()]; |
||
189 | |||
190 | int offset = 0; |
||
191 | int numRead = 0; |
||
192 | while (offset < bytes.length &&
|
||
193 | (numRead = fis.read(bytes, offset, bytes.length-offset)) >= 0) {
|
||
194 | offset += numRead; |
||
195 | } |
||
196 | } catch (IOException e) { |
||
197 | throw e;
|
||
198 | } finally {
|
||
199 | if (fis != null) { |
||
200 | fis.close(); |
||
201 | } |
||
202 | } |
||
203 | return bytes;
|
||
204 | } |
||
205 | |||
206 | /**
|
||
207 | * Sets longitude first in the axis order read from the capabilities file
|
||
208 | * @param force
|
||
209 | */
|
||
210 | 2613 | nbrodin | public void setForceChangeAxisOrder(boolean force) { |
211 | this.forceChangeAxisOrder = force;
|
||
212 | 2485 | nbrodin | } |
213 | |||
214 | //**************************************************************
|
||
215 | //Esto es temporal hasta que est? la cach?
|
||
216 | |||
217 | private Hashtable<URL, String> downloadedFiles; |
||
218 | /**
|
||
219 | * Returns the content of a URL as a file from the file system.<br>
|
||
220 | * <p>
|
||
221 | * If the URL has been already downloaded in this session and notified
|
||
222 | * to the system using the static <b>Utilities.addDownloadedURL(URL)</b>
|
||
223 | * method, it can be restored faster from the file system avoiding to
|
||
224 | * download it again.
|
||
225 | * </p>
|
||
226 | * @param url
|
||
227 | * @return File containing this URL's content or null if no file was found.
|
||
228 | */
|
||
229 | private File getPreviousDownloaded(Object object) { |
||
230 | File f = null; |
||
231 | if (downloadedFiles != null && downloadedFiles.containsKey(object)) { |
||
232 | String filePath = (String) downloadedFiles.get(object); |
||
233 | f = new File(filePath); |
||
234 | if (!f.exists())
|
||
235 | return null; |
||
236 | } |
||
237 | return f;
|
||
238 | } |
||
239 | |||
240 | /**
|
||
241 | * Adds an URL to the table of downloaded files for further uses. If the URL
|
||
242 | * already exists in the table its filePath value is updated to the new one and
|
||
243 | * the old file itself is removed from the file system.
|
||
244 | *
|
||
245 | * @param url
|
||
246 | * @param filePath
|
||
247 | */
|
||
248 | void addDownloadedURL(URL url, String filePath) { |
||
249 | if (downloadedFiles == null) |
||
250 | downloadedFiles = new Hashtable<URL, String>(); |
||
251 | downloadedFiles.put(url, filePath); |
||
252 | } |
||
253 | |||
254 | //Fin del c?digo temporal hasta que est? la cach?
|
||
255 | //**************************************************************
|
||
256 | |||
257 | public synchronized File getTile(WMTSStatusImpl status, ICancellable cancel, File file) throws ServerErrorException, WMTSException { |
||
258 | try {
|
||
259 | WMTSGetTileRequest request = createGetTileRequest(status); |
||
260 | request.sendRequest(cancel, file); |
||
261 | try {
|
||
262 | checkFileError(file); |
||
263 | } catch(WMTSException e) {
|
||
264 | file.delete(); |
||
265 | throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e); |
||
266 | } catch(IOException e) { |
||
267 | file.delete(); |
||
268 | throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e); |
||
269 | } |
||
270 | return file;
|
||
271 | } catch(IOException e) { |
||
272 | throw new WMTSException(e); |
||
273 | } |
||
274 | } |
||
275 | |||
276 | public synchronized File getTile(WMTSStatus status, ICancellable cancel) throws ServerErrorException, WMTSException { |
||
277 | try {
|
||
278 | WMTSGetTileRequest request = createGetTileRequest((WMTSStatusImpl)status); |
||
279 | File f = request.sendRequest(cancel);
|
||
280 | try {
|
||
281 | checkFileError(f); |
||
282 | } catch(WMTSException e) {
|
||
283 | downloader.removeURL(request); |
||
284 | throw new ServerErrorException(); |
||
285 | } |
||
286 | return f;
|
||
287 | } catch(IOException e) { |
||
288 | e.printStackTrace(); |
||
289 | throw new ServerErrorException(); |
||
290 | } |
||
291 | } |
||
292 | |||
293 | 2602 | nbrodin | public synchronized File getTile(String url, ICancellable cancel, File file) throws ServerErrorException, WMTSException { |
294 | try {
|
||
295 | downloadFile(new URL(url), cancel, file); |
||
296 | try {
|
||
297 | checkFileError(file); |
||
298 | } catch(WMTSException e) {
|
||
299 | file.delete(); |
||
300 | throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e); |
||
301 | } catch(IOException e) { |
||
302 | file.delete(); |
||
303 | throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e); |
||
304 | } |
||
305 | return file;
|
||
306 | } catch(IOException e) { |
||
307 | throw new WMTSException(e); |
||
308 | } catch (DownloadException e1) {
|
||
309 | throw new WMTSException(e1); |
||
310 | } |
||
311 | } |
||
312 | |||
313 | 2485 | nbrodin | /**
|
314 | * Checks if the file downloaded is correct or doesn't
|
||
315 | * @param f
|
||
316 | * @throws WMTSException
|
||
317 | * @throws IOException
|
||
318 | */
|
||
319 | private void checkFileError(File f) throws WMTSException, IOException { |
||
320 | if (f == null) |
||
321 | return;
|
||
322 | if (Utilities.isTextFile(f)) { |
||
323 | byte[] data = fileToBytes(f); |
||
324 | |||
325 | String exceptionMessage = parseException(data);
|
||
326 | if (exceptionMessage == null) { |
||
327 | String error = new String(data); |
||
328 | int pos = error.indexOf("<?xml"); |
||
329 | if (pos!= -1) { |
||
330 | String xml = error.substring(pos,error.length());
|
||
331 | exceptionMessage = parseException(xml.getBytes()); |
||
332 | } |
||
333 | if (exceptionMessage == null) |
||
334 | exceptionMessage = new String(data); |
||
335 | |||
336 | } |
||
337 | throw new WMTSException(exceptionMessage); |
||
338 | } |
||
339 | } |
||
340 | |||
341 | public synchronized URL getTileURL(WMTSStatusImpl status) throws MalformedURLException { |
||
342 | String onlineResource = getBaseURL(Tags.GETTILE);
|
||
343 | |||
344 | StringBuffer req = new StringBuffer(); |
||
345 | req.append(onlineResource) |
||
346 | .append("REQUEST=GetTile&SERVICE=WMTS&VERSION=").append(getVersion()).append("&") |
||
347 | .append("Layer=" + status.getLayer())
|
||
348 | .append("&Style=" + status.getStyle())
|
||
349 | .append("&Format=" + status.getFormat())
|
||
350 | .append("&TileMatrixSet=" + status.getTileMatrixSet())
|
||
351 | .append("&TileMatrix=" + status.getTileMatrix())
|
||
352 | .append("&TileRow=" + status. getTileRow())
|
||
353 | .append("&TileCol=" + status.getTileCol());
|
||
354 | |||
355 | return new URL(req.toString()); |
||
356 | } |
||
357 | |||
358 | /**
|
||
359 | * Gets the URL base for a operation (GetCapabilities, GetTile, ...)
|
||
360 | * @param operation
|
||
361 | * @return the base URL for the GET protocol or the host passed by the user
|
||
362 | * if it does not exists.
|
||
363 | */
|
||
364 | public String getBaseURL(String operation) { |
||
365 | String onlineResource = null; |
||
366 | WMTSServerDescription svDescription = getServerDescription(); |
||
367 | if(svDescription != null) { |
||
368 | WMTSOperationsMetadata opMetadata = svDescription.getOperationsMetadata(); |
||
369 | if(opMetadata != null) |
||
370 | onlineResource = opMetadata.getOnlineResource(operation); |
||
371 | } |
||
372 | if(onlineResource == null) |
||
373 | onlineResource = getHost(); |
||
374 | String symbol = getSymbol(onlineResource);
|
||
375 | onlineResource = onlineResource + symbol; |
||
376 | return onlineResource;
|
||
377 | } |
||
378 | |||
379 | /**
|
||
380 | * Gets the URL base for a operation (GetCapabilities, GetTile, ...) and
|
||
381 | * a protocol GET or POST
|
||
382 | * @param operation
|
||
383 | * @return the base URL for this protocol or null if it does not exists.
|
||
384 | */
|
||
385 | public String getBaseURL(String operation, int protocol) { |
||
386 | String onlineResource = null; |
||
387 | WMTSServerDescription svDescription = getServerDescription(); |
||
388 | if(svDescription != null) { |
||
389 | WMTSOperationsMetadata opMetadata = svDescription.getOperationsMetadata(); |
||
390 | if(opMetadata != null) { |
||
391 | onlineResource = opMetadata.getOnlineResource(operation, protocol); |
||
392 | if(onlineResource != null) { |
||
393 | String symbol = getSymbol(onlineResource);
|
||
394 | return onlineResource + symbol;
|
||
395 | } |
||
396 | } |
||
397 | } |
||
398 | return null; |
||
399 | } |
||
400 | |||
401 | /**
|
||
402 | * Gets a file name to download. I
|
||
403 | * @param url
|
||
404 | * @return
|
||
405 | */
|
||
406 | private File getFile() { |
||
407 | count ++; |
||
408 | int index = name.lastIndexOf("."); |
||
409 | if (index > 0){ |
||
410 | return new File(tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + count + |
||
411 | name.substring(index, name.length())); |
||
412 | } |
||
413 | return new File(tempDirectoryPath + "/" + name + System.currentTimeMillis() + count); |
||
414 | } |
||
415 | |||
416 | 2602 | nbrodin | public synchronized File downloadFile(URL url, ICancellable cancel, File forceFile) throws DownloadException { |
417 | if(forceFile == null) { |
||
418 | File f = null; |
||
419 | if((f = getPreviousDownloaded(url)) != null) |
||
420 | return f;
|
||
421 | } |
||
422 | 2485 | nbrodin | |
423 | Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" ); |
||
424 | int IO_BUFFER_SIZE = 8 * 1024; |
||
425 | int timeout = prefs.getInt("timeout", 60000); |
||
426 | |||
427 | 2602 | nbrodin | File dstFile = forceFile;
|
428 | if(dstFile == null) |
||
429 | dstFile = getFile(); |
||
430 | 2485 | nbrodin | |
431 | DataOutputStream dos;
|
||
432 | try {
|
||
433 | DataInputStream is;
|
||
434 | //OutputStreamWriter os = null;
|
||
435 | HttpURLConnection connection = null; |
||
436 | |||
437 | if (url.getProtocol().equals("https")) { |
||
438 | disableHttsValidation(); |
||
439 | } |
||
440 | connection = (HttpURLConnection)url.openConnection();
|
||
441 | connection.setConnectTimeout(timeout); |
||
442 | |||
443 | is = new DataInputStream(url.openStream()); |
||
444 | |||
445 | dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile))); |
||
446 | byte[] buffer = new byte[IO_BUFFER_SIZE]; |
||
447 | |||
448 | int read;
|
||
449 | while ((read = is.read(buffer)) != -1) { |
||
450 | dos.write(buffer, 0, read);
|
||
451 | } |
||
452 | |||
453 | /*if(os != null) {
|
||
454 | os.close();
|
||
455 | }*/
|
||
456 | dos.close(); |
||
457 | is.close(); |
||
458 | is = null;
|
||
459 | dos = null;
|
||
460 | if (cancel != null && cancel.isCanceled()) { |
||
461 | dstFile.delete(); |
||
462 | dstFile = null;
|
||
463 | return null; |
||
464 | } |
||
465 | } catch (Exception e) { |
||
466 | throw new DownloadException(e); |
||
467 | } |
||
468 | addDownloadedURL(url, dstFile.getAbsolutePath()); |
||
469 | return dstFile;
|
||
470 | } |
||
471 | |||
472 | /**
|
||
473 | * This method disables the Https certificate validation.
|
||
474 | * @throws KeyManagementException
|
||
475 | * @throws NoSuchAlgorithmException
|
||
476 | */
|
||
477 | private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{ |
||
478 | // Create a trust manager that does not validate certificate chains
|
||
479 | TrustManager[] trustAllCerts = new TrustManager[] { |
||
480 | new X509TrustManager() { |
||
481 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { |
||
482 | return null; |
||
483 | } |
||
484 | public void checkClientTrusted( |
||
485 | java.security.cert.X509Certificate[] certs, String authType) { |
||
486 | } |
||
487 | public void checkServerTrusted( |
||
488 | java.security.cert.X509Certificate[] certs, String authType) { |
||
489 | } |
||
490 | } |
||
491 | }; |
||
492 | |||
493 | // Install the all-trusting trust manager
|
||
494 | SSLContext sc = SSLContext.getInstance("SSL"); |
||
495 | sc.init(null, trustAllCerts, new java.security.SecureRandom()); |
||
496 | HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||
497 | } |
||
498 | |||
499 | /**
|
||
500 | * @return string that represents the url for getting the wms legend
|
||
501 | * If the layer has the object layer-->style-->legendurl that url will be returned
|
||
502 | * otherwise builds the getLegendGraphic according to the OGC WMS Specifications
|
||
503 | *
|
||
504 | */
|
||
505 | /*private String buildGetLegendGraphicRequest(WMTSLayer layer, WMTSStyle style) {
|
||
506 | String onlineResource = style.getLegendURL().getHref();
|
||
507 | String symbol = getSymbol(onlineResource);
|
||
508 | String layerName = layer.getTitle();
|
||
509 | |||
510 | if(onlineResource == null || onlineResource.equals(""))
|
||
511 | return null;
|
||
512 | |||
513 | StringBuffer req = new StringBuffer();
|
||
514 | req.append(onlineResource + symbol + "REQUEST=GetLegendGraphic&SERVICE=WMS&VERSION=").append(getVersion());
|
||
515 | req.append("&LAYER=" + layerName).append("&TRANSPARENT=TRUE").append("&FORMAT=image/png");
|
||
516 | String aux = req.toString().replaceAll(" ", "%20");
|
||
517 | System.out.println("GetLegendGraphic url:" + aux);
|
||
518 | return aux;
|
||
519 | }*/
|
||
520 | |||
521 | public File getLegendGraphic(WMTSLayer layer, WMTSStyle style, ICancellable cancel) |
||
522 | throws ServerErrorException, WMTSException, DownloadException {
|
||
523 | URL request = null; |
||
524 | try {
|
||
525 | String requestStr = style.getLegendURL().getHref();
|
||
526 | if(requestStr == null || requestStr.equals("")) |
||
527 | return null; |
||
528 | request = new URL(requestStr); |
||
529 | System.out.println(requestStr);
|
||
530 | |||
531 | 2602 | nbrodin | File f = downloadFile(request, cancel, null); |
532 | 2485 | nbrodin | if (f== null) |
533 | return null; |
||
534 | if (Utilities.isTextFile(f)) { |
||
535 | FileInputStream fis = new FileInputStream(f); |
||
536 | FileChannel fc = fis.getChannel();
|
||
537 | byte[] data = new byte[(int)fc.size()]; |
||
538 | ByteBuffer bb = ByteBuffer.wrap(data); |
||
539 | fc.read(bb); |
||
540 | |||
541 | WMTSException wmsEx = null;
|
||
542 | |||
543 | String exceptionMessage = parseException(data);
|
||
544 | if (exceptionMessage == null) { |
||
545 | String error = new String(data); |
||
546 | int pos = error.indexOf("<?xml"); |
||
547 | if (pos!= -1) { |
||
548 | String xml = error.substring(pos,error.length());
|
||
549 | exceptionMessage = parseException(xml.getBytes()); |
||
550 | } |
||
551 | if (exceptionMessage == null) |
||
552 | exceptionMessage = new String(data); |
||
553 | |||
554 | } |
||
555 | wmsEx = new WMTSException(exceptionMessage);
|
||
556 | wmsEx.setWMTSMessage(new String(data)); |
||
557 | Utilities.removeURL(request);
|
||
558 | fis.close(); |
||
559 | throw wmsEx;
|
||
560 | } |
||
561 | return f;
|
||
562 | } catch(IOException e) { |
||
563 | e.printStackTrace(); |
||
564 | throw new ServerErrorException(); |
||
565 | } |
||
566 | } |
||
567 | |||
568 | /**
|
||
569 | * <p>It will send a GetFeatureInfo request to the WMTS
|
||
570 | * Parsing the response and redirecting the info to the WMTS client</p>
|
||
571 | * TODO: return a stored file instead a String.
|
||
572 | */
|
||
573 | public String getFeatureInfo(WMTSStatusImpl status, int x, int y, ICancellable cancel) { |
||
574 | StringBuffer output = new StringBuffer(); |
||
575 | String outputFormat = new String(); |
||
576 | String ServiceException = "ServiceExceptionReport"; |
||
577 | StringBuffer sb = new StringBuffer(); |
||
578 | sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
|
||
579 | try {
|
||
580 | WMTSGetFeatureInfoRequest request = createGetFeatureInfoRequest(status, x, y); |
||
581 | URL url = request.getURL();
|
||
582 | outputFormat = url.openConnection().getContentType(); |
||
583 | File f = request.sendRequest(cancel);
|
||
584 | if (f == null) { |
||
585 | return ""; |
||
586 | } |
||
587 | |||
588 | FileReader fReader = new FileReader(f); |
||
589 | char[] buffer = new char[1024*256]; |
||
590 | for (int i = fReader.read(buffer);i > 0;i = fReader.read(buffer)) { |
||
591 | String str = new String(buffer, 0, i); |
||
592 | output.append(str); |
||
593 | } |
||
594 | fReader.close(); |
||
595 | if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1) |
||
596 | ||output.toString().toLowerCase().startsWith("<?xml")
|
||
597 | ||(outputFormat.indexOf("gml") != -1)) { |
||
598 | KXmlParser kxmlParser = null;
|
||
599 | kxmlParser = new KXmlParser();
|
||
600 | //kxmlParser.setInput(new StringReader(output.toString()));
|
||
601 | kxmlParser.setInput(new FileReader(f)); |
||
602 | |||
603 | kxmlParser.nextTag(); |
||
604 | if (kxmlParser.getName().compareTo(ServiceException) == 0) { |
||
605 | sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>"); |
||
606 | return sb.toString();
|
||
607 | } else if (kxmlParser.getName().compareToIgnoreCase("ERROR") == 0) { |
||
608 | return output.toString();
|
||
609 | } else {
|
||
610 | return output.toString();
|
||
611 | } |
||
612 | } else {
|
||
613 | return output.toString();
|
||
614 | } |
||
615 | } catch(XmlPullParserException parserEx) {
|
||
616 | if (output.toString().toLowerCase().indexOf("xml") != -1) { |
||
617 | return output.toString().trim();
|
||
618 | } else {
|
||
619 | sb.append("<INFO>").append("Info format not supported").append("</INFO>"); |
||
620 | return sb.toString();
|
||
621 | } |
||
622 | } catch(Exception e) { |
||
623 | e.printStackTrace(); |
||
624 | sb.append("<INFO>").append("Info format not supported").append("</INFO>"); |
||
625 | return sb.toString();
|
||
626 | } |
||
627 | } |
||
628 | |||
629 | /**
|
||
630 | * <p>Builds a GetCapabilities request that is sent to the WMS
|
||
631 | * the response will be parse to extract the data needed by the
|
||
632 | * WMS client</p>
|
||
633 | * @param override, if true the previous downloaded data will be overridden
|
||
634 | */
|
||
635 | public void getCapabilities(WMTSServerDescription status, boolean override, ICancellable cancel) { |
||
636 | try {
|
||
637 | serverDescription = status; |
||
638 | WMTSGetCapabilitiesRequest request = createGetCapabilitiesRequest(); |
||
639 | File f = request.sendRequest(cancel);
|
||
640 | |||
641 | if (f == null) |
||
642 | return;
|
||
643 | parseCapabilities(f); |
||
644 | } catch(Exception e) { |
||
645 | e.printStackTrace(); |
||
646 | } |
||
647 | } |
||
648 | |||
649 | |||
650 | /**
|
||
651 | * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
|
||
652 | * without a VERSION, to get the highest version than a WMS supports.
|
||
653 | */
|
||
654 | public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version) { |
||
655 | int index = _host.indexOf('?'); |
||
656 | |||
657 | if (index > -1) { |
||
658 | String host = _host.substring(0, index + 1); |
||
659 | String query = _host.substring(index + 1, _host.length()); |
||
660 | |||
661 | StringTokenizer tokens = new StringTokenizer(query, "&"); |
||
662 | String newQuery = "", token; |
||
663 | |||
664 | // If there is a field or a value with spaces, (and then it's on different tokens) -> unify them
|
||
665 | while (tokens.hasMoreTokens()) {
|
||
666 | token = tokens.nextToken().trim(); |
||
667 | |||
668 | if (token.toUpperCase().compareTo("REQUEST=GETCAPABILITIES") == 0) |
||
669 | continue;
|
||
670 | |||
671 | if (token.toUpperCase().compareTo("SERVICE=WMTS") == 0) |
||
672 | continue;
|
||
673 | |||
674 | if ((_version != null) && (_version.length() > 0)) { |
||
675 | if (token.toUpperCase().compareTo("VERSION=" + _version) == 0) |
||
676 | continue;
|
||
677 | } |
||
678 | |||
679 | if (token.toUpperCase().compareTo("EXCEPTIONS=XML") == 0) |
||
680 | continue;
|
||
681 | |||
682 | newQuery += token + "&";
|
||
683 | } |
||
684 | |||
685 | _host = host + newQuery; |
||
686 | } |
||
687 | else {
|
||
688 | _host += "?";
|
||
689 | } |
||
690 | |||
691 | if ((_version != null) && (_version.compareTo("") != 0)) |
||
692 | _host += "REQUEST=GetCapabilities&SERVICE=WMTS&VERSION=" + _version;
|
||
693 | else
|
||
694 | _host += "REQUEST=GetCapabilities&SERVICE=WMTS";
|
||
695 | |||
696 | return _host;
|
||
697 | } |
||
698 | |||
699 | protected String parseException(byte[] data) throws IOException { |
||
700 | List<String> errors = new ArrayList<String>(); |
||
701 | KXmlParser kxmlParser = new KXmlParser();
|
||
702 | try
|
||
703 | { |
||
704 | kxmlParser.setInput(new ByteArrayInputStream(data), encoding); |
||
705 | kxmlParser.nextTag(); |
||
706 | int tag;
|
||
707 | if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
|
||
708 | { |
||
709 | kxmlParser.require(KXmlParser.START_TAG, null, Tags.EXCEPTION_ROOT);
|
||
710 | tag = kxmlParser.nextTag(); |
||
711 | while(tag != KXmlParser.END_DOCUMENT)
|
||
712 | { |
||
713 | switch(tag)
|
||
714 | { |
||
715 | case KXmlParser.START_TAG:
|
||
716 | if (kxmlParser.getName().compareTo(Tags.SERVICE_EXCEPTION)==0){ |
||
717 | String errorCode = kxmlParser.getAttributeValue("", Tags.CODE); |
||
718 | errorCode = (errorCode != null) ? "["+errorCode+"] " : ""; |
||
719 | String errorMessage = kxmlParser.nextText();
|
||
720 | errors.add(errorCode + errorMessage); |
||
721 | } |
||
722 | break;
|
||
723 | case KXmlParser.END_TAG:
|
||
724 | break;
|
||
725 | |||
726 | } |
||
727 | tag = kxmlParser.nextTag(); |
||
728 | } |
||
729 | //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
|
||
730 | } |
||
731 | } |
||
732 | catch(XmlPullParserException parser_ex){
|
||
733 | throw new IOException(parser_ex.getMessage()); |
||
734 | } |
||
735 | |||
736 | String message = errors.size() > 0? "" : null; |
||
737 | for (int i = 0; i < errors.size(); i++) { |
||
738 | message += (String) errors.get(i)+"\n"; |
||
739 | } |
||
740 | return message;
|
||
741 | } |
||
742 | |||
743 | } |