Statistics
| Revision:

root / branches / v05 / libraries / libRemoteServices / src / org / gvsig / remoteClient / wms / WMSProtocolHandler.java @ 4036

History | View | Annotate | Download (20.8 KB)

1
package org.gvsig.remoteClient.wms;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.DataInputStream;
5
import java.io.File;
6
import java.io.FileInputStream;
7
import java.io.IOException;
8
import java.io.InputStream;
9
import java.io.InputStreamReader;
10
import java.io.Reader;
11
import java.io.StringReader;
12
import java.net.URL;
13
import java.net.URLConnection;
14
import java.nio.ByteBuffer;
15
import java.nio.channels.FileChannel;
16
import java.util.ArrayList;
17
import java.util.HashMap;
18
import java.util.TreeMap;
19
import java.util.Vector;
20

    
21
import org.gvsig.remoteClient.exceptions.ServerErrorException;
22
import org.gvsig.remoteClient.exceptions.WMSException;
23
import org.gvsig.remoteClient.utils.CapabilitiesTags;
24
import org.gvsig.remoteClient.utils.ExceptionTags;
25
import org.gvsig.remoteClient.utils.Utilities;
26
import org.kxml2.io.KXmlParser;
27
import org.xmlpull.v1.XmlPullParserException;
28

    
29
import com.iver.andami.PluginServices;
30

    
31
/**
32
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.
33
 * </p>
34
 * 
35
 */
36
public abstract class WMSProtocolHandler {
37
        
38
        /**
39
         * procotol handler name
40
         */
41
    protected String name;
42
    /**
43
     * protocol handler version
44
     */
45
    protected String version;
46
    /**
47
     * host of the WMS to connect
48
     */
49
    protected String host;
50
    /**
51
     * port number of the comunication channel of the WMS to connect
52
     */
53
    protected String port;    
54
    /**
55
     * WMS metadata
56
     */
57
    protected ServiceInformation serviceInfo;
58
    public TreeMap layers;
59
    public WMSLayer rootLayer;
60
    public Vector srs;
61
    
62
    /**
63
     * parses the data retrieved by the WMS in XML format. 
64
     * It will be mostly the WMS Capabilities, but the implementation
65
     * will be placed in the handler implementing certain version of the protocol.
66
     * 
67
     */
68
    public abstract void parse(File f) ;
69

    
70
    public String getName() {        
71
            return name;
72
    } 
73

    
74
    public String getVersion() {        
75
            return version;
76
    }    
77
    
78
    public ServiceInformation getServiceInformation() {        
79
        return serviceInfo;
80
    }  
81
    public String getHost ()
82
    {
83
            return host;
84
    }
85
    public void setHost(String _host)
86
    {
87
            host = _host;
88
    }
89
    public String getPort()
90
    {
91
            return port;
92
    }
93
    public void setPort(String _port)
94
    {
95
            port = _port;
96
    }
97
    
98

    
99
    /**
100
         * <p>Builds a GetCapabilities request that is sent to the WMS
101
         * the response will be parse to extract the data needed by the
102
         * WMS client</p>
103
         */
104
    public void getCapabilities(WMSStatus status)
105
    {                
106
            URL request = null;
107
                try
108
                {
109
                        request = new URL(buildCapabilitiesRequest(status));
110
                }
111
                catch(Exception e)
112
                {
113
                        e.printStackTrace();
114
                }
115
                try
116
                {
117
                File f = com.iver.andami.Utilities.downloadFile(request,"wms_capabilities.xml");
118
            parse(f);
119
            } catch(Exception e)
120
                {
121
                        //TODO
122
                        e.printStackTrace();
123
                }
124
    }
125

    
126
    /**
127
     * <p>It will send a GetFeatureInfo request to the WMS
128
     * Parsing the response and redirecting the info to the WMS client</p>
129
     */
130
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount)
131
    {
132
            URL request = null;
133
            StringBuffer output = new StringBuffer();
134
            String outputFormat = new String();
135
            String ServiceException = "ServiceExceptionReport";                        
136
            StringBuffer sb = new StringBuffer();
137
            sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
138
                try
139
                {
140
                        //TODO:
141
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
142
                        request = new URL(buildGetFeatureInfoRequest(status, x, y));
143
                        
144
                        //TODO:
145
                        //see which output format is being requested.                                         
146
                }
147
                catch(Exception e)
148
                {
149
                        e.printStackTrace();
150
                        return "";
151
                }
152
                
153
            try
154
            {                                
155
                    System.out.println(request.toString());          
156
                    byte[] buffer = new byte[1024*256];                    
157
                    DataInputStream is = new DataInputStream(request.openStream());                    
158
                    outputFormat = request.openConnection().getContentType();
159

    
160
                    for (int i = is.read(buffer); i>0; i = is.read(buffer))
161
                    {
162
                            String str = new String(buffer,0,i);
163
                            output.append(str);                    
164
                    }
165
                                
166
                    is.close();
167
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1)
168
                                    ||output.toString().toLowerCase().startsWith("<?xml")
169
                                    ||(outputFormat.indexOf("gml") != -1))
170
                    {
171
                            int tag;
172
                            KXmlParser kxmlParser = null;
173
                            kxmlParser = new KXmlParser();            
174
                            kxmlParser.setInput(new StringReader(output.toString()));
175
                            
176
                            tag = kxmlParser.nextTag();                   
177
                                  while(tag != KXmlParser.END_DOCUMENT)
178
                                 {
179
                                         switch(tag)
180
                                         {
181
                                                case KXmlParser.START_TAG:                
182
                                                        if (kxmlParser.getName().compareTo(ServiceException)==0)
183
                                                        {
184
                                                            sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>");
185
                                                            return sb.toString();                                                                        
186
                                                        }
187
                                                        else if (kxmlParser.getName().compareToIgnoreCase("ERROR")==0)
188
                                                                return output.toString();
189
                                                        else                                                                
190
                                                                sb.append("<" + kxmlParser.getName() + ">\n");
191
                                                        break;
192
                                                case KXmlParser.END_TAG:        
193
                                                        sb.append("</" + kxmlParser.getName() + ">\n");
194
                                                        break;
195
                                                case KXmlParser.TEXT:
196
                                                        sb.append(kxmlParser.getText());                                                
197
                                                break;
198
                                         }
199
                                     tag = kxmlParser.next();
200
                             }                                    
201
                            return sb.toString();
202
                    }
203
                    else
204
                    {
205
                            sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
206
                            return sb.toString();
207
                    }
208
                }
209
            catch(XmlPullParserException parserEx)
210
            {
211
                    if (output.toString().toLowerCase().indexOf("xml") != -1)
212
                    {
213
                            return output.toString().trim();
214
                    }
215
                    else
216
                    {
217
                               sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
218
                        return sb.toString();
219
                    }
220
            }
221
            catch(Exception e)
222
            {
223
                    e.printStackTrace();
224
                    sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
225
                    return sb.toString();
226

    
227
            }
228
    }
229
    /**
230
     * <p>Builds a GetMap request that is sent to the WMS
231
     * the response (image) will be redirect to the
232
     * WMS client</p>
233
     */   
234
    public byte[] _getMap(WMSStatus status) throws ServerErrorException, WMSException
235
    {        
236
            URL request = null;
237
                try
238
                {
239
                        //TODO:
240
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
241
                        request = new URL(buildMapRequest(status));
242
                        URLConnection conn = request.openConnection();
243
                        System.out.println(request.toString());
244
            String type = conn.getContentType();
245
            
246
                                
247
                    byte[] imageBytes = null;
248
                    byte[] buffer = new byte[1024*256];
249
            InputStream is = conn.getInputStream();
250
                    int readed = 0;
251
                    
252
                    for (int i = is.read(buffer); i>0; i = is.read(buffer)){
253
                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
254
                            byte[] buffered = new byte[readed+i];
255
                            for (int j = 0; j < buffered.length; j++) {
256
                                    if (j<readed){
257
                        // puts the previously downloaded bytes into the image buffer
258
                                            buffered[j] = imageBytes[j];
259
                                    }
260
                                    else {
261
                        // appends the recently downloaded bytes to the image buffer.
262
                                            buffered[j] = buffer[j-readed];
263
                                    }
264
                                }
265
                            imageBytes = (byte[]) buffered.clone();
266
                            readed += i;                            
267
                    }
268
                    
269
                    if ((type !=null && !type.subSequence(0,5).equals("image")) 
270
                            ||(Utilities.isTextData(imageBytes)))
271
                    {                            
272
                       WMSException wmsEx = null;
273
                       
274
                    String exceptionMessage = parseException(imageBytes);
275
                if (exceptionMessage==null)
276
                {
277
                         String error = new String(imageBytes);
278
                        int pos = error.indexOf("<?xml");
279
                        if (pos!= -1)
280
                        {
281
                                String xml = error.substring(pos,error.length());
282
                                exceptionMessage = parseException(xml.getBytes());
283
                        if (exceptionMessage == null)
284
                                exceptionMessage = new String(imageBytes);
285
                        }
286
                }
287
                     wmsEx = new WMSException(exceptionMessage);
288
                    wmsEx.setWMSMessage(new String(imageBytes));
289
                throw wmsEx;
290
            }
291
                        return imageBytes;                    
292
                }
293
                catch(IOException e)
294
                {
295
                        e.printStackTrace();
296
            throw new ServerErrorException();
297
                }
298
    } 
299
    
300
    public File getMap(WMSStatus status) throws ServerErrorException, WMSException
301
    {        
302
            URL request = null;
303
                try
304
                {
305
                        //TODO:
306
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
307
                        request = new URL(buildMapRequest(status));
308
//                        URLConnection conn = request.openConnection();
309
//                        System.out.println(request.toString());
310
//            String type = conn.getContentType();
311
            
312
            File f = com.iver.andami.Utilities.downloadFile(request, "wmsGetMap");                    
313
                    //byte[] imageBytes = null;
314
                    
315
                    
316
//                    if ((type !=null && !type.subSequence(0,5).equals("image")) 
317
//                            ||(Utilities.isTextFile(f))) {
318
            if (Utilities.isTextFile(f)) {
319
                            FileInputStream fis = new FileInputStream(f);
320
                            FileChannel fc = fis.getChannel();
321
                            byte[] data = new byte[(int)fc.size()];   // fc.size returns the size of the file which backs the channel
322
                            ByteBuffer bb = ByteBuffer.wrap(data);
323
                            fc.read(bb);
324
                                                        
325
                            WMSException wmsEx = null;
326
                       
327
                    String exceptionMessage = parseException(data);
328
                if (exceptionMessage==null)
329
                {
330
                         String error = new String(data);
331
                        int pos = error.indexOf("<?xml");
332
                        if (pos!= -1)
333
                        {
334
                                String xml = error.substring(pos,error.length());
335
                                exceptionMessage = parseException(xml.getBytes());
336
//                        if (exceptionMessage == null)
337
//                                exceptionMessage = new String(data);
338
                        }               
339
                    if (exceptionMessage == null)
340
                            exceptionMessage = new String(data);
341
                        
342
                }
343
                     wmsEx = new WMSException(exceptionMessage);
344
                    wmsEx.setWMSMessage(new String(data));
345
                    
346
                    // Since it is an error file, It must be deleted from the cache
347
                    com.iver.andami.Utilities.removeURL(request);
348
                            
349
                throw wmsEx;
350
            }
351
                        return f;                    
352
                }
353
                catch(IOException e)
354
                {
355
                        e.printStackTrace();
356
            throw new ServerErrorException();
357
                }
358
    } 
359

    
360
    
361
    
362
    /* (non-Javadoc)
363
     * @see org.gvsig.remoteClient.wms.WMSProtocolHandler#parseException(byte[])
364
     */
365
    protected String parseException(byte[] data) {
366
        ArrayList errors = new ArrayList();
367
        KXmlParser kxmlParser = new KXmlParser();
368
        Reader reader = new InputStreamReader(new ByteArrayInputStream(data));
369
        try
370
        {
371
            kxmlParser.setInput(reader);        
372
            kxmlParser.nextTag();
373
            int tag;
374
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT ) 
375
            { 
376
                kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);             
377
                tag = kxmlParser.nextTag();
378
                 while(tag != KXmlParser.END_DOCUMENT)
379
                 {
380
                     switch(tag)
381
                     {
382
                        case KXmlParser.START_TAG:
383
                            if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){
384
                                String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE);
385
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
386
                                String errorMessage = kxmlParser.nextText();
387
                                errors.add(errorCode+errorMessage);
388
                            }
389
                            break;
390
                        case KXmlParser.END_TAG:                            
391
                            break;
392
                        
393
                     }
394
                     tag = kxmlParser.nextTag();
395
                 }
396
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
397
            }
398
        }
399
        catch(XmlPullParserException parser_ex){ 
400
            parser_ex.printStackTrace();
401
        }
402
        catch (IOException ioe) {           
403
            ioe.printStackTrace();            
404
        }
405
        String message = errors.size()>0? "" : null;
406
        for (int i = 0; i < errors.size(); i++) {
407
            message += (String) errors.get(i)+"\n";
408
        }
409
        return message;
410
    }
411
    /**
412
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
413
     * without a VERSION, to get the highest version than a WMS supports.
414
     */
415
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version)
416
    {
417
                String req = new String();                
418
        String symbol = getSymbol(_host);
419
        req = req + _host + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";                
420
        if((_version != null) && (_version.length()>0 ))
421
        {
422
                req += ("&VERSION=" + _version);
423
        }
424
                req += ("&EXCEPTIONS=XML");
425
                return req;           
426
    }
427
    
428
//    /**
429
//     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
430
//     */
431
//    private String buildCapabilitiesRequest()
432
//    {
433
//                String req = new String();
434
//                String host = getHost();
435
//
436
//        String symbol = getSymbol(host);
437
//        req = req + getHost() + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
438
//                req = req + "VERSION=" + getVersion();
439
//                req += ("&EXCEPTIONS=XML");
440
//                return req;
441
//    }
442

    
443
    /**
444
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
445
     * @param WMSStatus
446
     */
447
    //private String buildCapabilitiesRequest()
448
    private String buildCapabilitiesRequest(WMSStatus status)
449
    {
450
                String req = null;
451
//                String resource = null;
452
                String symbol = null;
453
                
454
//                String onlineResource = null;
455
//                if(serviceInfo != null)
456
//                {
457
//                        onlineResource = serviceInfo.online_resource;
458
//                }
459
//                        
460
//                if (onlineResource == null)
461
//                {
462
//                        resource = getHost();
463
//                }
464
//                else
465
//                {
466
//                        resource = onlineResource;
467
//                }
468
//                symbol = getSymbol(resource);
469
        
470
//      req = resource + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
471
                String onlineResource;
472
                if (status == null || status.getOnlineResource() == null)
473
                        onlineResource = getHost();
474
                else 
475
                        onlineResource = status.getOnlineResource();
476
                symbol = getSymbol(onlineResource);
477
                
478
                req = onlineResource + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
479
                req = req + "VERSION=" + getVersion();
480
                req += ("&EXCEPTIONS=XML");
481
                return req;
482
    }
483
    
484
    /**
485
     * Builds the GetFeatureInfoRequest according to the OGC WMS Specifications
486
     */
487
    private String buildGetFeatureInfoRequest(WMSStatus status, int x, int y)
488
    {
489
                String req = null;
490
//                String resource = null;
491
                String symbol = null;
492
//                
493
//                if ((serviceInfo == null)
494
//                                || (serviceInfo.feature_online_resource == null))
495
//                {
496
//                        resource = getHost();
497
//                }
498
//                else
499
//                {
500
//                        resource = serviceInfo.feature_online_resource; 
501
//                }
502
                String onlineResource;
503
                if (status.getOnlineResource() == null)
504
                        onlineResource = getHost();
505
                else 
506
                        onlineResource = status.getOnlineResource();
507
                symbol = getSymbol(onlineResource);
508
        
509
                req = onlineResource + symbol + "REQUEST=GetFeatureInfo&SERVICE=WMS&";
510
                req = req + "QUERY_LAYERS="+Utilities.Vector2CS(status.getLayerNames()); 
511
                req = req + "&VERSION=" + getVersion() + "&";
512
                req = req + "INFO_FORMAT=application/vnd.ogc.gml&";
513
                req = req + getPartialQuery(status);
514
                req = req + "&x="+x + "&y="+y;
515
       if (status.getExceptionFormat() != null) {
516
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
517
        } else {
518
            req += ("&EXCEPTIONS=XML");
519
        }
520
                return req;
521
    }    
522

    
523
    /**
524
     * Builds the GetMapRequest according to the OGC WMS Specifications
525
     */
526
    private String buildMapRequest(WMSStatus status)
527
    { 
528
                String req = null;
529
//                String resource = null;
530
                String symbol = null;
531
//                
532
//                if ((serviceInfo == null)
533
//                                || (serviceInfo.map_online_resource == null))
534
//                {
535
//                        resource = getHost();
536
//                }
537
//                else
538
//                {
539
//                        resource = serviceInfo.map_online_resource; 
540
//                }
541
//                symbol = getSymbol(resource);
542
                String onlineResource;
543
                if (status.getOnlineResource() == null)
544
                        onlineResource = getHost();
545
                else 
546
                        onlineResource = status.getOnlineResource();
547
                symbol = getSymbol(onlineResource);
548
        
549
                req = onlineResource + symbol + "REQUEST=GetMap&SERVICE=WMS&";
550
                req = req + "VERSION=" + getVersion() + "&";
551
                req = req + getPartialQuery(status);
552
       if (status.getExceptionFormat() != null) {
553
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
554
        } else {
555
            req += ("&EXCEPTIONS=XML");
556
        }
557
                return req;
558
    }
559
    
560
    /**
561
     * Just for not repeat code. Gets the correct separator according to the server URL
562
     * @param h
563
     * @return
564
     */
565
    private static String getSymbol(String h) {
566
        String symbol;
567
        if (h.indexOf("?")==-1) 
568
            symbol = "?";
569
        else if (h.indexOf("?")!=h.length()-1)
570
            symbol = "&";
571
        else
572
            symbol = "";
573
        return symbol;
574
    }
575

    
576
    /**
577
     * Gets the part of the OGC request that share GetMap and GetFeatureInfo
578
     * @return String request
579
     */
580
    public String getPartialQuery(WMSStatus status)
581
    {            
582
        String req = "LAYERS=" + Utilities.Vector2CS(status.getLayerNames()) + 
583
                    "&SRS=" + status.getSrs() +
584
                    "&BBOX=" + status.getExtent().getMinX()+ "," +
585
                                    status.getExtent().getMinY()+ "," +
586
                                    status.getExtent().getMaxX()+ "," +
587
                                    status.getExtent().getMaxY() +
588
                    "&WIDTH=" + status.getWidth() +
589
                    "&HEIGHT=" + status.getHeight() + "&FORMAT=" + status.getFormat() +
590
                    "&STYLES=";
591
        Vector v = status.getStyles();
592
        if (v!=null && v.size()>0)
593
                req += Utilities.Vector2CS(v); 
594
        v = status.getDimensions();
595
        if (v!=null && v.size()>0)
596
            req += "&" + Utilities.Vector2URLParamString(v);
597
        if (status.getTransparency()) {
598
            req += "&TRANSPARENT=TRUE";
599
        }
600
//
601
//        if (status.getBGColor() != null) {
602
//            req += ("&COLOR=" + status.getBGColor());
603
//        }
604
//
605
        return req.replaceAll(" ", "%20");
606
    }
607

    
608
    
609
    
610
    public void close() {        
611
        // your code here
612
    } 
613
    
614
    /**
615
     * Inner class that represents the description of the WMS metadata.
616
     * The first part of the capabilities will return the service information
617
     * from the WMS, this class will hold this information. 
618
     * 
619
     */
620
    public class ServiceInformation {
621

    
622
        public String online_resource = null;
623
        /*public String map_online_resource = null;
624
        public String feature_online_resource = null;*/
625
        public String version;
626
        public String name;
627
        public String scope;
628
        public String title;
629
        public String abstr;
630
        public String keywords;
631
        public String fees;
632
        public String operationsInfo;
633
        public String personname;
634
        public String organization;
635
        public String function;
636
        public String addresstype;
637
        public String address;
638
        public String place;
639
        public String province;
640
        public String postcode;
641
        public String country;
642
        public String phone;
643
        public String fax;
644
        public String email;
645
        public Vector formats;
646
        public HashMap operations; // operations that WMS supports
647
        
648
        public ServiceInformation()
649
        {          
650
            version = new String();
651
            name = new String();
652
            scope = new String();
653
            title = new String();
654
            abstr = new String();
655
            keywords = new String();
656
            fees = new String();
657
            operationsInfo = new String();
658
            personname = new String();
659
            organization = new String();
660
            function = new String();
661
            addresstype = new String();
662
            address = new String();
663
            place = new String();
664
            province = new String();
665
            postcode = new String();
666
            country = new String();
667
            phone = new String();
668
            fax = new String();
669
            email = new String();
670
            formats = new Vector();               
671
            operations = new HashMap();            
672
        }
673
        public boolean isQueryable()
674
        {
675
                if (operations.keySet().contains( CapabilitiesTags.GETFEATUREINFO ))
676
                        return true;
677
                else
678
                        return false;
679
        }
680
     }   
681
 }