Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRemoteServices / src / org / gvsig / remoteClient / wms / WMSProtocolHandler.java @ 3798

History | View | Annotate | Download (16.2 KB)

1

    
2
package org.gvsig.remoteClient.wms;
3

    
4
import java.io.ByteArrayInputStream;
5
import java.io.File;
6
import java.io.IOException;
7
import java.io.InputStream;
8
import java.io.InputStreamReader;
9
import java.io.Reader;
10
import java.io.StringReader;
11
import java.net.URL;
12
import java.net.URLConnection;
13
import java.util.ArrayList;
14
import java.util.TreeMap;
15
import java.util.Vector;
16

    
17
import org.gvsig.remoteClient.exceptions.ServerErrorException;
18
import org.gvsig.remoteClient.exceptions.WMSException;
19
import org.gvsig.remoteClient.utils.CapabilitiesTags;
20
import org.gvsig.remoteClient.utils.ExceptionTags;
21
import org.gvsig.remoteClient.utils.Utilities;
22
import org.kxml2.io.KXmlParser;
23
import org.xmlpull.v1.XmlPullParserException;
24

    
25
import com.iver.andami.PluginServices;
26

    
27
/**
28
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.
29
 * </p>
30
 * 
31
 */
32
public abstract class WMSProtocolHandler {
33
        
34
        public static final int GETCAPABILITIES_OPERATION = 0;
35
        public static final int GETMAP_OPERATION = 1;
36
        public static final int GETFEATUREINFO_OPERATION = 2;
37
        public static final int DESCRIBELAYER_OPERATION = 3;
38
        public static final int GETLEGENDGRAPHIC_OPERATION = 4; // this is only for sld-enabled WMS
39
        
40
        /**
41
         * procotol handler name
42
         */
43
    protected String name;
44
    /**
45
     * protocol handler version
46
     */
47
    protected String version;
48
    /**
49
     * host of the WMS to connect
50
     */
51
    protected String host;
52
    /**
53
     *  port number of the comunication channel of the WMS to connect
54
     */
55
    protected String port;    
56
    /**
57
     * WMS metadata
58
     */
59
    protected ServiceInformation serviceInfo;
60
    public TreeMap layers;
61
    public WMSLayer rootLayer;
62
    public Vector srs;
63
    
64

    
65
    // abstract methods to implement by the handlers that implement
66
    // the connection to a WMS with certain version.
67
    //    public abstract String getName();   
68
    //    public abstract String getVersion();
69
    
70
    /**
71
     * parses the data retrieved by the WMS in XML format. 
72
     * It will be mostly the WMS Capabilities, but the implementation
73
     * will be placed in the handler implementing certain version of the protocol.
74
     * 
75
     */
76
    public abstract void parse(File f) ;
77

    
78
    public String getName() {        
79
            return name;
80
    } 
81

    
82
    public String getVersion() {        
83
            return version;
84
    }    
85
    
86
    public ServiceInformation getServiceInformation() {        
87
        return serviceInfo;
88
    }  
89
    public String getHost ()
90
    {
91
            return host;
92
    }
93
    public void setHost(String _host)
94
    {
95
            host = _host;
96
    }
97
    public String getPort()
98
    {
99
            return port;
100
    }
101
    public void setPort(String _port)
102
    {
103
            port = _port;
104
    }
105

    
106
    /**
107
     * <p>Builds a GetMap request that is sent to the WMS
108
     * the response (image) will be redirect to the
109
     * WMS client</p>
110
     */
111
    
112
    public byte[] getMap(WMSStatus status) throws ServerErrorException, WMSException
113
    {        
114
            URL request = null;
115
                try
116
                {
117
                        //TODO:
118
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
119
                        request = new URL(buildMapRequest(status));
120
                        URLConnection conn = request.openConnection();
121
                        System.out.println(request.toString());
122
            String type = conn.getContentType();
123
            
124
                    
125
                    byte[] imageBytes = null;
126
                    byte[] buffer = new byte[1024*256];
127
            InputStream is = conn.getInputStream();
128
                    int readed = 0;
129
                    
130
                    for (int i = is.read(buffer); i>0; i = is.read(buffer)){
131
                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
132
                            byte[] buffered = new byte[readed+i];
133
                            for (int j = 0; j < buffered.length; j++) {
134
                                    if (j<readed){
135
                        // puts the previously downloaded bytes into the image buffer
136
                                            buffered[j] = imageBytes[j];
137
                                    }
138
                                    else {
139
                        // appends the recently downloaded bytes to the image buffer.
140
                                            buffered[j] = buffer[j-readed];
141
                                    }
142
                                }
143
                            imageBytes = (byte[]) buffered.clone();
144
                            readed += i;
145
                            
146
                    }
147
                    
148
                    if (type !=null && !type.subSequence(0,5).equals("image")) {
149
                    String exceptionMessage = parseException(imageBytes);
150
                if (exceptionMessage!=null)
151
                    throw new WMSException(exceptionMessage);
152
                throw new ServerErrorException();
153
            }
154
            
155
                        if (Utilities.isTextData(imageBytes)){
156
                String exceptionMessage = parseException(imageBytes);
157
                if (exceptionMessage!=null)
158
                    throw new WMSException(exceptionMessage);
159
                throw new ServerErrorException();
160
            }
161
                        return imageBytes;
162
                    
163
                }
164
                catch(IOException e)
165
                {
166
                        e.printStackTrace();
167
            throw new ServerErrorException();
168
                }
169
    } 
170

    
171
    /* (non-Javadoc)
172
     * @see org.gvsig.remoteClient.wms.WMSProtocolHandler#parseException(byte[])
173
     */
174
    protected String parseException(byte[] data) {
175
        ArrayList errors = new ArrayList();
176
        KXmlParser kxmlParser = new KXmlParser();
177
        Reader reader = new InputStreamReader(new ByteArrayInputStream(data));
178
        try
179
        {
180
            kxmlParser.setInput(reader);        
181
            kxmlParser.nextTag();
182
            int tag;
183
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT ) 
184
            { 
185
                kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);             
186
                tag = kxmlParser.nextTag();
187
                 while(tag != KXmlParser.END_DOCUMENT)
188
                 {
189
                     switch(tag)
190
                     {
191
                        case KXmlParser.START_TAG:
192
                            if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){
193
                                String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE);
194
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
195
                                String errorMessage = kxmlParser.nextText();
196
                                errors.add(errorCode+errorMessage);
197
                            }
198
                            break;
199
                        case KXmlParser.END_TAG:                            
200
                            break;
201
                        
202
                     }
203
                     tag = kxmlParser.nextTag();
204
                 }
205
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
206
            }
207
        }
208
        catch(XmlPullParserException parser_ex){
209
            System.out.println(parser_ex.getMessage());
210
            parser_ex.printStackTrace();
211
        }
212
        catch (IOException ioe) {           
213
            ioe.printStackTrace();            
214
        }
215
        String message = errors.size()>0? "" : null;
216
        for (int i = 0; i < errors.size(); i++) {
217
            message += (String) errors.get(i)+"\n";
218
        }
219
        return message;
220
    }
221

    
222
    /**
223
         * <p>Builds a GetCapabilities request that is sent to the WMS
224
         * the response will be parse to extract the data needed by the
225
         * WMS client</p>
226
         */
227
    public void getCapabilities()
228
    {                
229
            URL request = null;
230
                try
231
                {
232
                        request = new URL(buildCapabilitiesRequest());
233
                }
234
                catch(Exception e)
235
                {
236
                        e.printStackTrace();
237
                }
238
                try
239
                {
240
                File f = com.iver.andami.Utilities.downloadFile(request,"wms_capabilities.xml");
241
            parse(f);
242
            } catch(Exception e)
243
                {
244
                        //TODO
245
                        e.printStackTrace();
246
                }
247
    }
248

    
249
    /**
250
     * <p>It will send a GetFeatureInfo request to the WMS
251
     * Parsing the response and redirecting the info to the WMS client</p>
252
     */
253
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount)
254
    {
255
            URL request = null;
256
            StringBuffer output = new StringBuffer();
257
            String outputFormat = new String();
258
            String ServiceException = "ServiceExceptionReport";
259
                try
260
                {
261
                        //TODO:
262
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
263
                        request = new URL(buildGetFeatureInfoRequest(status, x, y));
264
                        
265
                        //TODO:
266
                        //see which output format is being requested.                                         
267
                }
268
                catch(Exception e)
269
                {
270
                        e.printStackTrace();
271
                }
272
                
273
            try
274
            {            
275
                    StringBuffer sb = new StringBuffer();
276
                    sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
277
                    
278
                    System.out.println(request.toString());
279
                    //File f = new File("featureInfo.xml");
280
                    //DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));           
281
                    byte[] buffer = new byte[1024*256];                    
282
                    InputStream is = request.openStream();                    
283
                    outputFormat = request.openConnection().getContentType();
284
                    
285
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1))
286
                    {
287
                            for (int i = is.read(buffer); i>0; i = is.read(buffer)){
288
                                    //dos.write(buffer, 0, i);
289
                                    output.append(buffer);                            
290
                            }
291
                            //dos.close();
292
                            is.close();
293
                            
294
                            int tag;
295
                            KXmlParser kxmlParser = null;
296
                            kxmlParser = new KXmlParser();            
297
                            //kxmlParser.setInput(new FileReader(f));
298
                            kxmlParser.setInput(new StringReader(output.toString()));
299
                                tag = kxmlParser.nextTag();
300
                            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT ) 
301
                            {                    
302
                                          while(tag != KXmlParser.END_DOCUMENT)
303
                                         {
304
                                                 switch(tag)
305
                                                 {
306
                                                        case KXmlParser.START_TAG:                
307
                                                                if (kxmlParser.getName().compareTo(ServiceException)==0)
308
                                                                        return parseException( output.toString().getBytes());
309
                                                                else                                                                
310
                                                                        sb.append("<" + kxmlParser.getName() + ">\n");
311
                                                                break;
312
                                                        case KXmlParser.END_TAG:        
313
                                                                sb.append("</" + kxmlParser.getName() + ">\n");
314
                                                                break;
315
                                                        case KXmlParser.TEXT:
316
                                                                sb.append(kxmlParser.getText());                                                
317
                                                        break;
318
                                                 }
319
                                             tag = kxmlParser.next();
320
                                     }
321
                            }        
322
                            //System.out.println(sb.toString());
323
                            return sb.toString();
324
                    }
325
                    else
326
                    {
327
                            sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
328
                            return sb.toString();
329
                    }
330
                }
331
            catch(Exception e)
332
            {
333
                    e.printStackTrace();
334
            return "";
335
            }
336
    }
337
    
338
    /**
339
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
340
     * without a VERSION, to get the highest version than a WMS supports.
341
     */
342
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version)
343
    {
344
                String req = new String();                
345
        String symbol = getSymbol(_host);
346
        req = req + _host + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";                
347
        if((_version != null) && (_version.length()>0 ))
348
        {
349
                req += ("&VERSION=" + _version);
350
        }
351
                req += ("&EXCEPTIONS=XML");
352
                return req;           
353
    }
354
    
355
    /**
356
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
357
     */
358
    private String buildCapabilitiesRequest()
359
    {
360
                String req = new String();
361
                String host = getHost();
362

    
363
        String symbol = getSymbol(host);
364
        req = req + getHost() + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
365
                req = req + "VERSION=" + getVersion();
366
                req += ("&EXCEPTIONS=XML");
367
                return req;
368
    }
369

    
370
    /**
371
     * Builds the GetFeatureInfoRequest according to the OGC WMS Specifications
372
     */
373
    private String buildGetFeatureInfoRequest(WMSStatus status, int x, int y)
374
    {
375
                String req = new String();
376

    
377
        String symbol = getSymbol(host);
378
        
379
                req = req + getHost() + symbol + "REQUEST=GetFeatureInfo&SERVICE=WMS&";
380
                req = req + "QUERY_LAYERS="+Utilities.Vector2CS(status.getLayerNames()); 
381
                req = req + "&VERSION=" + getVersion() + "&";
382
                req = req + "INFO_FORMAT=application/vnd.ogc.gml&";
383
                req = req + getPartialQuery(status);
384
                req = req + "&x="+x + "&y="+y;
385
       if (status.getExceptionFormat() != null) {
386
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
387
        } else {
388
            req += ("&EXCEPTIONS=XML");
389
        }
390
                return req;
391
    }    
392

    
393
    /**
394
     * Builds the GetMapRequest according to the OGC WMS Specifications
395
     */
396
    private String buildMapRequest(WMSStatus status)
397
    { 
398
                String req = new String();
399

    
400
                String symbol = getSymbol(host);
401
                req = req + getHost() + symbol + "REQUEST=GetMap&SERVICE=WMS&";
402
                req = req + "VERSION=" + getVersion() + "&";
403
                req = req + getPartialQuery(status);
404
       if (status.getExceptionFormat() != null) {
405
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
406
        } else {
407
            req += ("&EXCEPTIONS=XML");
408
        }
409
                return req;
410
    }
411
    
412
    /**
413
     * Just for not repeat code. Gets the correct separator according to the server URL
414
     * @param h
415
     * @return
416
     */
417
    private static String getSymbol(String h) {
418
        String symbol;
419
        if (h.indexOf("?")==-1) 
420
            symbol = "?";
421
        else if (h.indexOf("?")!=h.length()-1)
422
            symbol = "&";
423
        else
424
            symbol = "";
425
        return symbol;
426
    }
427

    
428
    /**
429
     * Gets the part of the OGC request that share GetMap and GetFeatureInfo
430
     * @return String request
431
     */
432
    public String getPartialQuery(WMSStatus status)
433
    {            
434
        String req = "LAYERS=" + Utilities.Vector2CS(status.getLayerNames()) + 
435
                    "&SRS=" + status.getSrs() +
436
                    "&BBOX=" + status.getExtent().getMinX()+ "," +
437
                                    status.getExtent().getMinY()+ "," +
438
                                    status.getExtent().getMaxX()+ "," +
439
                                    status.getExtent().getMaxY() +
440
                    "&WIDTH=" + status.getWidth() +
441
                    "&HEIGHT=" + status.getHeight() + "&FORMAT=" + status.getFormat();
442

    
443

    
444
        Vector v = status.getStyles();
445
        if (v!=null && v.size()>0)
446
                req += "&STYLES=" + Utilities.Vector2CS(v); 
447
        v = status.getDimensions();
448
        if (v!=null && v.size()>0)
449
            req += "&" + Utilities.Vector2URLParamString(v);
450
        if (status.getTransparency()) {
451
            req += "&TRANSPARENT=TRUE";
452
        }
453

    
454
//
455
//        if (status.getBGColor() != null) {
456
//            req += ("&COLOR=" + status.getBGColor());
457
//        }
458
//
459
        return req.replaceAll(" ", "%20");
460
    }
461

    
462
    
463
    
464
    public void close() {        
465
        // your code here
466
    } 
467
    
468
    /**
469
     * Inner class that represents the description of the WMS metadata.
470
     * The first part of the capabilities will return the service information
471
     * from the WMS, this class will hold this information. 
472
     * 
473
     */
474
    public class ServiceInformation {
475

    
476
        public String online_resource;
477
        public String version;
478
        public String name;
479
        public String scope;
480
        public String title;
481
        public String abstr;
482
        public String keywords;
483
        public String fees;
484
        public String operationsInfo;
485
        public String personname;
486
        public String organization;
487
        public String function;
488
        public String addresstype;
489
        public String address;
490
        public String place;
491
        public String province;
492
        public String postcode;
493
        public String country;
494
        public String phone;
495
        public String fax;
496
        public String email;
497
        public Vector formats;
498
        public Vector operations; // operations that WMS supports
499
        
500
        public ServiceInformation()
501
        {
502
                online_resource = new String();
503
            version = new String();
504
            name = new String();
505
            scope = new String();
506
            title = new String();
507
            abstr = new String();
508
            keywords = new String();
509
            fees = new String();
510
            operationsInfo = new String();
511
            personname = new String();
512
            organization = new String();
513
            function = new String();
514
            addresstype = new String();
515
            address = new String();
516
            place = new String();
517
            province = new String();
518
            postcode = new String();
519
            country = new String();
520
            phone = new String();
521
            fax = new String();
522
            email = new String();
523
            formats = new Vector();               
524
            operations = new Vector();            
525
        }
526
        public boolean isQueryable()
527
        {
528
                if (operations.contains( CapabilitiesTags.GETFEATUREINFO ))
529
                        return true;
530
                else
531
                        return false;
532
        }
533
     }   
534
 }