Statistics
| Revision:

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
/* 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
        protected boolean                forceChangeAxisOrder         = false;
83
    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
        public void setForceChangeAxisOrder(boolean force) {
211
                this.forceChangeAxisOrder = force;
212
        }
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
    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
    /**
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
    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
                    
423
            Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" );
424
            int IO_BUFFER_SIZE = 8 * 1024;
425
                int timeout = prefs.getInt("timeout", 60000);
426
                
427
                File dstFile = forceFile;
428
                if(dstFile == null)
429
                        dstFile = getFile();
430
                
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
                        File f = downloadFile(request, cancel, null);
532
                        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
 }