Statistics
| Revision:

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

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.kxml2.io.KXmlParser;
15
import org.xmlpull.v1.XmlPullParserException;
16

    
17
import org.gvsig.compat.net.ICancellable;
18
import org.gvsig.remoteclient.exceptions.ServerErrorException;
19
import org.gvsig.remoteclient.exceptions.WMSException;
20
import org.gvsig.remoteclient.ogc.OGCProtocolHandler;
21
import org.gvsig.remoteclient.ogc.OGCServiceInformation;
22
import org.gvsig.remoteclient.utils.CapabilitiesTags;
23
import org.gvsig.remoteclient.utils.ExceptionTags;
24
import org.gvsig.remoteclient.utils.Utilities;
25
import org.gvsig.remoteclient.wms.request.WMSGetCapabilitiesRequest;
26
import org.gvsig.remoteclient.wms.request.WMSGetFeatureInfoRequest;
27
import org.gvsig.remoteclient.wms.request.WMSGetLegendGraphicRequest;
28
import org.gvsig.remoteclient.wms.request.WMSGetMapRequest;
29

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

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

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

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

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

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

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

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

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

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

    
196

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

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

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

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

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

    
262
                            WMSException wmsEx = null;
263

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

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

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

    
304
                            WMSException wmsEx = null;
305

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

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

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

    
338

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

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

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

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

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

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

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

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

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

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

    
434
            return _host;
435
    }
436

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

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

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

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