Statistics
| Revision:

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

History | View | Annotate | Download (16.2 KB)

1 3323 ldiaz
2
package org.gvsig.remoteClient.wms;
3
4 3798 ldiaz
import java.io.ByteArrayInputStream;
5 3323 ldiaz
import java.io.File;
6 3377 ldiaz
import java.io.IOException;
7 3323 ldiaz
import java.io.InputStream;
8 3798 ldiaz
import java.io.InputStreamReader;
9
import java.io.Reader;
10
import java.io.StringReader;
11 3323 ldiaz
import java.net.URL;
12 3776 jaume
import java.net.URLConnection;
13 3798 ldiaz
import java.util.ArrayList;
14 3323 ldiaz
import java.util.TreeMap;
15
import java.util.Vector;
16 3776 jaume
17 3516 jaume
import org.gvsig.remoteClient.exceptions.ServerErrorException;
18
import org.gvsig.remoteClient.exceptions.WMSException;
19 3798 ldiaz
import org.gvsig.remoteClient.utils.CapabilitiesTags;
20
import org.gvsig.remoteClient.utils.ExceptionTags;
21 3351 ldiaz
import org.gvsig.remoteClient.utils.Utilities;
22 3532 ldiaz
import org.kxml2.io.KXmlParser;
23 3798 ldiaz
import org.xmlpull.v1.XmlPullParserException;
24 3323 ldiaz
25 3798 ldiaz
import com.iver.andami.PluginServices;
26
27 3323 ldiaz
/**
28
 * <p> Abstract class that represents handlers to comunicate via WMS protocol.
29
 * </p>
30
 *
31
 */
32
public abstract class WMSProtocolHandler {
33 3687 ldiaz
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 3483 jaume
        /**
41
         * procotol handler name
42
         */
43 3323 ldiaz
    protected String name;
44 3483 jaume
    /**
45
     * protocol handler version
46
     */
47 3323 ldiaz
    protected String version;
48 3483 jaume
    /**
49
     * host of the WMS to connect
50
     */
51 3323 ldiaz
    protected String host;
52 3483 jaume
    /**
53
     *  port number of the comunication channel of the WMS to connect
54
     */
55 3323 ldiaz
    protected String port;
56 3483 jaume
    /**
57
     * WMS metadata
58
     */
59 3323 ldiaz
    protected ServiceInformation serviceInfo;
60
    public TreeMap layers;
61 3483 jaume
    public WMSLayer rootLayer;
62 3341 ldiaz
    public Vector srs;
63
64 3323 ldiaz
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 3516 jaume
    public abstract void parse(File f) ;
77 3323 ldiaz
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 3516 jaume
    public byte[] getMap(WMSStatus status) throws ServerErrorException, WMSException
113 3351 ldiaz
    {
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 3776 jaume
                        URLConnection conn = request.openConnection();
121
                        System.out.println(request.toString());
122
            String type = conn.getContentType();
123
124
125 3516 jaume
                    byte[] imageBytes = null;
126 3377 ldiaz
                    byte[] buffer = new byte[1024*256];
127 3776 jaume
            InputStream is = conn.getInputStream();
128 3377 ldiaz
                    int readed = 0;
129
130
                    for (int i = is.read(buffer); i>0; i = is.read(buffer)){
131 3483 jaume
                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
132 3377 ldiaz
                            byte[] buffered = new byte[readed+i];
133
                            for (int j = 0; j < buffered.length; j++) {
134
                                    if (j<readed){
135 3483 jaume
                        // puts the previously downloaded bytes into the image buffer
136 3377 ldiaz
                                            buffered[j] = imageBytes[j];
137
                                    }
138
                                    else {
139 3483 jaume
                        // appends the recently downloaded bytes to the image buffer.
140 3377 ldiaz
                                            buffered[j] = buffer[j-readed];
141
                                    }
142
                                }
143
                            imageBytes = (byte[]) buffered.clone();
144
                            readed += i;
145
146
                    }
147 3776 jaume
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 3516 jaume
                        if (Utilities.isTextData(imageBytes)){
156
                String exceptionMessage = parseException(imageBytes);
157
                if (exceptionMessage!=null)
158
                    throw new WMSException(exceptionMessage);
159
                throw new ServerErrorException();
160
            }
161 3377 ldiaz
                        return imageBytes;
162
163 3351 ldiaz
                }
164 3516 jaume
                catch(IOException e)
165 3351 ldiaz
                {
166 3405 jaume
                        e.printStackTrace();
167 3516 jaume
            throw new ServerErrorException();
168 3351 ldiaz
                }
169 3323 ldiaz
    }
170
171 3798 ldiaz
    /* (non-Javadoc)
172
     * @see org.gvsig.remoteClient.wms.WMSProtocolHandler#parseException(byte[])
173 3516 jaume
     */
174 3798 ldiaz
    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 3516 jaume
222
    /**
223 3323 ldiaz
         * <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 3345 ldiaz
            URL request = null;
230 3323 ldiaz
                try
231
                {
232 3345 ldiaz
                        request = new URL(buildCapabilitiesRequest());
233 3323 ldiaz
                }
234
                catch(Exception e)
235
                {
236 3377 ldiaz
                        e.printStackTrace();
237 3323 ldiaz
                }
238 3377 ldiaz
                try
239
                {
240 3773 ldiaz
                File f = com.iver.andami.Utilities.downloadFile(request,"wms_capabilities.xml");
241 3323 ldiaz
            parse(f);
242 3776 jaume
            } catch(Exception e)
243 3377 ldiaz
                {
244
                        //TODO
245
                        e.printStackTrace();
246
                }
247 3323 ldiaz
    }
248
249 3776 jaume
    /**
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 3377 ldiaz
    public String getFeatureInfo(WMSStatus status, int x, int y, int featureCount)
254 3323 ldiaz
    {
255 3351 ldiaz
            URL request = null;
256 3798 ldiaz
            StringBuffer output = new StringBuffer();
257
            String outputFormat = new String();
258
            String ServiceException = "ServiceExceptionReport";
259 3351 ldiaz
                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 3798 ldiaz
265
                        //TODO:
266
                        //see which output format is being requested.
267 3351 ldiaz
                }
268
                catch(Exception e)
269
                {
270 3522 ldiaz
                        e.printStackTrace();
271 3351 ldiaz
                }
272
273
            try
274
            {
275 3798 ldiaz
                    StringBuffer sb = new StringBuffer();
276
                    sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
277
278 3351 ldiaz
                    System.out.println(request.toString());
279 3798 ldiaz
                    //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 3351 ldiaz
285 3798 ldiaz
                    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 3532 ldiaz
                                         {
304 3798 ldiaz
                                                 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 3532 ldiaz
                                                        break;
318 3798 ldiaz
                                                 }
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 3351 ldiaz
            catch(Exception e)
332
            {
333 3483 jaume
                    e.printStackTrace();
334 3798 ldiaz
            return "";
335 3351 ldiaz
            }
336 3323 ldiaz
    }
337 3687 ldiaz
338 3345 ldiaz
    /**
339
     * Builds the GetCapabilitiesRequest according to the OGC WMS Specifications
340 3687 ldiaz
     * without a VERSION, to get the highest version than a WMS supports.
341 3345 ldiaz
     */
342 3687 ldiaz
    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 3345 ldiaz
    private String buildCapabilitiesRequest()
359
    {
360
                String req = new String();
361 3377 ldiaz
                String host = getHost();
362 3604 jaume
363 3655 jaume
        String symbol = getSymbol(host);
364 3604 jaume
        req = req + getHost() + symbol + "REQUEST=GetCapabilities&SERVICE=WMS&";
365 3345 ldiaz
                req = req + "VERSION=" + getVersion();
366
                req += ("&EXCEPTIONS=XML");
367
                return req;
368
    }
369
370
    /**
371 3351 ldiaz
     * 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 3604 jaume
377 3655 jaume
        String symbol = getSymbol(host);
378 3604 jaume
379 3522 ldiaz
                req = req + getHost() + symbol + "REQUEST=GetFeatureInfo&SERVICE=WMS&";
380 3351 ldiaz
                req = req + "QUERY_LAYERS="+Utilities.Vector2CS(status.getLayerNames());
381
                req = req + "&VERSION=" + getVersion() + "&";
382 3532 ldiaz
                req = req + "INFO_FORMAT=application/vnd.ogc.gml&";
383 3351 ldiaz
                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 3655 jaume
393 3351 ldiaz
    /**
394 3345 ldiaz
     * Builds the GetMapRequest according to the OGC WMS Specifications
395
     */
396
    private String buildMapRequest(WMSStatus status)
397 3522 ldiaz
    {
398 3345 ldiaz
                String req = new String();
399 3604 jaume
400 3655 jaume
                String symbol = getSymbol(host);
401 3522 ldiaz
                req = req + getHost() + symbol + "REQUEST=GetMap&SERVICE=WMS&";
402 3345 ldiaz
                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 3655 jaume
412
    /**
413
     * Just for not repeat code. Gets the correct separator according to the server URL
414
     * @param h
415
     * @return
416
     */
417 3687 ldiaz
    private static String getSymbol(String h) {
418 3655 jaume
        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 3345 ldiaz
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 3351 ldiaz
    {
434 3776 jaume
        String req = "LAYERS=" + Utilities.Vector2CS(status.getLayerNames()) +
435
                    "&SRS=" + status.getSrs() +
436 3572 jaume
                    "&BBOX=" + status.getExtent().getMinX()+ "," +
437 3351 ldiaz
                                    status.getExtent().getMinY()+ "," +
438
                                    status.getExtent().getMaxX()+ "," +
439
                                    status.getExtent().getMaxY() +
440 3572 jaume
                    "&WIDTH=" + status.getWidth() +
441 3776 jaume
                    "&HEIGHT=" + status.getHeight() + "&FORMAT=" + status.getFormat();
442 3345 ldiaz
443 3776 jaume
444
        Vector v = status.getStyles();
445 3777 jaume
        if (v!=null && v.size()>0)
446 3776 jaume
                req += "&STYLES=" + Utilities.Vector2CS(v);
447
        v = status.getDimensions();
448 3777 jaume
        if (v!=null && v.size()>0)
449 3776 jaume
            req += "&" + Utilities.Vector2URLParamString(v);
450 3592 jaume
        if (status.getTransparency()) {
451
            req += "&TRANSPARENT=TRUE";
452
        }
453 3776 jaume
454 3345 ldiaz
//
455
//        if (status.getBGColor() != null) {
456
//            req += ("&COLOR=" + status.getBGColor());
457
//        }
458
//
459
        return req.replaceAll(" ", "%20");
460
    }
461
462
463
464 3323 ldiaz
    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 3687 ldiaz
        public Vector operations; // operations that WMS supports
499 3323 ldiaz
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 3798 ldiaz
            operations = new Vector();
525 3323 ldiaz
        }
526 3798 ldiaz
        public boolean isQueryable()
527
        {
528
                if (operations.contains( CapabilitiesTags.GETFEATUREINFO ))
529
                        return true;
530
                else
531
                        return false;
532
        }
533 3377 ldiaz
     }
534 3323 ldiaz
 }