Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libRemoteServices / src / org / gvsig / remoteclient / wms / WMSProtocolHandler.java @ 34305

History | View | Annotate | Download (19.4 KB)

1
package org.gvsig.remoteclient.wms;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.File;
5
import java.io.FileReader;
6
import java.io.IOException;
7
import java.io.InputStream;
8
import java.net.URL;
9
import java.net.URLConnection;
10
import java.util.ArrayList;
11
import java.util.StringTokenizer;
12
import java.util.TreeMap;
13

    
14
import org.gvsig.compat.net.ICancellable;
15
import org.gvsig.remoteclient.exceptions.ServerErrorException;
16
import org.gvsig.remoteclient.exceptions.WMSException;
17
import org.gvsig.remoteclient.ogc.OGCProtocolHandler;
18
import org.gvsig.remoteclient.ogc.OGCServiceInformation;
19
import org.gvsig.remoteclient.utils.CapabilitiesTags;
20
import org.gvsig.remoteclient.utils.ExceptionTags;
21
import org.gvsig.remoteclient.utils.Utilities;
22
import org.gvsig.remoteclient.wms.request.WMSGetCapabilitiesRequest;
23
import org.gvsig.remoteclient.wms.request.WMSGetFeatureInfoRequest;
24
import org.gvsig.remoteclient.wms.request.WMSGetLegendGraphicRequest;
25
import org.gvsig.remoteclient.wms.request.WMSGetMapRequest;
26
import org.kxml2.io.KXmlParser;
27
import org.xmlpull.v1.XmlPullParserException;
28

    
29
/**
30
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.
31
 * </p>
32
 *
33
 */
34
public abstract class WMSProtocolHandler extends OGCProtocolHandler{
35
        /**
36
         * Encoding used to parse different xml documents.
37
         */
38
        protected String encoding = "UTF-8";
39
    /**
40
     * WMS metadata
41
     */
42
    protected WMSServiceInformation serviceInfo;
43
    public TreeMap layers;
44
    public WMSLayer rootLayer;
45

    
46
    /**
47
     * returns the alfanumeric information of the layers at the specified point.
48
     * the diference between the other getfeatureInfo method is that this will
49
     * be implemented by each specific version because the XML from the server will be
50
     * parsed and presented by a well known structure.
51
     */
52

    
53
    public String getName() {
54
            return name;
55
    }
56

    
57
    /*
58
     * (non-Javadoc)
59
     * @see org.gvsig.remoteClient.ogc.OGCProtocolHandler#getServiceInformation()
60
     */
61
    public OGCServiceInformation getServiceInformation() {
62
        return serviceInfo;
63
    }
64

    
65
    /**
66
         * <p>Builds a GetCapabilities request that is sent to the WMS
67
         * the response will be parse to extract the data needed by the
68
         * WMS client</p>
69
         * @param override, if true the previous downloaded data will be overridden
70
         */
71
    public void getCapabilities(WMSStatus status, boolean override, ICancellable cancel)
72
    {
73
            try
74
                {
75
                    if (status == null){
76
                            
77
                    }
78
                        WMSGetCapabilitiesRequest request = createGetCapabilitiesRequest(status);
79
                        File f = request.sendRequest(cancel);                        
80
        
81
                        if (f == null)
82
                                return;
83
                        clear();
84
                        parseCapabilities(f);
85
            } catch(Exception e)
86
                {
87
                        //TODO
88
                        e.printStackTrace();
89
                }
90
    }
91

    
92
    private void clear() {
93
                layers.clear();
94
                serviceInfo.clear();
95
        }
96

    
97
        /**
98
     * <p>It will send a GetFeatureInfo request to the WMS
99
     * Parsing the response and redirecting the info to the WMS client</p>
100
     * TODO: return a stored file instead a String.
101
     */
102
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount, ICancellable cancel)
103
    {
104
            StringBuffer output = new StringBuffer();
105
            String outputFormat = new String();
106
            String ServiceException = "ServiceExceptionReport";
107
            StringBuffer sb = new StringBuffer();
108
            sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
109
                try
110
                {
111
                        WMSGetFeatureInfoRequest request = createGetFeatureInfoRequest(status, x, y);
112
                        URL url = request.getURL();
113
                    outputFormat = url.openConnection().getContentType();
114
                    File f = request.sendRequest(cancel);
115
                        if (f == null){
116
                                return "";
117
                        }
118

    
119
                        FileReader fReader = new FileReader(f);
120
                        char[] buffer = new char[1024*256];
121
                        for (int i = fReader.read(buffer); i>0; i = fReader.read(buffer))
122
                    {
123
                            String str = new String(buffer,0,i);
124
                            output.append(str);
125
                    }
126
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1)
127
                                    ||output.toString().toLowerCase().startsWith("<?xml")
128
                                    ||(outputFormat.indexOf("gml") != -1))
129
                    {
130
                            int tag;
131
                            KXmlParser kxmlParser = null;
132
                            kxmlParser = new KXmlParser();
133
                            //kxmlParser.setInput(new StringReader(output.toString()));
134
                            kxmlParser.setInput(new FileReader(f));
135

    
136
                            tag = kxmlParser.nextTag();
137
                            if (kxmlParser.getName().compareTo(ServiceException)==0)
138
                                {
139
                                    sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>");
140
                                    return sb.toString();
141
                                }
142
                                else if (kxmlParser.getName().compareToIgnoreCase("ERROR")==0)
143
                                {
144
                                        return output.toString();
145
                                }
146
                                else
147
                                {
148
                                        return output.toString();
149
                                }
150
                    }
151
                    else
152
                    {                  
153
                            //Para que funcione con el GetFeatureInfo Viewer generico hay que devolver:
154
                             return output.toString();
155
                    }
156
                }
157
            catch(XmlPullParserException parserEx)
158
            {
159
                    if (output.toString().toLowerCase().indexOf("xml") != -1)
160
                    {
161
                            return output.toString().trim();
162
                    }
163
                    else
164
                    {
165
                               sb.append("<INFO>").append("Info format not supported").append("</INFO>");
166
                        return sb.toString();
167
                    }
168
            }
169
            catch(Exception e)
170
            {
171
                    e.printStackTrace();
172
                    sb.append("<INFO>").append("Info format not supported").append("</INFO>");
173
                    return sb.toString();
174

    
175
            }
176
    }
177
    /**
178
     * <p>Builds a GetMap request that is sent to the WMS
179
     * the response (image) will be redirect to the
180
     * WMS client</p>
181
     */
182
    public byte[] _getMap(WMSStatus status) throws ServerErrorException, WMSException
183
    {
184
            try
185
                {
186
                        //TODO:
187
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
188
                        WMSGetMapRequest request = createGetMapRequest(status);
189
                        URL url = request.getURL();
190
                        
191
                        URLConnection conn = url.openConnection();
192
                        System.out.println(request.toString());
193
            String type = conn.getContentType();
194

    
195

    
196
                    byte[] imageBytes = null;
197
                    byte[] buffer = new byte[1024*256];
198
            InputStream is = conn.getInputStream();
199
                    int readed = 0;
200

    
201
                    for (int i = is.read(buffer); i>0; i = is.read(buffer)){
202
                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
203
                            byte[] buffered = new byte[readed+i];
204
                            for (int j = 0; j < buffered.length; j++) {
205
                                    if (j<readed){
206
                        // puts the previously downloaded bytes into the image buffer
207
                                            buffered[j] = imageBytes[j];
208
                                    }
209
                                    else {
210
                        // appends the recently downloaded bytes to the image buffer.
211
                                            buffered[j] = buffer[j-readed];
212
                                    }
213
                                }
214
                            imageBytes = (byte[]) buffered.clone();
215
                            readed += i;
216
                    }
217

    
218
                    if ((type !=null && !type.subSequence(0,5).equals("image"))
219
                            ||(Utilities.isTextData(imageBytes)))
220
                    {
221
                       WMSException wmsEx = null;
222

    
223
                    String exceptionMessage = parseException(imageBytes);
224
                if (exceptionMessage==null)
225
                {
226
                         String error = new String(imageBytes);
227
                        int pos = error.indexOf("<?xml");
228
                        if (pos!= -1)
229
                        {
230
                                String xml = error.substring(pos,error.length());
231
                                exceptionMessage = parseException(xml.getBytes());
232
                        if (exceptionMessage == null)
233
                                exceptionMessage = new String(imageBytes);
234
                        }
235
                }
236
                     wmsEx = new WMSException(exceptionMessage);
237
                    wmsEx.setWMSMessage(new String(imageBytes));
238
                throw wmsEx;
239
            }
240
                        return imageBytes;
241
                }
242
                catch(IOException e)
243
                {
244
                        e.printStackTrace();
245
            throw new ServerErrorException();
246
                }
247
    }
248

    
249
    public File getLegendGraphic(WMSStatus status, String layerName, ICancellable cancel) throws ServerErrorException, WMSException
250
    {
251
            try
252
                {
253
                        WMSGetLegendGraphicRequest request = createGetLegendGraphicRequest(status, layerName);
254
                        File f = request.sendRequest(cancel);
255
                    if (f== null)
256
                            return null;
257
            if (Utilities.isTextFile(f)) {
258
                            
259
                byte[] data = fileToBytes(f);
260

    
261
                            WMSException wmsEx = null;
262

    
263
                    String exceptionMessage = parseException(data);
264
                if (exceptionMessage==null)
265
                {
266
                         String error = new String(data);
267
                        int pos = error.indexOf("<?xml");
268
                        if (pos!= -1)
269
                        {
270
                                String xml = error.substring(pos,error.length());
271
                                exceptionMessage = parseException(xml.getBytes());
272
                        }
273
                    if (exceptionMessage == null)
274
                            exceptionMessage = new String(data);
275

    
276
                }
277
                     wmsEx = new WMSException(exceptionMessage);
278
                    wmsEx.setWMSMessage(new String(data));
279
                    downloader.removeURL(request);
280
                throw wmsEx;
281
            }
282
                        return f;
283
                }
284
                catch(IOException e)
285
                {
286
                        e.printStackTrace();
287
            throw new ServerErrorException();
288
                }
289
    }
290

    
291
    public File getMap(WMSStatus status, ICancellable cancel) throws ServerErrorException, WMSException
292
    {
293
            try
294
                {
295
                        WMSGetMapRequest request = createGetMapRequest(status);
296
                        File f = request.sendRequest(cancel);
297
                        
298
                        if (f== null)
299
                            return null;
300
            if (Utilities.isTextFile(f)) {
301
                byte[] data = fileToBytes(f);
302

    
303
                            WMSException wmsEx = null;
304

    
305
                    String exceptionMessage = parseException(data);
306
                if (exceptionMessage==null)
307
                {
308
                         String error = new String(data);
309
                        int pos = error.indexOf("<?xml");
310
                        if (pos!= -1)
311
                        {
312
                                String xml = error.substring(pos,error.length());
313
                                exceptionMessage = parseException(xml.getBytes());
314
//                        if (exceptionMessage == null)
315
//                                exceptionMessage = new String(data);
316
                        }
317
                    if (exceptionMessage == null)
318
                            exceptionMessage = new String(data);
319

    
320
                }
321
                     wmsEx = new WMSException(exceptionMessage);
322
                    wmsEx.setWMSMessage(new String(data));
323

    
324
                    // Since it is an error file, It must be deleted from the cache
325
                    downloader.removeURL(request);
326
                throw wmsEx;
327
            }
328
                        return f;
329
                }
330
                catch(IOException e)
331
                {
332
                        e.printStackTrace();
333
            throw new ServerErrorException();
334
                }
335
    }
336

    
337

    
338
    /* (non-Javadoc)
339
     * @see org.gvsig.remoteClient.wms.WMSProtocolHandler#parseException(byte[])
340
     */
341
    protected String parseException(byte[] data) {
342
        ArrayList errors = new ArrayList();
343
        KXmlParser kxmlParser = new KXmlParser();
344
        try
345
        {
346
            kxmlParser.setInput(new ByteArrayInputStream(data), encoding);
347
            kxmlParser.nextTag();
348
            int tag;
349
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
350
            {
351
                kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);
352
                tag = kxmlParser.nextTag();
353
                 while(tag != KXmlParser.END_DOCUMENT)
354
                 {
355
                     switch(tag)
356
                     {
357
                        case KXmlParser.START_TAG:
358
                            if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){
359
                                String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE);
360
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
361
                                String errorMessage = kxmlParser.nextText();
362
                                errors.add(errorCode+errorMessage);
363
                            }
364
                            break;
365
                        case KXmlParser.END_TAG:
366
                            break;
367

    
368
                     }
369
                     tag = kxmlParser.nextTag();
370
                 }
371
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
372
            }
373
        }
374
        catch(XmlPullParserException parser_ex){
375
            parser_ex.printStackTrace();
376
        }
377
        catch (IOException ioe) {
378
            ioe.printStackTrace();
379
        }
380
        String message = errors.size()>0? "" : null;
381
        for (int i = 0; i < errors.size(); i++) {
382
            message += (String) errors.get(i)+"\n";
383
        }
384
        return message;
385
    }
386
    /**
387
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
388
     * without a VERSION, to get the highest version than a WMS supports.
389
     */
390
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version)
391
    {
392
                int index = _host.indexOf('?');
393
                
394
                if (index > -1) {
395
                        String host = _host.substring(0, index + 1);
396
                        String query = _host.substring(index + 1, _host.length());
397
                        
398
                        StringTokenizer tokens = new StringTokenizer(query, "&");
399
                        String newQuery = "", token;
400

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

    
405
                                if (token.toUpperCase().compareTo("REQUEST=GETCAPABILITIES") == 0)
406
                                        continue;
407

    
408
                                if (token.toUpperCase().compareTo("SERVICE=WMS") == 0)
409
                                        continue;
410

    
411
                                if ((_version != null) && (_version.length() > 0)) {
412
                                    if (token.toUpperCase().compareTo("VERSION=" + _version) == 0)
413
                                            continue;
414
                                }
415

    
416
                                if (token.toUpperCase().compareTo("EXCEPTIONS=XML") == 0)
417
                                        continue;
418

    
419
                                newQuery += token + "&";
420
                        }
421

    
422
                _host = host + newQuery;
423
                }
424
                else {
425
                        _host += "?";
426
                }
427

    
428
            if ((_version != null) && (_version.compareTo("") != 0))
429
                    _host += "REQUEST=GetCapabilities&SERVICE=WMS&VERSION=" + _version;
430
            else
431
                    _host += "REQUEST=GetCapabilities&SERVICE=WMS";
432

    
433
            return _host;
434
    }
435

    
436
    /**
437
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
438
     * @param WMSStatus
439
     */
440
    private String buildCapabilitiesRequest(WMSStatus status)
441
    {
442
                StringBuffer req = new StringBuffer();
443
                String symbol = null;
444

    
445
                String onlineResource;
446
                if (status == null || status.getOnlineResource() == null)
447
                        onlineResource = getHost();
448
                else
449
                        onlineResource = status.getOnlineResource();
450
                symbol = getSymbol(onlineResource);
451

    
452
                req.append(onlineResource).append(symbol).append("REQUEST=GetCapabilities&SERVICE=WMS&");
453
                req.append("VERSION=").append(getVersion());
454
                return req.toString();
455
    }  
456
   
457
     public void close() {
458
        // your code here
459
    } 
460
     
461
     /**
462
          * @param status
463
          * The WMS status
464
          * @param protocolHandler
465
          * The handler to parse the requests
466
          * @return an object to send the GetMap requests
467
          */
468
         protected abstract WMSGetMapRequest createGetMapRequest(WMSStatus status);
469
         
470
         protected abstract WMSGetFeatureInfoRequest createGetFeatureInfoRequest(WMSStatus status, int x, int y);
471
         
472
         protected abstract WMSGetLegendGraphicRequest createGetLegendGraphicRequest(WMSStatus status, String layerName);
473

    
474
         protected abstract WMSGetCapabilitiesRequest createGetCapabilitiesRequest(WMSStatus status);
475
         
476
         /**
477
     * <p>Parses the Request tag </p>
478
     */ 
479
    protected void parseRequestTag(KXmlParser parser) throws IOException, XmlPullParserException
480
    {        
481
            int currentTag;
482
            boolean end = false;
483
            
484
            parser.require(KXmlParser.START_TAG, null, CapabilitiesTags.REQUEST);
485
            currentTag = parser.next();
486
            
487
            while (!end) 
488
            {
489
                         switch(currentTag)
490
                         {
491
                                case KXmlParser.START_TAG:
492
                                        if (parser.getName().compareTo(CapabilitiesTags.GETCAPABILITIES)==0)
493
                                        {
494
                                                parserDcpType(parser, CapabilitiesTags.GETCAPABILITIES);
495
                                        }        
496
                                        else if (parser.getName().compareTo(CapabilitiesTags.GETMAP)==0)
497
                                        {        
498
                                                parseGetMapTag(parser);                                                
499
                                        }
500
                                        else if (parser.getName().compareTo(CapabilitiesTags.GETFEATUREINFO)==0)
501
                                        {
502
                                                parseGetFeatureInfoTag(parser);
503
                                        }                
504
                                        else if (parser.getName().compareTo(CapabilitiesTags.DESCRIBELAYER)==0)
505
                                        {
506
                                                parserDcpType(parser, CapabilitiesTags.DESCRIBELAYER);
507
                                        }        
508
                                        else if (parser.getName().compareTo(CapabilitiesTags.GETLEGENDGRAPHIC)==0)
509
                                        {
510
                                                parseGetLegendGraphicTag(parser);
511
                                        }                                        
512
                                        break;
513
                                case KXmlParser.END_TAG:
514
                                        if (parser.getName().compareTo(CapabilitiesTags.REQUEST) == 0)
515
                                                end = true;
516
                                        break;
517
                                case KXmlParser.TEXT:                                        
518
                                break;
519
                         }
520
                         if(!end)
521
                                 currentTag = parser.next();
522
            }
523
            // TODO: does not get such a tag when arrives here!!!!!!
524
            //parser.require(KXmlParser.END_TAG, null, CapabilitiesTags.REQUEST);            
525
    }   
526
          /**
527
     * <p>Parses the GetMap tag </p>
528
     */ 
529
    protected void parseGetMapTag(KXmlParser parser) throws IOException, XmlPullParserException
530
    {        
531
            int currentTag;
532
            boolean end = false;
533
            
534
            parser.require(KXmlParser.START_TAG, null, CapabilitiesTags.GETMAP);
535
            currentTag = parser.next();
536
            
537
            while (!end) 
538
            {
539
                         switch(currentTag)
540
                         {
541
                                case KXmlParser.START_TAG:
542
                                        if (parser.getName().compareTo(CapabilitiesTags.FORMAT)==0)
543
                                        {
544
                                                serviceInfo.formats.add(parser.nextText());
545
                                        }        
546
                                        else if (parser.getName().compareTo(CapabilitiesTags.DCPTYPE)==0)
547
                                        {                
548
                                                parserDcpType(parser, CapabilitiesTags.GETMAP);                                                
549
                                        }                        
550
                                        break;
551
                                case KXmlParser.END_TAG:
552
                                        if (parser.getName().compareTo(CapabilitiesTags.GETMAP) == 0)
553
                                                end = true;
554
                                        break;
555
                                case KXmlParser.TEXT:                                        
556
                                break;
557
                         }
558
                         if(!end)
559
                                 currentTag = parser.next();
560
            }        
561
    }    
562
    
563
    /**
564
     * <p>Parses the GetFeatureInfo tag </p>
565
     */ 
566
    protected void parseGetFeatureInfoTag(KXmlParser parser) throws IOException, XmlPullParserException
567
    {        
568
            int currentTag;
569
            boolean end = false;
570
            
571
            parser.require(KXmlParser.START_TAG, null, CapabilitiesTags.GETFEATUREINFO);
572
            currentTag = parser.next();
573
            
574
            while (!end) 
575
            {
576
                         switch(currentTag)
577
                         {
578
                                case KXmlParser.START_TAG:
579
                                        if (parser.getName().compareTo(CapabilitiesTags.FORMAT)==0)
580
                                        {
581
                                                //TODO:
582
                                                // add the supported formats by the GetFeatureInfo request
583
                                                //serviceInfo.formats.add(parser.nextText());
584
                                        }        
585
                                        else if (parser.getName().compareTo(CapabilitiesTags.DCPTYPE)==0)
586
                                        {                        
587
                                                parserDcpType(parser, CapabilitiesTags.GETFEATUREINFO);                
588
                                        }                        
589
                                        break;
590
                                case KXmlParser.END_TAG:
591
                                        if (parser.getName().compareTo(CapabilitiesTags.GETFEATUREINFO) == 0)
592
                                                end = true;
593
                                        break;
594
                                case KXmlParser.TEXT:                                        
595
                                break;
596
                         }
597
                         if(!end)
598
                                 currentTag = parser.next();
599
            }        
600
    }     
601
 
602
    /**
603
     * <p>Parses the GetLegendGraphic tag </p>
604
     */ 
605
    protected void parseGetLegendGraphicTag(KXmlParser parser) throws IOException, XmlPullParserException
606
    {        
607
            int currentTag;
608
            boolean end = false;
609
            
610
            parser.require(KXmlParser.START_TAG, null, CapabilitiesTags.GETLEGENDGRAPHIC);
611
            currentTag = parser.next();
612
            
613
            while (!end) 
614
            {
615
                         switch(currentTag)
616
                         {
617
                                case KXmlParser.START_TAG:
618
                                        if (parser.getName().compareTo(CapabilitiesTags.FORMAT)==0)
619
                                        {
620
                                                //TODO:
621
                                                // add the supported formats by the GetLegendGraphic request
622
                                                //serviceInfo.formats.add(parser.nextText());
623
                                        }        
624
                                        else if (parser.getName().compareTo(CapabilitiesTags.DCPTYPE)==0)
625
                                        {                        
626
                                                parserDcpType(parser, CapabilitiesTags.GETLEGENDGRAPHIC);                
627
                                        }                        
628
                                        break;
629
                                case KXmlParser.END_TAG:
630
                                        if (parser.getName().compareTo(CapabilitiesTags.GETLEGENDGRAPHIC) == 0)
631
                                                end = true;
632
                                        break;
633
                                case KXmlParser.TEXT:                                        
634
                                break;
635
                         }
636
                         if(!end)
637
                                 currentTag = parser.next();
638
            }        
639
    }
640
 }