svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.remoteclient / src / main / java / org / gvsig / remoteclient / wcs / WCSProtocolHandler.java @ 40559
History | View | Annotate | Download (12 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | 40559 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * of the License, or (at your option) any later version.
|
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | 40559 | jjdelcerro | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 | * MA 02110-1301, USA.
|
||
20 | 40435 | jjdelcerro | *
|
21 | 40559 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | package org.gvsig.remoteclient.wcs; |
||
25 | |||
26 | import java.io.ByteArrayInputStream; |
||
27 | import java.io.File; |
||
28 | import java.io.IOException; |
||
29 | import java.net.MalformedURLException; |
||
30 | import java.net.URL; |
||
31 | import java.util.ArrayList; |
||
32 | import java.util.Hashtable; |
||
33 | import java.util.StringTokenizer; |
||
34 | |||
35 | import org.gvsig.compat.CompatLocator; |
||
36 | import org.gvsig.compat.lang.StringUtils; |
||
37 | import org.gvsig.compat.net.ICancellable; |
||
38 | import org.gvsig.remoteclient.exceptions.ServerErrorException; |
||
39 | import org.gvsig.remoteclient.exceptions.WCSException; |
||
40 | import org.gvsig.remoteclient.exceptions.WMSException; |
||
41 | import org.gvsig.remoteclient.ogc.OGCProtocolHandler; |
||
42 | import org.gvsig.remoteclient.ogc.OGCServiceInformation; |
||
43 | import org.gvsig.remoteclient.utils.CapabilitiesTags; |
||
44 | import org.gvsig.remoteclient.utils.ExceptionTags; |
||
45 | import org.gvsig.remoteclient.utils.Utilities; |
||
46 | import org.gvsig.remoteclient.wcs.request.WCSDescribeCoverageRequest; |
||
47 | import org.gvsig.remoteclient.wcs.request.WCSGetCoverageRequest; |
||
48 | import org.kxml2.io.KXmlParser; |
||
49 | import org.xmlpull.v1.XmlPullParserException; |
||
50 | /**
|
||
51 | *
|
||
52 | * @author jaume
|
||
53 | *
|
||
54 | */
|
||
55 | public abstract class WCSProtocolHandler extends OGCProtocolHandler { |
||
56 | /**
|
||
57 | * Encoding used to parse different xml documents.
|
||
58 | */
|
||
59 | protected String encoding = "UTF-8"; |
||
60 | protected Hashtable layerPool = new Hashtable(); |
||
61 | |||
62 | /**
|
||
63 | * WCS metadata
|
||
64 | */
|
||
65 | protected WCSServiceInformation serviceInfo = new WCSServiceInformation(); |
||
66 | |||
67 | private static final StringUtils stringUtils = CompatLocator.getStringUtils(); |
||
68 | |||
69 | /*
|
||
70 | * (non-Javadoc)
|
||
71 | * @see org.gvsig.remoteClient.OGCProtocolHandler#setHost(java.lang.String)
|
||
72 | */
|
||
73 | public void setHost(String host) { |
||
74 | try {
|
||
75 | // Validates the URL if doesn't produces an exception
|
||
76 | new URL(host); |
||
77 | |||
78 | int index = host.indexOf("?"); |
||
79 | |||
80 | if (index == -1) |
||
81 | super.setHost(host);
|
||
82 | else
|
||
83 | super.setHost(host.substring(0, index)); |
||
84 | } |
||
85 | catch (MalformedURLException m) { |
||
86 | // Bad URL -> hold it
|
||
87 | super.setHost(host);
|
||
88 | } |
||
89 | } |
||
90 | |||
91 | /**
|
||
92 | * <p>
|
||
93 | * Builds a GetCapabilities request that is sent to the WCS
|
||
94 | * the response will be parse to extract the data needed by the
|
||
95 | * WCS client.
|
||
96 | * </p>
|
||
97 | * @param override, if true the cache is ignored
|
||
98 | */
|
||
99 | public void getCapabilities(WCSStatus status, boolean override, ICancellable cancel) { |
||
100 | URL request = null; |
||
101 | try {
|
||
102 | request = new URL(buildCapabilitiesRequest(status)); |
||
103 | } |
||
104 | catch(Exception e) { |
||
105 | e.printStackTrace(); |
||
106 | } |
||
107 | try {
|
||
108 | if (override)
|
||
109 | downloader.removeURL(request); |
||
110 | File f = downloader.downloadFile(request,"wcs_capabilities.xml", cancel); |
||
111 | if (f!=null) |
||
112 | parseCapabilities(f); |
||
113 | } catch(Exception e) { |
||
114 | e.printStackTrace(); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | /**
|
||
119 | * Builds a complete URL-string that can be used to send a GetCapabilities request.
|
||
120 | * @return String
|
||
121 | */
|
||
122 | private String buildCapabilitiesRequest(WCSStatus status) { |
||
123 | StringBuffer req = new StringBuffer(); |
||
124 | String symbol = null; |
||
125 | |||
126 | String onlineResource;
|
||
127 | if (status == null || status.getOnlineResource() == null) |
||
128 | onlineResource = getHost(); |
||
129 | else
|
||
130 | onlineResource = status.getOnlineResource(); |
||
131 | symbol = getSymbol(onlineResource); |
||
132 | |||
133 | req.append(onlineResource).append(symbol).append("REQUEST=GetCapabilities&SERVICE=WCS&");
|
||
134 | req.append("VERSION=").append(getVersion()).append("&EXCEPTIONS=XML"); |
||
135 | return req.toString();
|
||
136 | } |
||
137 | |||
138 | |||
139 | |||
140 | /**
|
||
141 | * parses the data retrieved by the DescribeCoverage XML document
|
||
142 | */
|
||
143 | public abstract boolean parseDescribeCoverage(File f); |
||
144 | |||
145 | /**
|
||
146 | * Send a DescribeCoverage request using the settings passed in the status argument.
|
||
147 | * If status is null, then default settings are used.
|
||
148 | * @param override
|
||
149 | * @return String
|
||
150 | */
|
||
151 | public void describeCoverage(WCSStatus status, boolean override, ICancellable cancel) { |
||
152 | try {
|
||
153 | WCSDescribeCoverageRequest request = createDescribeCoverageRequest(status); |
||
154 | File f = request.sendRequest(cancel);
|
||
155 | if (f!=null) |
||
156 | parseDescribeCoverage(f); |
||
157 | } catch(Exception e) { |
||
158 | e.printStackTrace(); |
||
159 | } |
||
160 | } |
||
161 | |||
162 | /**
|
||
163 | * Send a GetCoverage request using the settings passed in the status.
|
||
164 | * @return String
|
||
165 | */
|
||
166 | public File getCoverage(WCSStatus status, ICancellable cancel) throws ServerErrorException, WCSException { |
||
167 | try
|
||
168 | { |
||
169 | //TODO:
|
||
170 | //pass this buildXXXRequest to the WCSProtocolHandlerXXX: The request can depend on the WCS version.
|
||
171 | WCSGetCoverageRequest request = createGetCoverageRequest(status); |
||
172 | File f = request.sendRequest(cancel);
|
||
173 | |||
174 | if (f!=null && Utilities.isTextFile(f)) { |
||
175 | byte[] data = fileToBytes(f); |
||
176 | |||
177 | WCSException wcsEx = null;
|
||
178 | |||
179 | String exceptionMessage = parseException(data);
|
||
180 | if (exceptionMessage==null) |
||
181 | { |
||
182 | String error = new String(data); |
||
183 | int pos = error.indexOf("<?xml"); |
||
184 | if (pos!= -1) |
||
185 | { |
||
186 | String xml = error.substring(pos,error.length());
|
||
187 | exceptionMessage = parseException(xml.getBytes()); |
||
188 | } |
||
189 | if (exceptionMessage == null) |
||
190 | exceptionMessage = new String(data); |
||
191 | |||
192 | } |
||
193 | wcsEx = new WCSException(exceptionMessage);
|
||
194 | wcsEx.setWCSMessage(new String(data)); |
||
195 | |||
196 | // Since it is an error file, It must be deleted from the cache
|
||
197 | downloader.removeURL(request); |
||
198 | throw wcsEx;
|
||
199 | } |
||
200 | return f;
|
||
201 | } |
||
202 | catch(IOException e) |
||
203 | { |
||
204 | e.printStackTrace(); |
||
205 | throw new ServerErrorException(); |
||
206 | } |
||
207 | } |
||
208 | |||
209 | public URL getCoverageURL(WCSStatus status, ICancellable cancel) throws ServerErrorException, WMSException { |
||
210 | try {
|
||
211 | WCSGetCoverageRequest request = createGetCoverageRequest(status); |
||
212 | return request.getURL();
|
||
213 | } catch(IOException e) { |
||
214 | e.printStackTrace(); |
||
215 | throw new ServerErrorException(); |
||
216 | } |
||
217 | } |
||
218 | |||
219 | /**
|
||
220 | * Returns the exception message if the file is a XML instead of a image.
|
||
221 | * @param file3
|
||
222 | * @return
|
||
223 | * @throws IOException
|
||
224 | */
|
||
225 | public String getExceptionMessage(File f) throws IOException { |
||
226 | if (f == null) |
||
227 | return null; |
||
228 | |||
229 | if (Utilities.isTextFile(f)) { |
||
230 | byte[] data = fileToBytes(f); |
||
231 | |||
232 | String exceptionMessage = parseException(data);
|
||
233 | if (exceptionMessage == null) { |
||
234 | String error = new String(data); |
||
235 | int pos = error.indexOf("<?xml"); |
||
236 | if (pos!= -1) { |
||
237 | String xml = error.substring(pos,error.length());
|
||
238 | exceptionMessage = parseException(xml.getBytes()); |
||
239 | } |
||
240 | if (exceptionMessage == null) |
||
241 | exceptionMessage = new String(data); |
||
242 | } |
||
243 | return exceptionMessage;
|
||
244 | } |
||
245 | return null; |
||
246 | } |
||
247 | |||
248 | /**
|
||
249 | * Parses the WCS Exception document.
|
||
250 | * @param bytes, byte[]
|
||
251 | * @return
|
||
252 | */
|
||
253 | private String parseException(byte[] data) { |
||
254 | // TODO: a?? est? fusilat del WMS, comprovar que funciona.
|
||
255 | ArrayList errors = new ArrayList(); |
||
256 | KXmlParser kxmlParser = new KXmlParser();
|
||
257 | boolean end = false; |
||
258 | try
|
||
259 | { |
||
260 | kxmlParser.setInput(new ByteArrayInputStream(data), encoding); |
||
261 | kxmlParser.nextTag(); |
||
262 | int tag;
|
||
263 | if ( kxmlParser.getEventType() != KXmlParser.END_DOCUMENT )
|
||
264 | { |
||
265 | kxmlParser.require(KXmlParser.START_TAG, null, ExceptionTags.EXCEPTION_ROOT);
|
||
266 | tag = kxmlParser.nextTag(); |
||
267 | while(!end)
|
||
268 | { |
||
269 | switch(tag)
|
||
270 | { |
||
271 | case KXmlParser.START_TAG:
|
||
272 | if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION)==0){ |
||
273 | String errorCode = kxmlParser.getAttributeValue("", ExceptionTags.CODE); |
||
274 | errorCode = (errorCode != null) ? "["+errorCode+"] " : ""; |
||
275 | String errorMessage = kxmlParser.nextText();
|
||
276 | errors.add(errorCode+errorMessage); |
||
277 | } |
||
278 | break;
|
||
279 | case KXmlParser.END_TAG:
|
||
280 | if (kxmlParser.getName().compareTo(ExceptionTags.SERVICE_EXCEPTION) == 0 || |
||
281 | kxmlParser.getName().compareTo(ExceptionTags.EXCEPTION_ROOT) == 0)
|
||
282 | end = true;
|
||
283 | break;
|
||
284 | |||
285 | } |
||
286 | if (!end)
|
||
287 | tag = kxmlParser.nextTag(); |
||
288 | } |
||
289 | //kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
|
||
290 | } |
||
291 | } |
||
292 | catch(XmlPullParserException parser_ex){
|
||
293 | parser_ex.printStackTrace(); |
||
294 | } |
||
295 | catch (IOException ioe) { |
||
296 | ioe.printStackTrace(); |
||
297 | } |
||
298 | String message = errors.size()>0? "" : null; |
||
299 | for (int i = 0; i < errors.size(); i++) { |
||
300 | message += (String) errors.get(i)+"\n"; |
||
301 | } |
||
302 | return message;
|
||
303 | } |
||
304 | |||
305 | /**
|
||
306 | * Builds the GetCapabilitiesRequest according to the OGC WCS Specifications
|
||
307 | * without a VERSION, to get the highest version than a WCS supports.
|
||
308 | */
|
||
309 | public static String buildCapabilitiesSuitableVersionRequest(String _host, String _version) { |
||
310 | int index = _host.indexOf('?'); |
||
311 | |||
312 | if (index > -1) { |
||
313 | String host = _host.substring(0, index + 1); |
||
314 | String query = _host.substring(index + 1, _host.length()); |
||
315 | |||
316 | StringTokenizer tokens = new StringTokenizer(query, "&"); |
||
317 | String newQuery = "", token; |
||
318 | |||
319 | // If there is a field or a value with spaces, (and then it's on different tokens) -> unify them
|
||
320 | while (tokens.hasMoreTokens()) {
|
||
321 | token = tokens.nextToken().trim(); |
||
322 | |||
323 | if (token.toUpperCase().compareTo("REQUEST=GETCAPABILITIES") == 0) |
||
324 | continue;
|
||
325 | |||
326 | if (token.toUpperCase().compareTo("SERVICE=WCS") == 0) |
||
327 | continue;
|
||
328 | |||
329 | if ((_version != null) && (_version.length() > 0)) { |
||
330 | if (token.toUpperCase().compareTo("VERSION=" + _version) == 0) |
||
331 | continue;
|
||
332 | } |
||
333 | |||
334 | if (token.toUpperCase().compareTo("EXCEPTIONS=XML") == 0) |
||
335 | continue;
|
||
336 | |||
337 | newQuery += token + "&";
|
||
338 | } |
||
339 | |||
340 | _host = host + newQuery; |
||
341 | } |
||
342 | else {
|
||
343 | _host += "?";
|
||
344 | } |
||
345 | |||
346 | if ((_version != null) && (_version.compareTo("") != 0)) |
||
347 | _host += "REQUEST=GetCapabilities&SERVICE=WCS&VERSION=" + _version + "&EXCEPTIONS=XML"; |
||
348 | else
|
||
349 | _host += "REQUEST=GetCapabilities&SERVICE=WCS&EXCEPTIONS=XML";
|
||
350 | |||
351 | return stringUtils.replaceAll(_host, " ", "%20"); |
||
352 | } |
||
353 | |||
354 | public ArrayList getFormats() { |
||
355 | return new ArrayList(serviceInfo.formats); |
||
356 | } |
||
357 | |||
358 | public Hashtable getLayers() { |
||
359 | return layerPool;
|
||
360 | } |
||
361 | |||
362 | public abstract WCSDescribeCoverageRequest createDescribeCoverageRequest(WCSStatus status); |
||
363 | |||
364 | public abstract WCSGetCoverageRequest createGetCoverageRequest(WCSStatus status); |
||
365 | |||
366 | /* (non-Javadoc)
|
||
367 | * @see org.gvsig.remoteclient.ogc.OGCProtocolHandler#getServiceInformation()
|
||
368 | */
|
||
369 | public OGCServiceInformation getServiceInformation() {
|
||
370 | return serviceInfo;
|
||
371 | } |
||
372 | |||
373 | } |