Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libRemoteServices / src / org / gvsig / remoteclient / wcs / WCSProtocolHandler.java @ 29649

History | View | Annotate | Download (12.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.remoteclient.wcs;
42

    
43
import java.io.ByteArrayInputStream;
44
import java.io.File;
45
import java.io.FileInputStream;
46
import java.io.IOException;
47
import java.net.MalformedURLException;
48
import java.net.URL;
49
import java.nio.ByteBuffer;
50
import java.nio.channels.FileChannel;
51
import java.util.ArrayList;
52
import java.util.HashMap;
53
import java.util.Hashtable;
54
import java.util.StringTokenizer;
55
import java.util.Vector;
56

    
57
import org.gvsig.remoteclient.exceptions.ServerErrorException;
58
import org.gvsig.remoteclient.exceptions.WCSException;
59
import org.gvsig.remoteclient.ogc.OGCProtocolHandler;
60
import org.gvsig.remoteclient.utils.ExceptionTags;
61
import org.gvsig.remoteclient.utils.Utilities;
62
import org.gvsig.remoteclient.wcs.request.WCSDescribeCoverageRequest;
63
import org.gvsig.remoteclient.wcs.request.WCSGetCoverageRequest;
64
import org.gvsig.remoteclient.wms.ICancellable;
65
import org.kxml2.io.KXmlParser;
66
import org.xmlpull.v1.XmlPullParserException;
67
/**
68
 *
69
 * @author jaume
70
 *
71
 */
72
public abstract class WCSProtocolHandler extends OGCProtocolHandler {
73
        /**
74
         * Encoding used to parse different xml documents.
75
         */
76
        protected String encoding = "UTF-8";
77
        protected Hashtable layerPool = new Hashtable();
78

    
79
        /**
80
     * WCS metadata
81
     */
82
    protected ServiceInformation serviceInfo = new ServiceInformation();
83

    
84
        /*
85
         * (non-Javadoc)
86
         * @see org.gvsig.remoteClient.OGCProtocolHandler#setHost(java.lang.String)
87
         */
88
        public void setHost(String host) {
89
                try {
90
                        // Validates the URL if doesn't produces an exception
91
                        new URL(host);
92

    
93
                        int index = host.indexOf("?");
94
                        
95
                        if (index == -1)
96
                                super.setHost(host);
97
                        else
98
                                super.setHost(host.substring(0, index));
99
                }
100
                catch (MalformedURLException m) {
101
                        // Bad URL -> hold it
102
                        super.setHost(host);
103
                }
104
        }
105

    
106
        /**
107
     * <p>
108
     * Builds a GetCapabilities request that is sent to the WCS
109
     * the response will be parse to extract the data needed by the
110
     * WCS client.
111
     * </p>
112
     * @param override, if true the cache is ignored
113
     */
114
    public void getCapabilities(WCSStatus status, boolean override, ICancellable cancel) {
115
           URL request = null;
116
            try {
117
                request = new URL(buildCapabilitiesRequest(status));
118
            }
119
            catch(Exception e) {
120
                e.printStackTrace();
121
            }
122
            try {
123
                    if (override)
124
                                    Utilities.removeURL(request);
125
                    File f =  Utilities.downloadFile(request,"wcs_capabilities.xml", cancel);
126
                    if (f!=null)
127
                            parseCapabilities(f);
128
            } catch(Exception e) {
129
                    e.printStackTrace();
130
            }
131
    }
132

    
133
    /**
134
     * Builds a complete URL-string that can be used to send a GetCapabilities request.
135
     * @return String
136
     */
137
    private String buildCapabilitiesRequest(WCSStatus status) {
138
            StringBuffer req = new StringBuffer();
139
                String symbol = null;
140

    
141
                String onlineResource;
142
                if (status == null || status.getOnlineResource() == null)
143
                        onlineResource = getHost();
144
                else
145
                        onlineResource = status.getOnlineResource();
146
                symbol = getSymbol(onlineResource);
147

    
148
                req.append(onlineResource).append(symbol).append("REQUEST=GetCapabilities&SERVICE=WCS&");
149
                req.append("VERSION=").append(getVersion()).append("&EXCEPTIONS=XML");
150
                return req.toString();
151
    }
152

    
153

    
154

    
155
    /**
156
     * parses the data retrieved by the DescribeCoverage XML document
157
     */
158
    public abstract boolean parseDescribeCoverage(File f);
159

    
160
    /**
161
     * Send a DescribeCoverage request using the settings passed in the status argument.
162
     * If status is null, then default settings are used.
163
     * @param override
164
     * @return String
165
     */
166
    public void describeCoverage(WCSStatus status, boolean override, ICancellable cancel) {
167
       try {
168
               WCSDescribeCoverageRequest request = createDescribeCoverageRequest(status);
169
           File f = request.sendRequest();
170
                if (f!=null)
171
                        parseDescribeCoverage(f);
172
        } catch(Exception e) {
173
                e.printStackTrace();
174
        }
175
    }
176

    
177
    /**
178
     * Send a GetCoverage request using the settings passed in the status.
179
     * @return String
180
     */
181
    public File getCoverage(WCSStatus status, ICancellable cancel) throws ServerErrorException, WCSException {
182
            try
183
                {
184
                        //TODO:
185
                        //pass this buildXXXRequest to the WCSProtocolHandlerXXX: The request can depend on the WCS version.
186
                        WCSGetCoverageRequest request = createGetCoverageRequest(status);
187
            File f = request.sendRequest();
188

    
189
            if (f!=null && Utilities.isTextFile(f)) {
190
                            FileInputStream fis = new FileInputStream(f);
191
                            FileChannel fc = fis.getChannel();
192
                            byte[] data = new byte[(int)fc.size()];   // fc.size returns the size of the file which backs the channel
193
                            ByteBuffer bb = ByteBuffer.wrap(data);
194
                            fc.read(bb);
195

    
196
                            WCSException wcsEx = null;
197

    
198
                    String exceptionMessage = parseException(data);
199
                if (exceptionMessage==null)
200
                {
201
                         String error = new String(data);
202
                        int pos = error.indexOf("<?xml");
203
                        if (pos!= -1)
204
                        {
205
                                String xml = error.substring(pos,error.length());
206
                                exceptionMessage = parseException(xml.getBytes());
207
                        }
208
                    if (exceptionMessage == null)
209
                            exceptionMessage = new String(data);
210

    
211
                }
212
                     wcsEx = new WCSException(exceptionMessage);
213
                    wcsEx.setWCSMessage(new String(data));
214

    
215
                    // Since it is an error file, It must be deleted from the cache
216
                    Utilities.removeURL(request);
217
                throw wcsEx;
218
            }
219
                        return f;
220
                }
221
                catch(IOException e)
222
                {
223
                        e.printStackTrace();
224
            throw new ServerErrorException();
225
                }
226
    }
227

    
228

    
229
    /**
230
     * Parses the WCS Exception document.
231
     * @param bytes, byte[]
232
     * @return
233
     */
234
    private String parseException(byte[] data) {
235
            // TODO: a?? est? fusilat del WMS, comprovar que funciona.
236
            ArrayList errors = new ArrayList();
237
        KXmlParser kxmlParser = new KXmlParser();
238
        try
239
        {
240
            kxmlParser.setInput(new ByteArrayInputStream(data), encoding);
241
            kxmlParser.nextTag();
242
            int tag;
243
            if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
244
            {
245
                kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);
246
                tag = kxmlParser.nextTag();
247
                 while(tag != KXmlParser.END_DOCUMENT)
248
                 {
249
                     switch(tag)
250
                     {
251
                        case KXmlParser.START_TAG:
252
                            if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){
253
                                String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE);
254
                                errorCode = (errorCode != null) ? "["+errorCode+"] " : "";
255
                                String errorMessage = kxmlParser.nextText();
256
                                errors.add(errorCode+errorMessage);
257
                            }
258
                            break;
259
                        case KXmlParser.END_TAG:
260
                            break;
261

    
262
                     }
263
                     tag = kxmlParser.nextTag();
264
                 }
265
                 //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
266
            }
267
        }
268
        catch(XmlPullParserException parser_ex){
269
            parser_ex.printStackTrace();
270
        }
271
        catch (IOException ioe) {
272
            ioe.printStackTrace();
273
        }
274
        String message = errors.size()>0? "" : null;
275
        for (int i = 0; i < errors.size(); i++) {
276
            message += (String) errors.get(i)+"\n";
277
        }
278
        return message;
279
        }        
280

    
281
    /**
282
     * Builds the GetCapabilitiesRequest according to the OGC WCS Specifications
283
     * without a VERSION, to get the highest version than a WCS supports.
284
     */
285
    public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version) {
286
                int index = _host.indexOf('?');
287
                
288
                if (index > -1) {
289
                        String host = _host.substring(0, index + 1);
290
                        String query = _host.substring(index + 1, _host.length());
291
                        
292
                        StringTokenizer tokens = new StringTokenizer(query, "&");
293
                        String newQuery = "", token;
294

    
295
                        // If there is a field or a value with spaces, (and then it's on different tokens) -> unify them
296
                        while (tokens.hasMoreTokens()) {
297
                                token = tokens.nextToken().trim();
298

    
299
                                if (token.toUpperCase().compareTo("REQUEST=GETCAPABILITIES") == 0)
300
                                        continue;
301

    
302
                                if (token.toUpperCase().compareTo("SERVICE=WCS") == 0)
303
                                        continue;
304

    
305
                                if ((_version != null) && (_version.length() > 0)) {
306
                                    if (token.toUpperCase().compareTo("VERSION=" + _version) == 0)
307
                                            continue;
308
                                }
309

    
310
                                if (token.toUpperCase().compareTo("EXCEPTIONS=XML") == 0)
311
                                        continue;
312

    
313
                                newQuery += token + "&";
314
                        }
315

    
316
                _host = host + newQuery;
317
                }
318
                else {
319
                        _host += "?";
320
                }
321

    
322
            if ((_version != null) && (_version.compareTo("") != 0))
323
                    _host += "REQUEST=GetCapabilities&SERVICE=WCS&VERSION=" + _version + "&EXCEPTIONS=XML";
324
            else
325
                    _host += "REQUEST=GetCapabilities&SERVICE=WCS&EXCEPTIONS=XML";
326

    
327
            return _host.replaceAll(" ", "%20");
328
    }
329

    
330
        public ArrayList getFormats() {
331
                return new ArrayList(serviceInfo.formats);
332
        }
333

    
334
    public class ServiceInformation {
335

    
336
        public String online_resource = null;
337
        public String version;
338
        public String name;
339
        public String scope;
340
        public String title;
341
        public String abstr;
342
        public String keywords;
343
        public String fees;
344
        public String operationsInfo;
345
        public String personname;
346
        public String organization;
347
        public String function;
348
        public String addresstype;
349
        public String address;
350
        public String place;
351
        public String province;
352
        public String postcode;
353
        public String country;
354
        public String phone;
355
        public String fax;
356
        public String email;
357
        public Vector formats;
358
        public HashMap operations; // operations that WCS supports
359

    
360
        public ServiceInformation()
361
        {
362
            version = new String();
363
            name = new String();
364
            scope = new String();
365
            title = new String();
366
            abstr = new String();
367
            keywords = new String();
368
            fees = new String();
369
            operationsInfo = new String();
370
            personname = new String();
371
            organization = new String();
372
            function = new String();
373
            addresstype = new String();
374
            address = new String();
375
            place = new String();
376
            province = new String();
377
            postcode = new String();
378
            country = new String();
379
            phone = new String();
380
            fax = new String();
381
            email = new String();
382
            operations = new HashMap();
383
        }
384

    
385
     }
386

    
387
        public Hashtable getLayers() {
388
                return layerPool;
389
        }
390
        
391
        public abstract WCSDescribeCoverageRequest createDescribeCoverageRequest(WCSStatus status);
392
        
393
        public abstract WCSGetCoverageRequest createGetCoverageRequest(WCSStatus status);
394
        
395
        
396
}