Statistics
| Revision:

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

History | View | Annotate | Download (19.6 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
                                
109
                                File f = new File(event.getFileName());
110
                                if (Utilities.isTextFile(f)) {
111
                                    FileInputStream fis;
112
                                        try {
113
                                                fis = new FileInputStream(f);
114
                                        FileChannel fc = fis.getChannel();
115
                                    byte[] data = new byte[(int)fc.size()];   // fc.size returns the size of the file which backs the channel
116
                                    ByteBuffer bb = ByteBuffer.wrap(data);
117
                                    fc.read(bb);
118
                                                                
119
                                    WMSException wmsEx = null;
120
                               
121
                            String exceptionMessage = parseException(data);
122
                        if (exceptionMessage==null)
123
                        {
124
                                 String error = new String(data);
125
                                int pos = error.indexOf("<?xml");
126
                                if (pos!= -1)
127
                                {
128
                                        String xml = error.substring(pos,error.length());
129
                                        exceptionMessage = parseException(xml.getBytes());
130
                                }               
131
                            if (exceptionMessage == null)
132
                                    exceptionMessage = new String(data);
133
                                
134
                        }
135
                             wmsEx = new WMSException(exceptionMessage);
136
                            wmsEx.setWMSMessage(new String(data));
137
                            
138
                            // Since it is an error file, It must be deleted from the cache
139
                            RequestManager.getInstance().removeURLRequest(mapRequest);
140
                        } catch (FileNotFoundException e) {
141
                                                // TODO Auto-generated catch block
142
                                                e.printStackTrace();
143
                                        } catch (IOException e) {
144
                                                // TODO Auto-generated catch block
145
                                                e.printStackTrace();
146
                                        }
147
                                    
148
                    }        
149
                        }
150
                }
151
            
152
    } ,
153
    getFeatureInfoListener = new RetrieveListener() {
154
                public void transferEventReceived(RetrieveEvent event) {
155
                        int type = event.getType();
156
                        
157
                }};
158
    /**
159
     * parses the data retrieved by the WMS in XML format. 
160
     * It will be mostly the WMS Capabilities, but the implementation
161
     * will be placed in the handler implementing certain version of the protocol.
162
     * 
163
     */
164
    public abstract void parse(File f) ;
165

    
166
    public String getName() {        
167
            return name;
168
    } 
169

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

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

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

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

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

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

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

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

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

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

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

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

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