Statistics
| Revision:

svn-gvsig-desktop / branches / MULTITHREADING_DEVELOPMENT / libraries / libRemoteServices / src / org / gvsig / remoteClient / wms / WMSProtocolHandler.java @ 5327

History | View | Annotate | Download (19.3 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.FileNotFoundException;
8
import java.io.IOException;
9
import java.io.InputStream;
10
import java.io.StringReader;
11
import java.net.MalformedURLException;
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.taskplanning.retrieving.RequestManager;
24
import org.gvsig.remoteClient.taskplanning.retrieving.RetrieveEvent;
25
import org.gvsig.remoteClient.taskplanning.retrieving.RetrieveListener;
26
import org.gvsig.remoteClient.taskplanning.retrieving.URLRequest;
27
import org.gvsig.remoteClient.taskplanning.retrieving.URLRetrieveTask;
28
import org.gvsig.remoteClient.utils.CapabilitiesTags;
29
import org.gvsig.remoteClient.utils.ExceptionTags;
30
import org.gvsig.remoteClient.utils.Utilities;
31
import org.kxml2.io.KXmlParser;
32
import org.xmlpull.v1.XmlPullParserException;
33

    
34
import com.iver.andami.PluginServices;
35

    
36
/**
37
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.
38
 * </p>
39
 * 
40
 */
41
public abstract class WMSProtocolHandler {
42
        /**
43
         * Encoding used to parse different xml documents.
44
         */
45
        protected String encoding = "UTF-8";
46
        /**
47
         * procotol handler name
48
         */
49
    protected String name;
50
    /**
51
     * protocol handler version
52
     */
53
    protected String version;
54
    /**
55
     * host of the WMS to connect
56
     */
57
    protected String host;
58
    /**
59
     * port number of the comunication channel of the WMS to connect
60
     */
61
    protected String port;    
62
    /**
63
     * WMS metadata
64
     */
65
    protected ServiceInformation serviceInfo;
66
    public TreeMap layers;
67
    public WMSLayer rootLayer;
68
    public Vector srs;
69
    
70
        private URLRequest capabilitiesRequest, mapRequest, featureInfo;
71
    
72
    /**
73
     * The listener that a driver must implement to receive the events.
74
     */
75
    private WMSEventListener theListener;
76
    
77
    /**
78
     * Listener for the asynchronous getCapabilities requests
79
     */
80
    private RetrieveListener getCapabilitiesListener = new RetrieveListener() {
81

    
82
                public void transferEventReceived(RetrieveEvent event) {
83
                        int type = event.getType();
84
                        
85
                        if (type == RetrieveEvent.REQUEST_FINISHED) {
86
                                System.out.println("parsing "+capabilitiesRequest.getFileName());
87
                                parse(new File(capabilitiesRequest.getFileName()));
88
                                
89
                        }
90
                        if (theListener!=null) {
91
                                theListener.newEvent(WMSEventListener.CAPABILITIES, event);
92
                        }
93

    
94
                }
95
            
96
    } ,
97
    /**
98
     * Listener for the asynchronous getMap requests
99
     */
100
    getMapListener = new RetrieveListener() {
101

    
102
                public void transferEventReceived(RetrieveEvent event) {
103
                        int type = event.getType();
104
                        
105
                        if (type == RetrieveEvent.REQUEST_FINISHED) {
106
                                
107
                                // TODO revisar no estic segur de que a?? haja d'estar ac?
108
                                System.out.println(event.getFileName());
109
                                
110
                                File f = new File(event.getFileName());
111
                                if (Utilities.isTextFile(f)) {
112
                                        FileInputStream fis;
113
                                        try {
114
                                                fis = new FileInputStream(f);
115
                                                FileChannel fc = fis.getChannel();
116
                                                byte[] data = new byte[(int)fc.size()];   // fc.size returns the size of the file which backs the channel
117
                                                ByteBuffer bb = ByteBuffer.wrap(data);
118
                                                fc.read(bb);
119
                                                String exceptionMessage = parseException(data);
120
                                                if (exceptionMessage==null)
121
                                                {
122
                                                        String error = new String(data);
123
                                                        int pos = error.indexOf("<?xml");
124
                                                        if (pos!= -1)
125
                                                        {
126
                                                                String xml = error.substring(pos,error.length());
127
                                                                exceptionMessage = parseException(xml.getBytes());
128
                                                        }               
129
                                                        if (exceptionMessage == null)
130
                                                                exceptionMessage = new String(data);
131
                                                        
132
                                                }
133
                                                event.setType(RetrieveEvent.ERROR);
134
                                                event.setMessage(exceptionMessage);
135
                                                
136
                                                // Since it is an error file, It must be deleted from the cache
137
                                                RequestManager.getInstance().removeURLRequest(mapRequest);
138
                                        } catch (Exception e) {
139
                                                e.printStackTrace();
140
                                        } 
141
                                        
142
                                        
143
                    }        
144
                                if (theListener!=null) {
145
                                        theListener.newEvent(WMSEventListener.MAP, event);
146
                                }
147
                        }
148
                }
149
            
150
    } ,
151
    getFeatureInfoListener = new RetrieveListener() {
152
                public void transferEventReceived(RetrieveEvent event) {
153
                        int type = event.getType();
154
                        
155
                }};
156
    /**
157
     * parses the data retrieved by the WMS in XML format. 
158
     * It will be mostly the WMS Capabilities, but the implementation
159
     * will be placed in the handler implementing certain version of the protocol.
160
     * 
161
     */
162
    public abstract void parse(File f) ;
163

    
164
    public String getName() {        
165
            return name;
166
    } 
167

    
168
    public String getVersion() {        
169
            return version;
170
    }    
171
    
172
    public ServiceInformation getServiceInformation() {        
173
        return serviceInfo;
174
    }  
175
    public String getHost ()
176
    {
177
            return host;
178
    }
179
    public void setHost(String _host)
180
    {
181
            host = _host;
182
    }
183
    public String getPort()
184
    {
185
            return port;
186
    }
187
    public void setPort(String _port)
188
    {
189
            port = _port;
190
    }
191
    
192

    
193
    /**
194
         * <p>Builds a GetCapabilities request that is sent to the WMS
195
         * the response will be parsed to extract the data needed by the
196
         * WMS client</p>
197
         * @param override, if true the previous downloaded data will be overridden
198
         */
199
    public void getCapabilities(WMSStatus status, boolean override)
200
    {                
201
            
202
                try
203
                {
204
                        //request = new URL(buildCapabilitiesRequest(status));
205
                        capabilitiesRequest = buildCapabilitiesRequest(status);
206
                        capabilitiesRequest.setFileName("wmsCapabilities");
207
                        if (override)
208
                                RequestManager.getInstance().removeURLRequest(capabilitiesRequest);
209
                        capabilitiesRequest = RequestManager.getInstance().addURLRequest(capabilitiesRequest, getCapabilitiesListener);
210
                        
211
            } catch(MalformedURLException e) {
212
                        e.printStackTrace();
213
                }
214
    }
215

    
216
    /**
217
     * <p>It will send a GetFeatureInfo request to the WMS
218
     * Parsing the response and redirecting the info to the WMS client</p>
219
     */
220
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount)
221
    {
222
            URL request = null;
223
            StringBuffer output = new StringBuffer();
224
            String outputFormat = new String();
225
            String ServiceException = "ServiceExceptionReport";                        
226
            StringBuffer sb = new StringBuffer();
227
            sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
228
                try
229
                {
230
                        //TODO:
231
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
232
                        request = new URL(buildGetFeatureInfoRequest(status, x, y));
233
                        
234
                        //TODO:
235
                        //see which output format is being requested.                                         
236
                }
237
                catch(Exception e)
238
                {
239
                        e.printStackTrace();
240
                        return "";
241
                }
242
                
243
            try
244
            {                                
245
                    System.out.println(request.toString());          
246
                    byte[] buffer = new byte[1024*256];                    
247
                    DataInputStream is = new DataInputStream(request.openStream());                    
248
                    outputFormat = request.openConnection().getContentType();
249

    
250
                    for (int i = is.read(buffer); i>0; i = is.read(buffer))
251
                    {
252
                            String str = new String(buffer,0,i);
253
                            output.append(str);                    
254
                    }
255
                                
256
                    is.close();
257
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1)
258
                                    ||output.toString().toLowerCase().startsWith("<?xml")
259
                                    ||(outputFormat.indexOf("gml") != -1))
260
                    {
261
                            int tag;
262
                            KXmlParser kxmlParser = null;
263
                            kxmlParser = new KXmlParser();            
264
                            kxmlParser.setInput(new StringReader(output.toString()));
265
                            
266
                            tag = kxmlParser.nextTag();           
267
                            if (kxmlParser.getName().compareTo(ServiceException)==0)
268
                                {
269
                                    sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>");
270
                                    return sb.toString();                                                                        
271
                                }
272
                                else if (kxmlParser.getName().compareToIgnoreCase("ERROR")==0)
273
                                {
274
                                        return output.toString();
275
                                }
276
                                else                
277
                                {
278
                                        return output.toString();                
279
                                }
280
                    }
281
                    else
282
                    {
283
                            sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
284
                            return sb.toString();
285
                    }
286
                }
287
            catch(XmlPullParserException parserEx)
288
            {
289
                    if (output.toString().toLowerCase().indexOf("xml") != -1)
290
                    {
291
                            return output.toString().trim();
292
                    }
293
                    else
294
                    {
295
                               sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
296
                        return sb.toString();
297
                    }
298
            }
299
            catch(Exception e)
300
            {
301
                    e.printStackTrace();
302
                    sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
303
                    return sb.toString();
304

    
305
            }
306
    }
307
    
308
    public void getMap(WMSStatus status) throws ServerErrorException, WMSException
309
    {      
310
                try
311
                {
312
                        mapRequest = buildMapRequest(status);
313
                        mapRequest.setFileName("wmsGetMap");
314
                        mapRequest = RequestManager.getInstance().addURLRequest(mapRequest, getMapListener);
315
                        
316
            } catch(MalformedURLException e) {
317
                        e.printStackTrace();
318
                }
319
    } 
320
    
321
    
322
    /* (non-Javadoc)
323
     * @see org.gvsig.remoteClient.wms.WMSProtocolHandler#parseException(byte[])
324
     */
325
    protected String parseException(byte[] data) {
326
        ArrayList errors = new ArrayList();
327
        KXmlParser kxmlParser = new KXmlParser();
328
        try
329
        {
330
            kxmlParser.setInput(new ByteArrayInputStream(data), encoding);        
331
            kxmlParser.nextTag();
332
            int tag;
333
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT ) 
334
            { 
335
                kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);             
336
                tag = kxmlParser.nextTag();
337
                 while(tag != KXmlParser.END_DOCUMENT)
338
                 {
339
                     switch(tag)
340
                     {
341
                        case KXmlParser.START_TAG:
342
                            if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){
343
                                String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE);
344
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
345
                                String errorMessage = kxmlParser.nextText();
346
                                errors.add(errorCode+errorMessage);
347
                            }
348
                            break;
349
                        case KXmlParser.END_TAG:                            
350
                            break;
351
                        
352
                     }
353
                     tag = kxmlParser.nextTag();
354
                 }
355
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
356
            }
357
        }
358
        catch(XmlPullParserException parser_ex){ 
359
            parser_ex.printStackTrace();
360
        }
361
        catch (IOException ioe) {           
362
            ioe.printStackTrace();            
363
        }
364
        String message = errors.size()>0? "" : null;
365
        for (int i = 0; i < errors.size(); i++) {
366
            message += (String) errors.get(i)+"\n";
367
        }
368
        return message;
369
    }
370
    /**
371
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
372
     * without a VERSION, to get the highest version than a WMS supports.
373
     */
374
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version)
375
    {
376
                String req = new String();                
377
        String symbol = getSymbol(_host);
378
        req = req + _host + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";                
379
        if((_version != null) && (_version.length()>0 ))
380
        {
381
                req += ("&VERSION=" + _version);
382
        }
383
                req += ("&EXCEPTIONS=XML");
384
                return req;           
385
    }
386

    
387
    /**
388
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
389
     * @param WMSStatus
390
     * @throws MalformedURLException 
391
     */
392
    private URLRequest buildCapabilitiesRequest(WMSStatus status) throws MalformedURLException
393
    {
394
                URLRequest req = new URLRequest();
395
                StringBuffer u = new StringBuffer();
396
                String onlineResource;
397
                if (status == null || status.getOnlineResource() == null)
398
                        onlineResource = getHost();
399
                else 
400
                        onlineResource = status.getOnlineResource();
401
                u.append(onlineResource).
402
                  append(getSymbol(onlineResource)).
403
                  append("REQUEST=GetCapabilities&SERVICE=WMS&").
404
                  append("VERSION=").append(getVersion()).append("&EXCEPTIONS=XML");
405
                URL url = new URL(u.toString());
406
                req.setHost(url.getHost());
407
                req.setRequestType(URLRequest.GET);
408
                req.setProtocol(URLRequest.HTTP);
409
                req.setFile(url.getFile());
410
                int myPort = url.getPort();
411
                if (myPort != -1 && myPort != 80 )
412
                        req.setPort(myPort);
413
                
414
                return req;
415
    }
416
    
417
    /**
418
     * Builds the GetFeatureInfoRequest according to the OGC WMS Specifications
419
     */
420
    private String buildGetFeatureInfoRequest(WMSStatus status, int x, int y)
421
    {
422
                StringBuffer req = new StringBuffer();
423
                String symbol = null;
424

    
425
                String onlineResource;
426
                if (status.getOnlineResource() == null)
427
                        onlineResource = getHost();
428
                else 
429
                        onlineResource = status.getOnlineResource();
430
                symbol = getSymbol(onlineResource);
431
        
432
                req.append(onlineResource).append(symbol).append("REQUEST=GetFeatureInfo&SERVICE=WMS&");
433
                req.append("QUERY_LAYERS=").append(Utilities.Vector2CS(status.getLayerNames())); 
434
                req.append("&VERSION=").append(getVersion()).append("&INFO_FORMAT=application/vnd.ogc.gml&");
435
                req.append(getPartialQuery(status)).append("&x="+x + "&y="+y);
436
       if (status.getExceptionFormat() != null) {
437
            req.append("&EXCEPTIONS=" + status.getExceptionFormat());
438
        } else {
439
            req.append("&EXCEPTIONS=XML");
440
        }
441
                return req.toString().replaceAll(" ", "%20");
442
    }    
443

    
444
    /**
445
     * Builds the GetMapRequest according to the OGC WMS Specifications
446
     * @throws MalformedURLException 
447
     */
448
    private URLRequest buildMapRequest(WMSStatus status) throws MalformedURLException
449
    { 
450
                URLRequest req = new URLRequest();
451
                StringBuffer u = new StringBuffer();
452
                String onlineResource = null;
453
                
454
                if (status.getOnlineResource() == null)
455
                        onlineResource = getHost();
456
                else 
457
                        onlineResource = status.getOnlineResource();
458
                u.append(onlineResource +  getSymbol(onlineResource) + "REQUEST=GetMap&SERVICE=WMS&VERSION=").append(getVersion()).append("&");
459
                u.append(getPartialQuery(status));
460
        if (status.getExceptionFormat() != null) {
461
            u.append("&EXCEPTIONS=" + status.getExceptionFormat());
462
        } else {
463
            u.append("&EXCEPTIONS=XML");
464
        }
465
        URL url = new URL(u.toString());
466
                
467
        req.setHost(url.getHost());
468
                req.setRequestType(URLRequest.GET);
469
                req.setProtocol(URLRequest.HTTP);
470
                req.setFile(url.getFile());
471
                int myPort = url.getPort();
472
                if (myPort != -1 && myPort != 80 )
473
                        req.setPort(myPort);
474
                
475
                return req;
476
    }
477
    
478
    /**
479
     * Just for not repeat code. Gets the correct separator according to the server URL
480
     * @param h
481
     * @return
482
     */
483
    private static String getSymbol(String h) {
484
        String symbol;
485
        if (h.indexOf("?")==-1) 
486
            symbol = "?";
487
        else if (h.indexOf("?")!=h.length()-1)
488
            symbol = "&";
489
        else
490
            symbol = "";
491
        return symbol;
492
    }
493

    
494
    /**
495
     * Gets the part of the OGC request that share GetMap and GetFeatureInfo
496
     * @return String request
497
     */
498
    public String getPartialQuery(WMSStatus status)
499
    {            
500
        StringBuffer req = new StringBuffer();
501
        req.append("LAYERS=" + Utilities.Vector2CS(status.getLayerNames()))
502
           .append("&SRS=" + status.getSrs())
503
           .append("&BBOX=" + status.getExtent().getMinX()+ "," )
504
           .append(status.getExtent().getMinY()+ ",")
505
           .append(status.getExtent().getMaxX()+ ",")
506
           .append(status.getExtent().getMaxY())
507
           .append("&WIDTH=" + status.getWidth())
508
           .append("&HEIGHT=" + status.getHeight())
509
           .append("&FORMAT=" + status.getFormat())
510
           .append("&STYLES=");
511
        Vector v = status.getStyles();
512
        if (v!=null && v.size()>0)
513
                req.append(Utilities.Vector2CS(v)); 
514
        v = status.getDimensions();
515
        if (v!=null && v.size()>0)
516
            req.append("&" + Utilities.Vector2URLParamString(v));
517
        if (status.getTransparency()) {
518
            req.append("&TRANSPARENT=TRUE");
519
        }
520
        return req.toString();
521
    }
522

    
523
    
524
    
525
    public void close() {        
526
        // your code here
527
    } 
528
    
529
    /**
530
     * Inner class that represents the description of the WMS metadata.
531
     * The first part of the capabilities will return the service information
532
     * from the WMS, this class will hold this information. 
533
     * 
534
     */
535
    public class ServiceInformation {
536

    
537
        public String online_resource = null;
538
        /*public String map_online_resource = null;
539
        public String feature_online_resource = null;*/
540
        public String version;
541
        public String name;
542
        public String scope;
543
        public String title;
544
        public String abstr;
545
        public String keywords;
546
        public String fees;
547
        public String operationsInfo;
548
        public String personname;
549
        public String organization;
550
        public String function;
551
        public String addresstype;
552
        public String address;
553
        public String place;
554
        public String province;
555
        public String postcode;
556
        public String country;
557
        public String phone;
558
        public String fax;
559
        public String email;
560
        public Vector formats;
561
        public HashMap operations; // operations that WMS supports
562
        
563
        public ServiceInformation()
564
        {          
565
            version = new String();
566
            name = new String();
567
            scope = new String();
568
            title = new String();
569
            abstr = new String();
570
            keywords = new String();
571
            fees = new String();
572
            operationsInfo = new String();
573
            personname = new String();
574
            organization = new String();
575
            function = new String();
576
            addresstype = new String();
577
            address = new String();
578
            place = new String();
579
            province = new String();
580
            postcode = new String();
581
            country = new String();
582
            phone = new String();
583
            fax = new String();
584
            email = new String();
585
            formats = new Vector();               
586
            operations = new HashMap();            
587
        }
588
        public boolean isQueryable()
589
        {
590
                if (operations.keySet().contains( CapabilitiesTags.GETFEATUREINFO ))
591
                        return true;
592
                else
593
                        return false;
594
        }
595
     }
596

    
597
        public void setListener(WMSEventListener listener) {
598
                if (listener!=null)
599
                        this.theListener = listener;
600
        }
601

    
602
        public void cancel(int opCode) {
603
                URLRequest myUrlReq;
604
                RetrieveListener myListener;
605
                switch (opCode) {
606
                case WMSClient.GET_CAPABILITIES:
607
                        myUrlReq = capabilitiesRequest;
608
                        myListener = getCapabilitiesListener;
609
                        break;
610
                case WMSClient.GET_MAP:
611
                        myUrlReq = mapRequest;
612
                        myListener = getMapListener;
613
                        break;
614
                case WMSClient.GET_FEATURE_INFO:
615
                        myUrlReq = featureInfo;
616
                        myListener = getFeatureInfoListener;
617
                        break;
618
                default:
619
                        System.err.println("[RemoteClients:WMSProtocolHandler] cancelling an unknown operation");
620
                        return;
621
                }
622
                myUrlReq.removeRetrieveListener(myListener);
623
        }   
624
 }