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 @ 1806

History | View | Annotate | Download (22.8 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.io.OutputStreamWriter;
34
import java.net.HttpURLConnection;
35
import java.net.MalformedURLException;
36
import java.net.URL;
37
import java.security.KeyManagementException;
38
import java.security.NoSuchAlgorithmException;
39
import java.util.ArrayList;
40
import java.util.Hashtable;
41
import java.util.List;
42
import java.util.StringTokenizer;
43
import java.util.prefs.Preferences;
44

    
45
import javax.net.ssl.HttpsURLConnection;
46
import javax.net.ssl.SSLContext;
47
import javax.net.ssl.TrustManager;
48
import javax.net.ssl.X509TrustManager;
49

    
50
import org.gvsig.compat.CompatLocator;
51
import org.gvsig.compat.net.Downloader;
52
import org.gvsig.compat.net.ICancellable;
53
import org.gvsig.raster.wmts.ogc.WMTSStatus;
54
import org.gvsig.raster.wmts.ogc.exception.DownloadException;
55
import org.gvsig.raster.wmts.ogc.exception.ServerErrorException;
56
import org.gvsig.raster.wmts.ogc.exception.WMTSException;
57
import org.gvsig.raster.wmts.ogc.impl.Tags;
58
import org.gvsig.raster.wmts.ogc.impl.Utilities;
59
import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetCapabilitiesRequest;
60
import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetFeatureInfoRequest;
61
import org.gvsig.raster.wmts.ogc.impl.request.WMTSGetTileRequest;
62
import org.kxml2.io.KXmlParser;
63
import org.xmlpull.v1.XmlPullParserException;
64

    
65
/**
66
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.</p>
67
 * 
68
 * @author Nacho Brodin (nachobrodin@gmail.com)
69
 */
70
public abstract class WMTSProtocolHandler {
71
        protected static final Downloader downloader = CompatLocator.getDownloader();
72
        /**
73
         * Encoding used to parse different xml documents.
74
         */
75
        protected String                 encoding                     = "UTF-8";
76
    protected WMTSServiceInformation serviceInfo                  = null;
77
        private static int               count                        = 0;
78
        final String                     tempDirectoryPath            = System.getProperty("java.io.tmpdir")+"/tmp-andami";
79
        protected boolean                forceLongitudeFirstAxisOrder = false;
80
    protected String                 name;
81
    protected String                 version;
82
    protected String                 host;
83
    protected String                 port;  
84
        
85
    protected abstract WMTSGetFeatureInfoRequest createGetFeatureInfoRequest(WMTSStatusImpl status, int x, int y);
86

    
87
    protected abstract WMTSGetTileRequest createGetTileRequest(WMTSStatusImpl status);
88
    
89
    protected abstract WMTSGetCapabilitiesRequest createGetCapabilitiesRequest();
90
    
91
    /**
92
     * parses the data retrieved by the Capabilities XML document
93
     */
94
    public abstract boolean parseCapabilities(File f);
95

    
96
    /**
97
     * @return Returns the host.
98
     */
99
    public String getHost() {
100
        return host;
101
    }
102
    /**
103
     * @param host The host to set.
104
     */
105
    public void setHost(String host) {
106
        this.host = host;
107
    }
108
    /**
109
     * @return Returns the name.
110
     */
111
    public String getName() {
112
        return name;
113
    }
114
    /**
115
     * @param name The name to set.
116
     */
117
    public void setName(String name) {
118
        this.name = name;
119
    }
120
    /**
121
     * @return Returns the port.
122
     */
123
    public String getPort() {
124
        return port;
125
    }
126
    /**
127
     * @param port The port to set.
128
     */
129
    public void setPort(String port) {
130
        this.port = port;
131
    }
132
    /**
133
     * @return Returns the version.
134
     */
135
    public String getVersion() {
136
        return version;
137
    }
138
    /**
139
     * @param version The version to set.
140
     */
141
    public void setVersion(String version) {
142
        this.version = version;
143
    }
144

    
145
    /**
146
     * Just for not repeat code. Gets the correct separator according 
147
     * to the server URL
148
     * @param h
149
     * @return
150
     */
151
    protected static String getSymbol(String h) {
152
        String symbol;
153
        if (h.indexOf("?")==-1) 
154
            symbol = "?";
155
        else if (h.indexOf("?")!=h.length()-1)
156
            symbol = "&";
157
        else
158
            symbol = "";
159
        return symbol;
160
    }  
161

    
162
    /**
163
     * Parse an operation into a DcpType tag
164
     * @param parser
165
     * The KXMLParser
166
     * @param operation
167
     * The WFS operation to parse
168
     * @throws IOException 
169
     * @throws XmlPullParserException 
170
     */
171
    protected void parserDcpType(KXmlParser parser, String operation) throws XmlPullParserException, IOException {        
172
        int currentTag;
173
        boolean end = false;
174

    
175
        currentTag = parser.next();
176

    
177
        while (!end) 
178
        {
179
            switch(currentTag)
180
            {
181
            case KXmlParser.START_TAG:
182
                if(parser.getName().compareTo(Tags.HTTP)==0){
183
                    parseHTTPTag(parser, operation);
184
                }                 
185
                break;
186
            case KXmlParser.END_TAG:
187
                if (parser.getName().compareTo(Tags.DCPTYPE) == 0)
188
                    end = true;
189
                break;
190
            case KXmlParser.TEXT:                   
191
                break;
192
            }
193
            if (!end){
194
                currentTag = parser.next();
195
            }
196
        }     
197
    }
198

    
199
    /**
200
     * Parse an operation into a HTTP tag
201
     * @param parser
202
     * The KXMLParser
203
     * @param operation
204
     * The WFS operation to parse
205
     * @throws IOException 
206
     * @throws XmlPullParserException 
207
     */
208
    protected void parseHTTPTag(KXmlParser parser, String operation) throws XmlPullParserException, IOException {        
209
        int currentTag;
210
        boolean end = false;
211

    
212
        currentTag = parser.next();
213
        int protocol = -1;
214

    
215
        while (!end) 
216
        {
217
            switch(currentTag)
218
            {
219
            case KXmlParser.START_TAG:
220
                if(parser.getName().compareTo(Tags.GET)==0){
221
                    protocol = Tags.PROTOCOL_GET;
222
                    addOperationByAttribute(parser, operation, protocol);
223
                }else if(parser.getName().compareTo(Tags.POST)==0){
224
                    protocol = Tags.PROTOCOL_POST;
225
                    addOperationByAttribute(parser, operation, protocol);
226
                }else if(parser.getName().compareTo(Tags.ONLINERESOURCE)==0){
227
                    addOperationByAttribute(parser, operation, protocol);
228
                }                                
229
                break;
230
            case KXmlParser.END_TAG:
231
                if (parser.getName().compareTo(Tags.HTTP) == 0)
232
                    end = true;
233
                break;
234
            case KXmlParser.TEXT:                   
235
                break;
236
            }
237
            if (!end){
238
                currentTag = parser.next();
239
            }
240
        }     
241
    }
242

    
243
    /**
244
     * Add an operation and the online resource 
245
     * @param parser
246
     * The parser
247
     * @param operation
248
     * The operation to add
249
     * @param protocol
250
     * The parser to add
251
     */
252
    protected void addOperationByAttribute(KXmlParser parser, String operation, int protocol){
253
        String value = null;
254
        if (protocol > -1){
255
            for (int i=0 ; i<parser.getAttributeCount() ; i++){
256
                if ((parser.getAttributeName(i).toUpperCase().compareTo(Tags.ONLINERESOURCE.toUpperCase()) == 0) ||
257
                    (parser.getAttributeName(i).equals(Tags.XLINK_HREF))){                                        
258
                    value = parser.getAttributeValue(i);
259
                }
260
            }                                                                
261
            if (value == null){
262
                getServiceInformation().addOperation(operation, protocol);
263
            }else{
264
                getServiceInformation().addOperation(operation, protocol, value);
265
            }
266
        }  
267
    }
268

    
269
    /**
270
     * Copy the file in a byte array
271
     * @param file
272
     * The file to copy
273
     * @return
274
     * An array of bytes
275
     * @throws IOException
276
     */
277
    protected byte[] fileToBytes(File file) throws IOException{
278
        FileInputStream fis = null;
279
        byte[] bytes = null;
280
        try{
281
            fis = new FileInputStream(file);
282

    
283
            //long length = file.length(); 
284
            bytes = new byte[(int)file.length()];
285

    
286
            int offset = 0;
287
            int numRead = 0; 
288
            while (offset < bytes.length && (numRead=fis.read(bytes, offset, bytes.length-offset)) >= 0) 
289
            { 
290
                offset += numRead; 
291
            }
292
        }catch (IOException e) {
293
            throw e;
294
        }finally{
295
            if (fis != null){
296
                fis.close();
297
            }
298
        }         
299
        return bytes;
300
    }
301
    
302
    /**
303
         * Sets longitude first in the axis order read from the capabilities file
304
         * @param force
305
         */
306
        public void setForceLongitudeFirstAxisOrder(boolean force) {
307
                this.forceLongitudeFirstAxisOrder = force;
308
        }
309
        
310
    //**************************************************************
311
    //Esto es temporal hasta que est? la cach?
312
    
313
        private Hashtable                downloadedFiles;
314
    /**
315
         * Returns the content of a URL as a file from the file system.<br>
316
         * <p>
317
         * If the URL has been already downloaded in this session and notified
318
         * to the system using the static <b>Utilities.addDownloadedURL(URL)</b>
319
         * method, it can be restored faster from the file system avoiding to
320
         * download it again.
321
         * </p>
322
         * @param url
323
         * @return File containing this URL's content or null if no file was found.
324
         */
325
        private File getPreviousDownloaded(Object object) {
326
                File f = null;
327
                if (downloadedFiles != null && downloadedFiles.containsKey(object)) {
328
                        String filePath = (String) downloadedFiles.get(object);
329
                        f = new File(filePath);
330
                        if (!f.exists())
331
                                return null;
332
                }
333
                return f;
334
        }
335

    
336
        /**
337
         * Adds an URL to the table of downloaded files for further uses. If the URL
338
         * already exists in the table its filePath value is updated to the new one and
339
         * the old file itself is removed from the file system.
340
         *
341
         * @param url
342
         * @param filePath
343
         */
344
        void addDownloadedURL(URL url, String filePath) {
345
                if (downloadedFiles == null)
346
                        downloadedFiles = new Hashtable();
347
                String fileName = (String) downloadedFiles.put(url, filePath);
348
        }
349
        
350
        //Fin del c?digo temporal hasta que est? la cach?
351
        //**************************************************************
352
        
353
    /**
354
     * Sets the status object
355
     * @param status
356
     */
357
    protected abstract void setServerDescription(WMTSServerDescription status);
358
    
359
    public synchronized File getTile(WMTSStatusImpl status, ICancellable cancel, File file) throws ServerErrorException, WMTSException {
360
            try {
361
                        WMTSGetTileRequest request = createGetTileRequest(status);
362
                        request.sendRequest(cancel, file);
363
                        try {
364
                                checkFileError(file);
365
                        } catch(WMTSException e) {
366
                                file.delete();
367
                                throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e);
368
                        } catch(IOException e) {
369
                                file.delete();
370
                                throw new WMTSException("This tile is not available:" + file.getAbsoluteFile().toString(), e);
371
                        }
372
                        return file;
373
                } catch(IOException e) {
374
            throw new WMTSException(e);
375
                }
376
    }
377
    
378
    public synchronized File getTile(WMTSStatus status, ICancellable cancel) throws ServerErrorException, WMTSException {
379
            try {
380
                        WMTSGetTileRequest request = createGetTileRequest((WMTSStatusImpl)status);
381
                        File f = request.sendRequest(cancel);
382
                        try {
383
                                checkFileError(f);
384
                        } catch(WMTSException e) {
385
                                downloader.removeURL(request);
386
                    throw new ServerErrorException();
387
                        }
388
                        return f;
389
                } catch(IOException e) {
390
                        e.printStackTrace();
391
            throw new ServerErrorException();
392
                }
393
    }
394
    
395
    /**
396
     * Checks if the file downloaded is correct or doesn't
397
     * @param f
398
     * @throws WMTSException
399
     * @throws IOException
400
     */
401
    private void checkFileError(File f) throws WMTSException, IOException {
402
                if (f == null)
403
                    return;
404
            if (Utilities.isTextFile(f)) {
405
            byte[] data = fileToBytes(f);
406

    
407
                String exceptionMessage = parseException(data);
408
            if (exceptionMessage == null) {
409
                     String error = new String(data);
410
                    int pos = error.indexOf("<?xml");
411
                    if (pos!= -1) {
412
                            String xml = error.substring(pos,error.length());
413
                            exceptionMessage = parseException(xml.getBytes());
414
                    }
415
                if (exceptionMessage == null)
416
                        exceptionMessage = new String(data);
417

    
418
            }
419
            throw new WMTSException(exceptionMessage);
420
        }
421
    }
422
    
423
    public synchronized URL getTileURL(WMTSStatusImpl status) throws MalformedURLException {
424
                String onlineResource = getHost();
425
                String symbol = getSymbol(onlineResource);
426
                onlineResource = onlineResource + symbol;
427
                
428
                StringBuffer req = new StringBuffer();
429
                req.append(onlineResource)
430
                .append("REQUEST=GetTile&SERVICE=WMTS&VERSION=").append(getVersion()).append("&")
431
                .append("Layer=" + status.getLayer())
432
        .append("&Style=" + status.getStyle())
433
        .append("&Format=" + status.getFormat())
434
        .append("&TileMatrixSet=" + status.getTileMatrixSet())
435
        .append("&TileMatrix=" + status.getTileMatrix())
436
        .append("&TileRow=" + status. getTileRow())
437
        .append("&TileCol=" + status.getTileCol());
438
                
439
                return new URL(req.toString());
440
    }
441
    
442
    /**
443
     * Gets a file name to download. I
444
     * @param url
445
     * @return
446
     */
447
    private File getFile() {
448
            count ++;
449
                int index = name.lastIndexOf(".");
450
                if (index > 0){
451
                        return new File(tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + count + 
452
                                name.substring(index, name.length()));
453
                }
454
                return new File(tempDirectoryPath + "/" + name + System.currentTimeMillis() + count);
455
    }
456
    
457
    public synchronized File downloadFile(URL url, ICancellable cancel) throws DownloadException {
458
            File f = null;
459
            if((f = getPreviousDownloaded(url)) != null)
460
                    return f;
461
                    
462
            Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" );
463
            int IO_BUFFER_SIZE = 8 * 1024;
464
                int timeout = prefs.getInt("timeout", 60000);
465
                
466
                File dstFile = getFile();
467
                
468
                DataOutputStream dos;
469
                try {
470
                        DataInputStream is;
471
                        OutputStreamWriter os = null;
472
                        HttpURLConnection connection = null;
473

    
474
                        if (url.getProtocol().equals("https")) {
475
                                disableHttsValidation();
476
                        }
477
                        connection = (HttpURLConnection)url.openConnection();
478
                        connection.setConnectTimeout(timeout);
479
                        
480
                        is = new DataInputStream(url.openStream());
481
                        
482
                        dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile)));
483
                        byte[] buffer = new byte[IO_BUFFER_SIZE];
484

    
485
                        int read;
486
                        while ((read = is.read(buffer)) != -1) {
487
                                dos.write(buffer, 0, read);
488
                        }
489
                        
490
                        if(os != null) {
491
                                os.close();
492
                        }
493
                        dos.close();
494
                        is.close();
495
                        is = null;
496
                        dos = null;
497
                        if (cancel != null && cancel.isCanceled()) {
498
                                dstFile.delete();
499
                                dstFile = null;
500
                                return null;
501
                        }
502
                } catch (Exception e) {
503
                        throw new DownloadException(e);
504
                }
505
                addDownloadedURL(url, dstFile.getAbsolutePath());
506
                return dstFile;
507
    }
508
    
509
    /**
510
         * This method disables the Https certificate validation.
511
         * @throws KeyManagementException
512
         * @throws NoSuchAlgorithmException
513
         */
514
        private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{
515
                // Create a trust manager that does not validate certificate chains
516
                TrustManager[] trustAllCerts = new TrustManager[] {
517
                                new X509TrustManager() {
518
                                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
519
                                                return null;
520
                                        }
521
                                        public void checkClientTrusted(
522
                                                        java.security.cert.X509Certificate[] certs, String authType) {
523
                                        }
524
                                        public void checkServerTrusted(
525
                                                        java.security.cert.X509Certificate[] certs, String authType) {
526
                                        }
527
                                }
528
                };
529

    
530
                // Install the all-trusting trust manager
531
                SSLContext sc = SSLContext.getInstance("SSL");
532
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
533
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
534
        }
535
    
536
        /**
537
     * <p>It will send a GetFeatureInfo request to the WMTS
538
     * Parsing the response and redirecting the info to the WMTS client</p>
539
     * TODO: return a stored file instead a String.
540
     */
541
    public String getFeatureInfo(WMTSStatusImpl status, int x, int y, ICancellable cancel) {
542
            StringBuffer output = new StringBuffer();
543
            String outputFormat = new String();
544
            String ServiceException = "ServiceExceptionReport";
545
            StringBuffer sb = new StringBuffer();
546
            sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
547
                try {
548
                        WMTSGetFeatureInfoRequest request = createGetFeatureInfoRequest(status, x, y);
549
                        URL url = request.getURL();
550
                    outputFormat = url.openConnection().getContentType();
551
                    File f = request.sendRequest(cancel);
552
                        if (f == null) {
553
                                return "";
554
                        }
555

    
556
                        FileReader fReader = new FileReader(f);
557
                        char[] buffer = new char[1024*256];
558
                        for (int i = fReader.read(buffer); i > 0; i = fReader.read(buffer)) {
559
                            String str = new String(buffer,0,i);
560
                            output.append(str);
561
                    }
562
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1)
563
                                    ||output.toString().toLowerCase().startsWith("<?xml")
564
                                    ||(outputFormat.indexOf("gml") != -1)) {
565
                            KXmlParser kxmlParser = null;
566
                            kxmlParser = new KXmlParser();
567
                            //kxmlParser.setInput(new StringReader(output.toString()));
568
                            kxmlParser.setInput(new FileReader(f));
569

    
570
                            kxmlParser.nextTag();
571
                            if (kxmlParser.getName().compareTo(ServiceException) == 0) {
572
                                    sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>");
573
                                    return sb.toString();
574
                                } else if (kxmlParser.getName().compareToIgnoreCase("ERROR") == 0) {
575
                                        return output.toString();
576
                                } else {
577
                                        return output.toString();
578
                                }
579
                    } else {                  
580
                             return output.toString();
581
                    }
582
                } catch(XmlPullParserException parserEx) {
583
                    if (output.toString().toLowerCase().indexOf("xml") != -1) {
584
                            return output.toString().trim();
585
                    } else {
586
                               sb.append("<INFO>").append("Info format not supported").append("</INFO>");
587
                        return sb.toString();
588
                    }
589
            } catch(Exception e) {
590
                    e.printStackTrace();
591
                    sb.append("<INFO>").append("Info format not supported").append("</INFO>");
592
                    return sb.toString();
593
            }
594
    }
595

    
596
    /**
597
         * <p>Builds a GetCapabilities request that is sent to the WMS
598
         * the response will be parse to extract the data needed by the
599
         * WMS client</p>
600
         * @param override, if true the previous downloaded data will be overridden
601
         */
602
    public void getCapabilities(WMTSServerDescription status, boolean override, ICancellable cancel) {
603
            try {
604
                    setServerDescription(status);
605
                        WMTSGetCapabilitiesRequest request = createGetCapabilitiesRequest();
606
                        File f = request.sendRequest(cancel);                        
607
        
608
                        if (f == null)
609
                                return;
610
                        parseCapabilities(f);
611
            } catch(Exception e) {
612
                        e.printStackTrace();
613
                }
614
    }
615
    
616
    
617
    /**
618
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
619
     * without a VERSION, to get the highest version than a WMS supports.
620
     */
621
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version) {
622
                int index = _host.indexOf('?');
623
                
624
                if (index > -1) {
625
                        String host = _host.substring(0, index + 1);
626
                        String query = _host.substring(index + 1, _host.length());
627
                        
628
                        StringTokenizer tokens = new StringTokenizer(query, "&");
629
                        String newQuery = "", token;
630

    
631
                        // If there is a field or a value with spaces, (and then it's on different tokens) -> unify them
632
                        while (tokens.hasMoreTokens()) {
633
                                token = tokens.nextToken().trim();
634

    
635
                                if (token.toUpperCase().compareTo("REQUEST=GETCAPABILITIES") == 0)
636
                                        continue;
637

    
638
                                if (token.toUpperCase().compareTo("SERVICE=WMTS") == 0)
639
                                        continue;
640

    
641
                                if ((_version != null) && (_version.length() > 0)) {
642
                                    if (token.toUpperCase().compareTo("VERSION=" + _version) == 0)
643
                                            continue;
644
                                }
645

    
646
                                if (token.toUpperCase().compareTo("EXCEPTIONS=XML") == 0)
647
                                        continue;
648

    
649
                                newQuery += token + "&";
650
                        }
651

    
652
                _host = host + newQuery;
653
                }
654
                else {
655
                        _host += "?";
656
                }
657

    
658
            if ((_version != null) && (_version.compareTo("") != 0))
659
                    _host += "REQUEST=GetCapabilities&SERVICE=WMTS&VERSION=" + _version;
660
            else
661
                    _host += "REQUEST=GetCapabilities&SERVICE=WMTS";
662

    
663
            return _host;
664
    }
665
    
666
    public WMTSServiceInformation getServiceInformation() {
667
        return serviceInfo;
668
    }
669
    
670
        protected String parseException(byte[] data) throws IOException {
671
        List<String> errors = new ArrayList<String>();
672
        KXmlParser kxmlParser = new KXmlParser();
673
        try
674
        {
675
            kxmlParser.setInput(new ByteArrayInputStream(data), encoding);
676
            kxmlParser.nextTag();
677
            int tag;
678
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
679
            {
680
                kxmlParser.require(KXmlParser.START_TAG, null, Tags.EXCEPTION_ROOT);
681
                tag = kxmlParser.nextTag();
682
                 while(tag != KXmlParser.END_DOCUMENT)
683
                 {
684
                     switch(tag)
685
                     {
686
                        case KXmlParser.START_TAG:
687
                            if (kxmlParser.getName().compareTo(Tags.SERVICE_EXCEPTION)==0){
688
                                String errorCode = kxmlParser.getAttributeValue("", Tags.CODE);
689
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
690
                                String errorMessage = kxmlParser.nextText();
691
                                errors.add(errorCode + errorMessage);
692
                            }
693
                            break;
694
                        case KXmlParser.END_TAG:
695
                            break;
696

    
697
                     }
698
                     tag = kxmlParser.nextTag();
699
                 }
700
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
701
            }
702
        }
703
        catch(XmlPullParserException parser_ex){
704
            throw new IOException(parser_ex.getMessage());
705
        }
706
       
707
        String message = errors.size() > 0? "" : null;
708
        for (int i = 0; i < errors.size(); i++) {
709
            message += (String) errors.get(i)+"\n";
710
        }
711
        return message;
712
    }
713
    
714
 }