Statistics
| Revision:

root / trunk / libraries / libRemoteServices / src / org / gvsig / remoteClient / wms / WMSProtocolHandler.java @ 3824

History | View | Annotate | Download (17.6 KB)

1

    
2
package org.gvsig.remoteClient.wms;
3

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

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

    
27
import com.iver.andami.PluginServices;
28

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

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

    
80
    public String getName() {        
81
            return name;
82
    } 
83

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

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

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

    
234
    /**
235
         * <p>Builds a GetCapabilities request that is sent to the WMS
236
         * the response will be parse to extract the data needed by the
237
         * WMS client</p>
238
         */
239
    public void getCapabilities()
240
    {                
241
            URL request = null;
242
                try
243
                {
244
                        request = new URL(buildCapabilitiesRequest());
245
                }
246
                catch(Exception e)
247
                {
248
                        e.printStackTrace();
249
                }
250
                try
251
                {
252
                File f = com.iver.andami.Utilities.downloadFile(request,"wms_capabilities.xml");
253
            parse(f);
254
            } catch(Exception e)
255
                {
256
                        //TODO
257
                        e.printStackTrace();
258
                }
259
    }
260

    
261
    /**
262
     * <p>It will send a GetFeatureInfo request to the WMS
263
     * Parsing the response and redirecting the info to the WMS client</p>
264
     */
265
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount)
266
    {
267
            URL request = null;
268
            StringBuffer output = new StringBuffer();
269
            String outputFormat = new String();
270
            String ServiceException = "ServiceExceptionReport";            
271
            
272
            StringBuffer sb = new StringBuffer();
273
            sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
274
            
275
                try
276
                {
277
                        //TODO:
278
                        //pass this buildXXXRequest to the WMSProtocolHandlerXXX: The request can depend on the WMS version.
279
                        request = new URL(buildGetFeatureInfoRequest(status, x, y));
280
                        
281
                        //TODO:
282
                        //see which output format is being requested.                                         
283
                }
284
                catch(Exception e)
285
                {
286
                        e.printStackTrace();
287
                }
288
                
289
            try
290
            {                                
291
                    System.out.println(request.toString());
292
                    //File f = new File("c:\\featureInfo.xml");
293
                    //DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));           
294
                    byte[] buffer = new byte[1024*256];                    
295
                    DataInputStream is = new DataInputStream(request.openStream());                    
296
                    outputFormat = request.openConnection().getContentType();
297

    
298
                    for (int i = is.read(buffer); i>0; i = is.read(buffer)){
299
                            //dos.write(buffer, 0, i);
300
                            String str = new String(buffer,0,i);
301
                            //System.out.println("str:" + str);
302
                            output.append(str);                    
303
                            //System.out.println("output:" +output.toString());
304
                    }
305
                                
306
                    //dos.close();
307
                    is.close();
308
                    if ( (outputFormat == null) || (outputFormat.indexOf("xml") != -1)
309
                                    ||output.toString().toLowerCase().startsWith("<?xml")
310
                                    ||(outputFormat.indexOf("gml") != -1))
311
                    {
312
                            int tag;
313
                            KXmlParser kxmlParser = null;
314
                            kxmlParser = new KXmlParser();            
315
                            //kxmlParser.setInput(new FileReader(f));
316
                            kxmlParser.setInput(new StringReader(output.toString()));
317
                            
318
                                tag = kxmlParser.nextTag();
319
                            //if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT ) 
320
                            {                    
321
                                          while(tag != KXmlParser.END_DOCUMENT)
322
                                         {
323
                                                 switch(tag)
324
                                                 {
325
                                                        case KXmlParser.START_TAG:                
326
                                                                if (kxmlParser.getName().compareTo(ServiceException)==0)
327
                                                                {
328
                                                                    sb.append("<INFO>").append(parseException( output.toString().getBytes())).append("</INFO>");
329
                                                                    return sb.toString();                                                                        
330
                                                                }
331
                                                                else if (kxmlParser.getName().compareToIgnoreCase("ERROR")==0)
332
                                                                        return output.toString();
333
                                                                else                                                                
334
                                                                        sb.append("<" + kxmlParser.getName() + ">\n");
335
                                                                break;
336
                                                        case KXmlParser.END_TAG:        
337
                                                                sb.append("</" + kxmlParser.getName() + ">\n");
338
                                                                break;
339
                                                        case KXmlParser.TEXT:
340
                                                                sb.append(kxmlParser.getText());                                                
341
                                                        break;
342
                                                 }
343
                                             tag = kxmlParser.next();
344
                                     }
345
                            }        
346
                            //System.out.println(sb.toString());
347
                            return sb.toString();
348
                    }
349
                    else
350
                    {
351
                            sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
352
                            return sb.toString();
353
                    }
354
                }
355
            catch(XmlPullParserException parserEx)
356
            {
357
                    if (output.toString().toLowerCase().indexOf("xml") != -1)
358
                            return output.toString().trim();
359
                    else
360
                    {
361
                               sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
362
                        return sb.toString();
363
                    }
364
            }
365
            catch(Exception e)
366
            {
367
                    e.printStackTrace();
368
                    sb.append("<INFO>").append(PluginServices.getText(this, "info_format_not_supported")).append("</INFO>");
369
                    return sb.toString();
370

    
371
            }
372
    }
373
    
374
    /**
375
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
376
     * without a VERSION, to get the highest version than a WMS supports.
377
     */
378
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version)
379
    {
380
                String req = new String();                
381
        String symbol = getSymbol(_host);
382
        req = req + _host + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";                
383
        if((_version != null) && (_version.length()>0 ))
384
        {
385
                req += ("&VERSION=" + _version);
386
        }
387
                req += ("&EXCEPTIONS=XML");
388
                return req;           
389
    }
390
    
391
    /**
392
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
393
     */
394
    private String buildCapabilitiesRequest()
395
    {
396
                String req = new String();
397
                String host = getHost();
398

    
399
        String symbol = getSymbol(host);
400
        req = req + getHost() + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
401
                req = req + "VERSION=" + getVersion();
402
                req += ("&EXCEPTIONS=XML");
403
                return req;
404
    }
405

    
406
    /**
407
     * Builds the GetFeatureInfoRequest according to the OGC WMS Specifications
408
     */
409
    private String buildGetFeatureInfoRequest(WMSStatus status, int x, int y)
410
    {
411
                String req = new String();
412

    
413
        String symbol = getSymbol(host);
414
        
415
                req = req + getHost() + symbol + "REQUEST=GetFeatureInfo&SERVICE=WMS&";
416
                req = req + "QUERY_LAYERS="+Utilities.Vector2CS(status.getLayerNames()); 
417
                req = req + "&VERSION=" + getVersion() + "&";
418
                req = req + "INFO_FORMAT=application/vnd.ogc.gml&";
419
                req = req + getPartialQuery(status);
420
                req = req + "&x="+x + "&y="+y;
421
       if (status.getExceptionFormat() != null) {
422
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
423
        } else {
424
            req += ("&EXCEPTIONS=XML");
425
        }
426
                return req;
427
    }    
428

    
429
    /**
430
     * Builds the GetMapRequest according to the OGC WMS Specifications
431
     */
432
    private String buildMapRequest(WMSStatus status)
433
    { 
434
                String req = new String();
435

    
436
                String symbol = getSymbol(host);
437
                req = req + getHost() + symbol + "REQUEST=GetMap&SERVICE=WMS&";
438
                req = req + "VERSION=" + getVersion() + "&";
439
                req = req + getPartialQuery(status);
440
       if (status.getExceptionFormat() != null) {
441
            req += ("&EXCEPTIONS=" + status.getExceptionFormat());
442
        } else {
443
            req += ("&EXCEPTIONS=XML");
444
        }
445
                return req;
446
    }
447
    
448
    /**
449
     * Just for not repeat code. Gets the correct separator according to the server URL
450
     * @param h
451
     * @return
452
     */
453
    private static String getSymbol(String h) {
454
        String symbol;
455
        if (h.indexOf("?")==-1) 
456
            symbol = "?";
457
        else if (h.indexOf("?")!=h.length()-1)
458
            symbol = "&";
459
        else
460
            symbol = "";
461
        return symbol;
462
    }
463

    
464
    /**
465
     * Gets the part of the OGC request that share GetMap and GetFeatureInfo
466
     * @return String request
467
     */
468
    public String getPartialQuery(WMSStatus status)
469
    {            
470
        String req = "LAYERS=" + Utilities.Vector2CS(status.getLayerNames()) + 
471
                    "&SRS=" + status.getSrs() +
472
                    "&BBOX=" + status.getExtent().getMinX()+ "," +
473
                                    status.getExtent().getMinY()+ "," +
474
                                    status.getExtent().getMaxX()+ "," +
475
                                    status.getExtent().getMaxY() +
476
                    "&WIDTH=" + status.getWidth() +
477
                    "&HEIGHT=" + status.getHeight() + "&FORMAT=" + status.getFormat();
478

    
479

    
480
        Vector v = status.getStyles();
481
        if (v!=null && v.size()>0)
482
                req += "&STYLES=" + Utilities.Vector2CS(v); 
483
        v = status.getDimensions();
484
        if (v!=null && v.size()>0)
485
            req += "&" + Utilities.Vector2URLParamString(v);
486
        if (status.getTransparency()) {
487
            req += "&TRANSPARENT=TRUE";
488
        }
489

    
490
//
491
//        if (status.getBGColor() != null) {
492
//            req += ("&COLOR=" + status.getBGColor());
493
//        }
494
//
495
        return req.replaceAll(" ", "%20");
496
    }
497

    
498
    
499
    
500
    public void close() {        
501
        // your code here
502
    } 
503
    
504
    /**
505
     * Inner class that represents the description of the WMS metadata.
506
     * The first part of the capabilities will return the service information
507
     * from the WMS, this class will hold this information. 
508
     * 
509
     */
510
    public class ServiceInformation {
511

    
512
        public String online_resource;
513
        public String version;
514
        public String name;
515
        public String scope;
516
        public String title;
517
        public String abstr;
518
        public String keywords;
519
        public String fees;
520
        public String operationsInfo;
521
        public String personname;
522
        public String organization;
523
        public String function;
524
        public String addresstype;
525
        public String address;
526
        public String place;
527
        public String province;
528
        public String postcode;
529
        public String country;
530
        public String phone;
531
        public String fax;
532
        public String email;
533
        public Vector formats;
534
        public Vector operations; // operations that WMS supports
535
        
536
        public ServiceInformation()
537
        {
538
                online_resource = new String();
539
            version = new String();
540
            name = new String();
541
            scope = new String();
542
            title = new String();
543
            abstr = new String();
544
            keywords = new String();
545
            fees = new String();
546
            operationsInfo = new String();
547
            personname = new String();
548
            organization = new String();
549
            function = new String();
550
            addresstype = new String();
551
            address = new String();
552
            place = new String();
553
            province = new String();
554
            postcode = new String();
555
            country = new String();
556
            phone = new String();
557
            fax = new String();
558
            email = new String();
559
            formats = new Vector();               
560
            operations = new Vector();            
561
        }
562
        public boolean isQueryable()
563
        {
564
                if (operations.contains( CapabilitiesTags.GETFEATUREINFO ))
565
                        return true;
566
                else
567
                        return false;
568
        }
569
     }   
570
 }