001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcwebservices/wms/RemoteWMService.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53115 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044: package org.deegree.ogcwebservices.wms;
045:
046: import static org.deegree.ogcwebservices.OWSUtils.validateHTTPGetBaseURL;
047:
048: import java.io.IOException;
049: import java.io.InputStream;
050: import java.io.StringReader;
051: import java.net.URL;
052: import java.util.HashMap;
053: import java.util.List;
054: import java.util.Properties;
055:
056: import javax.media.jai.JAI;
057: import javax.media.jai.RenderedOp;
058:
059: import org.apache.commons.httpclient.Header;
060: import org.apache.commons.httpclient.HttpClient;
061: import org.apache.commons.httpclient.methods.GetMethod;
062: import org.deegree.datatypes.QualifiedName;
063: import org.deegree.framework.log.ILogger;
064: import org.deegree.framework.log.LoggerFactory;
065: import org.deegree.framework.util.BootLogger;
066: import org.deegree.framework.util.CharsetUtils;
067: import org.deegree.framework.util.MimeTypeMapper;
068: import org.deegree.framework.util.NetWorker;
069: import org.deegree.framework.util.StringTools;
070: import org.deegree.framework.xml.XMLFragment;
071: import org.deegree.i18n.Messages;
072: import org.deegree.ogcwebservices.OGCWebService;
073: import org.deegree.ogcwebservices.OGCWebServiceException;
074: import org.deegree.ogcwebservices.OGCWebServiceRequest;
075: import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
076: import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
077: import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
078: import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
079: import org.deegree.ogcwebservices.wms.operation.DescribeLayer;
080: import org.deegree.ogcwebservices.wms.operation.GetFeatureInfo;
081: import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic;
082: import org.deegree.ogcwebservices.wms.operation.GetMap;
083: import org.deegree.ogcwebservices.wms.operation.GetStyles;
084: import org.deegree.ogcwebservices.wms.operation.PutStyles;
085: import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities;
086: import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
087: import org.deegree.owscommon_new.DCP;
088: import org.deegree.owscommon_new.HTTP;
089: import org.deegree.owscommon_new.Operation;
090: import org.deegree.owscommon_new.OperationsMetadata;
091:
092: import com.sun.media.jai.codec.MemoryCacheSeekableStream;
093:
094: /**
095: * An instance of the class acts as a wrapper to a remote WMS.
096: *
097: * @version $Revision: 10024 $
098: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
099: */
100: public class RemoteWMService implements OGCWebService {
101:
102: private static ILogger LOG = LoggerFactory
103: .getLogger(RemoteWMService.class);
104:
105: private static final String GETCAPABILITIES_NAME = "GetCapabilities";
106:
107: private static final String CAPABILITIES_NAME = "Capabilities";
108:
109: private static final String GETMAP_NAME = "GetMap";
110:
111: private static final String MAP_NAME = "Map";
112:
113: private static final String GETFEATUREINFO_NAME = "GetFeatureInfo";
114:
115: private static final String FEATUREINFO_NAME = "FeatureInfo";
116:
117: private static final String DESCRIBELAYER_NAME = "DescribeLayer";
118:
119: private static final String GETLEGENDGRAPHIC_NAME = "GetLegendGraphic";
120:
121: private static final String GETSTYLES_NAME = "GetStyles";
122:
123: private static final String PUTSTYLES_NAME = "PutStyles";
124:
125: // private static final String UNKNOWN_NAME = "Unknown";
126:
127: protected HashMap<String, URL> addresses = null;
128:
129: protected WMSCapabilities capabilities = null;
130:
131: private static Properties properties;
132: static {
133: if (properties == null) {
134: try {
135: properties = new Properties();
136: InputStream is = RemoteWMService.class
137: .getResourceAsStream("remotewmservice.properties");
138: properties.load(is);
139: is.close();
140: } catch (Exception e) {
141: BootLogger.logError(e.getMessage(), e);
142: }
143: }
144: }
145:
146: /**
147: * Creates a new instance of RemoteWMService
148: *
149: * @param capabilities
150: */
151: public RemoteWMService(WMSCapabilities capabilities) {
152: this .capabilities = capabilities;
153: addresses = new HashMap<String, URL>();
154:
155: // get GetCapabilities operation address
156: List<DCP> dcps = null;
157: HTTP http = null;
158:
159: OperationsMetadata om = capabilities.getOperationMetadata();
160:
161: if (capabilities.getVersion().equals("1.0.0")) {
162: dcps = om
163: .getOperation(new QualifiedName(CAPABILITIES_NAME))
164: .getDCP();
165: for (DCP dcp : dcps)
166: if (dcp instanceof HTTP)
167: http = (HTTP) dcp;
168: addresses.put(CAPABILITIES_NAME, http.getLinks().get(0)
169: .getLinkage().getHref());
170: } else {
171: dcps = om.getOperation(
172: new QualifiedName(GETCAPABILITIES_NAME)).getDCP();
173: for (DCP dcp : dcps)
174: if (dcp instanceof HTTP)
175: http = (HTTP) dcp;
176: addresses.put(GETCAPABILITIES_NAME, http.getLinks().get(0)
177: .getLinkage().getHref());
178: }
179:
180: // get GetMap operation address
181: if (capabilities.getVersion().equals("1.0.0")) {
182: dcps = om.getOperation(new QualifiedName(MAP_NAME))
183: .getDCP();
184: for (DCP dcp : dcps)
185: if (dcp instanceof HTTP)
186: http = (HTTP) dcp;
187: addresses.put(MAP_NAME, http.getLinks().get(0).getLinkage()
188: .getHref());
189: } else {
190: dcps = om.getOperation(new QualifiedName(GETMAP_NAME))
191: .getDCP();
192: for (DCP dcp : dcps)
193: if (dcp instanceof HTTP)
194: http = (HTTP) dcp;
195: addresses.put(GETMAP_NAME, http.getLinks().get(0)
196: .getLinkage().getHref());
197: }
198:
199: // get GetFeatureInfo operation address
200: if (capabilities.getVersion().equals("1.0.0")) {
201: Operation operation = om.getOperation(new QualifiedName(
202: FEATUREINFO_NAME));
203:
204: if (operation != null) {
205: dcps = operation.getDCP();
206: for (DCP dcp : dcps)
207: if (dcp instanceof HTTP)
208: http = (HTTP) dcp;
209: addresses.put(FEATUREINFO_NAME, http.getLinks().get(0)
210: .getLinkage().getHref());
211: }
212: } else {
213: Operation operation = om.getOperation(new QualifiedName(
214: GETFEATUREINFO_NAME));
215:
216: if (operation != null) {
217: dcps = operation.getDCP();
218: for (DCP dcp : dcps)
219: if (dcp instanceof HTTP)
220: http = (HTTP) dcp;
221: addresses.put(GETFEATUREINFO_NAME, http.getLinks().get(
222: 0).getLinkage().getHref());
223: }
224: }
225:
226: // get GetLegendGraphic operation address
227: Operation operation = om.getOperation(new QualifiedName(
228: GETLEGENDGRAPHIC_NAME));
229:
230: if (operation != null) {
231: dcps = operation.getDCP();
232: for (DCP dcp : dcps)
233: if (dcp instanceof HTTP)
234: http = (HTTP) dcp;
235: addresses.put(GETLEGENDGRAPHIC_NAME, http.getLinks().get(0)
236: .getLinkage().getHref());
237: }
238:
239: // get GetStyles operation address
240: operation = om.getOperation(new QualifiedName(GETSTYLES_NAME));
241:
242: if (operation != null) {
243: dcps = operation.getDCP();
244: for (DCP dcp : dcps)
245: if (dcp instanceof HTTP)
246: http = (HTTP) dcp;
247: addresses.put(GETSTYLES_NAME, http.getLinks().get(0)
248: .getLinkage().getHref());
249: }
250:
251: // get PutStyles operation address
252: operation = om.getOperation(new QualifiedName(PUTSTYLES_NAME));
253:
254: if (operation != null) {
255: dcps = operation.getDCP();
256: for (DCP dcp : dcps)
257: if (dcp instanceof HTTP)
258: http = (HTTP) dcp;
259: addresses.put(PUTSTYLES_NAME, http.getLinks().get(0)
260: .getLinkage().getHref());
261: }
262:
263: // get DescribeLayer operation address
264: operation = om.getOperation(new QualifiedName(
265: DESCRIBELAYER_NAME));
266:
267: if (operation != null) {
268: dcps = operation.getDCP();
269: for (DCP dcp : dcps)
270: if (dcp instanceof HTTP)
271: http = (HTTP) dcp;
272: addresses.put(DESCRIBELAYER_NAME, http.getLinks().get(0)
273: .getLinkage().getHref());
274: }
275:
276: }
277:
278: public OGCCapabilities getCapabilities() {
279: return capabilities;
280: }
281:
282: /**
283: * the method performs the handling of the passed OGCWebServiceEvent directly and returns the
284: * result to the calling class/method
285: *
286: * @param request
287: * request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
288: *
289: * @throws OGCWebServiceException
290: */
291: public Object doService(OGCWebServiceRequest request)
292: throws OGCWebServiceException {
293: Object o = null;
294: if (request instanceof GetMap) {
295: o = handleGetMap((GetMap) request);
296: o = WMSProtocolFactory.createGetMapResponse(request, null,
297: o);
298: } else if (request instanceof GetFeatureInfo) {
299: o = handleFeatureInfo((GetFeatureInfo) request);
300: o = WMSProtocolFactory.createGetFeatureInfoResponse(
301: request, null, (String) o);
302: }
303: /*
304: * else if ( request instanceof WMSGetCapabilities) { handleGetCapabilities(
305: * (WMSGetCapabilities)request, client ); } else if ( request instanceof GetStyles ) {
306: * handleGetStyles( (GetStyles)request, client ); } else if ( request instanceof PutStyles ) {
307: * handlePutStyles( (PutStyles)request, client ); } else if ( request instanceof
308: * DescribeLayer ) { handleDescribeLayer( (DescribeLayer)request, client ); } else if (
309: * request instanceof GetLegendGraphic ) { handleGetLegendGraphic(
310: * (GetLegendGraphic)request, client ); }
311: */
312:
313: return o;
314:
315: }
316:
317: // checks for excessive &
318: private static String constructRequestURL(String params, String url) {
319: if (url.endsWith("?") && params.startsWith("&")) {
320: return url + params.substring(1);
321: }
322:
323: return url + params;
324: }
325:
326: /**
327: * performs a GetMap request against the remote service. The result contains the map decoded in
328: * the desired format as a byte array.
329: *
330: * @param request
331: * GetMap request
332: */
333: protected Object handleGetMap(GetMap request)
334: throws OGCWebServiceException {
335:
336: URL url = null;
337:
338: if (request.getVersion().equals("1.0.0")) {
339: url = addresses.get(MAP_NAME);
340: } else {
341: url = addresses.get(GETMAP_NAME);
342: }
343:
344: String us = constructRequestURL(request.getRequestParameter(),
345: validateHTTPGetBaseURL(url.toExternalForm()));
346:
347: LOG.logDebug("remote wms getmap", us);
348:
349: if (capabilities.getVersion().compareTo("1.0.0") <= 0) {
350: us = StringTools.replace(us, "TRANSPARENCY", "TRANSPARENT",
351: false);
352: us = StringTools.replace(us, "GetMap", "map", false);
353: us = StringTools.replace(us, "image/", "", false);
354: }
355:
356: Object result = null;
357: try {
358: HttpClient client = new HttpClient();
359: int timeout = 25000;
360: if (properties != null
361: && properties.getProperty("timeout") != null) {
362: timeout = Integer.parseInt(properties
363: .getProperty("timeout"));
364: }
365: LOG.logDebug("timeout is:", timeout);
366: client.getHttpConnectionManager().getParams().setSoTimeout(
367: timeout);
368: GetMethod get = new GetMethod(us);
369: client.executeMethod(get);
370: InputStream is = get.getResponseBodyAsStream();
371: Header header = get.getResponseHeader("Content-type");
372:
373: String contentType = header.getValue();
374: String[] tmp = StringTools.toArray(contentType, ";", true);
375: for (int i = 0; i < tmp.length; i++) {
376: if (tmp[i].indexOf("image") > -1) {
377: contentType = tmp[i];
378: break;
379: }
380: contentType = tmp[0];
381: }
382:
383: if (MimeTypeMapper.isImageType(contentType)
384: && MimeTypeMapper.isKnownImageType(contentType)) {
385: MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream(
386: is);
387: RenderedOp rop = JAI.create("stream", mcss);
388: result = rop.getAsBufferedImage();
389: mcss.close();
390: } else {
391: // extract remote (error) message if the response
392: // contains a known mime type
393: String res = "";
394: if (MimeTypeMapper.isKnownMimeType(contentType)) {
395: res = "; remote message: ";
396: res += getInputStreamContent(is);
397: }
398: String msg = Messages.getMessage(
399: "REMOTEWMS_GETMAP_INVALID_RESULT", contentType,
400: us);
401: throw new OGCWebServiceException(
402: "RemoteWMS:handleGetMap", msg);
403: }
404: } catch (Exception e) {
405: LOG.logError(e.getMessage(), e);
406: String msg = Messages.getMessage(
407: "REMOTEWMS_GETMAP_GENERAL_ERROR", capabilities
408: .getServiceIdentification().getTitle(), us);
409: throw new OGCWebServiceException("RemoteWMS:handleGetMap",
410: msg);
411: }
412:
413: return result;
414: }
415:
416: /**
417: * reads feature infos from the remote WMS by performing a FeatureInfo request against it. As
418: * long the result of a FeatureInfo request is generic (for usual it is som HTML) it isn't easy
419: * to combine the result with that of other WMS's
420: *
421: * @param request
422: * feature info request
423: */
424: protected Object handleFeatureInfo(GetFeatureInfo request)
425: throws OGCWebServiceException {
426:
427: URL url = null;
428:
429: if (request.getVersion().equals("1.0.0")) {
430: url = addresses.get(FEATUREINFO_NAME);
431: } else {
432: url = addresses.get(GETFEATUREINFO_NAME);
433: }
434:
435: if (url == null) {
436: String msg = Messages.getMessage(
437: "REMOTEWMS_GFI_NOT_SUPPORTED", capabilities
438: .getServiceIdentification().getTitle());
439: throw new OGCWebServiceException(msg);
440: }
441:
442: String us = constructRequestURL(request.getRequestParameter(),
443: validateHTTPGetBaseURL(url.toExternalForm()));
444:
445: String result = null;
446: try {
447: LOG.logDebug("GetFeatureInfo: ", us);
448: URL ur = new URL(us);
449: // get map from the remote service
450: NetWorker nw = new NetWorker(ur);
451: byte[] b = nw.getDataAsByteArr(20000);
452: String contentType = nw.getContentType();
453:
454: // extract content charset if available; otherwise use configured system charset
455: String charset = null;
456: LOG.logDebug("content type: ", contentType);
457: if (contentType != null) {
458: String[] tmp = StringTools.toArray(contentType, ";",
459: false);
460: if (tmp.length == 2) {
461: charset = tmp[1].substring(tmp[1].indexOf('=') + 1,
462: tmp[1].length());
463: } else {
464: charset = CharsetUtils.getSystemCharset();
465: }
466: } else {
467: charset = CharsetUtils.getSystemCharset();
468: }
469:
470: if (contentType.toLowerCase().startsWith(
471: "application/vnd.ogc.gml")) {
472: result = new String(b, charset);
473: } else {
474: throw new OGCWebServiceException(
475: "RemoteWMS:handleFeatureInfo");
476: }
477: } catch (Exception e) {
478: LOG.logError(e.getMessage(), e);
479: String msg = Messages.getMessage(
480: "REMOTEWMS_GFI_GENERAL_ERROR", capabilities
481: .getServiceIdentification().getTitle(), us);
482: throw new OGCWebServiceException(
483: "RemoteWMS:handleFeatureInfo", msg);
484: }
485:
486: return result;
487: }
488:
489: /**
490: * reads the capabilities from the remote WMS by performing a GetCapabilities request against
491: * it.
492: *
493: * @param request
494: * capabilities request
495: */
496: protected WMSCapabilities handleGetCapabilities(
497: WMSGetCapabilities request) throws OGCWebServiceException {
498:
499: URL url = null;
500:
501: if (request.getVersion().equals("1.0.0")) {
502: url = addresses.get(CAPABILITIES_NAME);
503: } else {
504: url = addresses.get(GETCAPABILITIES_NAME);
505: }
506:
507: String us = constructRequestURL(request.getRequestParameter(),
508: validateHTTPGetBaseURL(url.toExternalForm()));
509:
510: WMSCapabilities result = null;
511:
512: try {
513: URL ur = new URL(us);
514: // get map from the remote service
515: NetWorker nw = new NetWorker(ur);
516: byte[] b = nw.getDataAsByteArr(20000);
517: String contentType = nw.getContentType();
518:
519: if (MimeTypeMapper.isKnownMimeType(contentType)) {
520: // create a WMSCapabilitiesTEMP instance from the result
521: StringReader reader = new StringReader(new String(b));
522: WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
523: doc.load(reader, XMLFragment.DEFAULT_URL);
524: doc = WMSCapabilitiesDocumentFactory
525: .getWMSCapabilitiesDocument(doc
526: .getRootElement());
527: result = (WMSCapabilities) doc.parseCapabilities();
528: } else {
529: String msg = Messages.getMessage(
530: "REMOTEWMS_GETCAPS_INVALID_CONTENTTYPE",
531: contentType, us);
532: throw new OGCWebServiceException(
533: "RemoteWMS:handleGetCapabilities", msg);
534: }
535: } catch (Exception e) {
536: LOG.logError(e.getMessage(), e);
537: String msg = Messages.getMessage(
538: "REMOTEWMS_GETCAPS_GENERAL_ERROR", capabilities
539: .getServiceIdentification().getTitle(), us);
540: throw new OGCWebServiceException(
541: "RemoteWMS:handleGetCapabilities", msg);
542: }
543:
544: return result;
545: }
546:
547: /**
548: *
549: *
550: * @param request
551: * get styles request (WMS 1.1.1 - SLD)
552: */
553: protected Object handleGetStyles(GetStyles request)
554: throws OGCWebServiceException {
555:
556: URL url = addresses.get(GETSTYLES_NAME);
557:
558: if (url == null) {
559: throw new OGCWebServiceException(
560: "GetStyles is not supported by the RemoteWMS: "
561: + capabilities.getServiceIdentification()
562: .getTitle());
563: }
564:
565: constructRequestURL(request.getRequestParameter(),
566: validateHTTPGetBaseURL(url.toExternalForm()));
567:
568: // FIXME
569: // TODO
570: return null;
571: }
572:
573: /**
574: *
575: *
576: * @param request
577: * put styles request (WMS 1.1.1 - SLD)
578: */
579: protected Object handlePutStyles(PutStyles request)
580: throws OGCWebServiceException {
581:
582: URL url = addresses.get(PUTSTYLES_NAME);
583:
584: if (url == null) {
585: throw new OGCWebServiceException(
586: "PUTSTYLES is not supported by the RemoteWMS: "
587: + capabilities.getServiceIdentification()
588: .getTitle());
589: }
590:
591: constructRequestURL(request.getRequestParameter(),
592: validateHTTPGetBaseURL(url.toExternalForm()));
593:
594: // FIXME
595: // TODO
596:
597: return null;
598: }
599:
600: /**
601: *
602: *
603: * @param request
604: * describe layer request (WMS 1.1.1 - SLD)
605: */
606: protected Object handleDescribeLayer(DescribeLayer request)
607: throws OGCWebServiceException {
608:
609: URL url = addresses.get(DESCRIBELAYER_NAME);
610:
611: if (url == null) {
612: throw new OGCWebServiceException(
613: "DESCRIBELAYER is not supported by the RemoteWMS: "
614: + capabilities.getServiceIdentification()
615: .getTitle());
616: }
617:
618: constructRequestURL(request.getRequestParameter(),
619: validateHTTPGetBaseURL(url.toExternalForm()));
620:
621: // FIXME
622: // TODO
623:
624: return null;
625: }
626:
627: /**
628: *
629: *
630: * @param request
631: * describe layer request (WMS 1.1.1 - SLD)
632: */
633: protected Object handleGetLegendGraphic(GetLegendGraphic request)
634: throws OGCWebServiceException {
635:
636: URL url = addresses.get(GETLEGENDGRAPHIC_NAME);
637:
638: if (url == null) {
639: throw new OGCWebServiceException(
640: "GETLEGENDGRAPHIC is not supported by the RemoteWMS: "
641: + capabilities.getServiceIdentification()
642: .getTitle());
643: }
644:
645: constructRequestURL(request.getRequestParameter(),
646: validateHTTPGetBaseURL(url.toExternalForm()));
647:
648: // FIXME
649: // TODO
650:
651: return null;
652: }
653:
654: /**
655: *
656: *
657: * @param is
658: *
659: * @return thr content as String
660: *
661: * @throws IOException
662: */
663: protected String getInputStreamContent(InputStream is)
664: throws IOException {
665: StringBuffer sb = new StringBuffer(1000);
666: int c = 0;
667:
668: while ((c = is.read()) >= 0) {
669: sb.append((char) c);
670: }
671:
672: is.close();
673: return sb.toString();
674: }
675:
676: }
|