001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcwebservices/wms/DefaultGetMapHandler.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: 53177 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: package org.deegree.ogcwebservices.wms;
044:
045: import java.awt.Color;
046: import java.awt.Font;
047: import java.awt.Graphics;
048: import java.awt.Graphics2D;
049: import java.awt.RenderingHints;
050: import java.awt.image.BufferedImage;
051: import java.util.ArrayList;
052: import java.util.LinkedList;
053: import java.util.List;
054: import java.util.concurrent.Callable;
055: import java.util.concurrent.CancellationException;
056:
057: import org.apache.batik.svggen.SVGGraphics2D;
058: import org.deegree.framework.concurrent.ExecutionFinishedEvent;
059: import org.deegree.framework.concurrent.Executor;
060: import org.deegree.framework.log.ILogger;
061: import org.deegree.framework.log.LoggerFactory;
062: import org.deegree.framework.util.ImageUtils;
063: import org.deegree.framework.util.MapUtils;
064: import org.deegree.framework.util.MimeTypeMapper;
065: import org.deegree.graphics.MapFactory;
066: import org.deegree.graphics.Theme;
067: import org.deegree.graphics.optimizers.LabelOptimizer;
068: import org.deegree.graphics.sld.AbstractLayer;
069: import org.deegree.graphics.sld.AbstractStyle;
070: import org.deegree.graphics.sld.NamedLayer;
071: import org.deegree.graphics.sld.NamedStyle;
072: import org.deegree.graphics.sld.StyledLayerDescriptor;
073: import org.deegree.graphics.sld.UserLayer;
074: import org.deegree.graphics.sld.UserStyle;
075: import org.deegree.i18n.Messages;
076: import org.deegree.model.crs.CRSFactory;
077: import org.deegree.model.crs.CoordinateSystem;
078: import org.deegree.model.crs.GeoTransformer;
079: import org.deegree.model.spatialschema.Envelope;
080: import org.deegree.model.spatialschema.Geometry;
081: import org.deegree.model.spatialschema.GeometryFactory;
082: import org.deegree.ogcbase.InvalidSRSException;
083: import org.deegree.ogcwebservices.InconsistentRequestException;
084: import org.deegree.ogcwebservices.OGCWebServiceException;
085: import org.deegree.ogcwebservices.OGCWebServiceResponse;
086: import org.deegree.ogcwebservices.wms.capabilities.ScaleHint;
087: import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
088: import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationType;
089: import org.deegree.ogcwebservices.wms.configuration.WMSConfiguration_1_3_0;
090: import org.deegree.ogcwebservices.wms.configuration.WMSDeegreeParams;
091: import org.deegree.ogcwebservices.wms.operation.GetMap;
092: import org.deegree.ogcwebservices.wms.operation.GetMapResult;
093: import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
094: import org.deegree.ogcwebservices.wms.operation.GetMap.Layer;
095: import org.w3c.dom.Element;
096:
097: /**
098: *
099: *
100: * @version $Revision: 9697 $
101: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
102: */
103: public class DefaultGetMapHandler implements GetMapHandler {
104:
105: private static final ILogger LOG = LoggerFactory
106: .getLogger(DefaultGetMapHandler.class);
107:
108: private GetMap request = null;
109:
110: // private Object[] themes = null;
111:
112: private double scale = 0;
113:
114: private CoordinateSystem reqCRS = null;
115:
116: private WMSConfigurationType configuration = null;
117:
118: private BufferedImage copyrightImg = null;
119:
120: boolean version130 = false;
121:
122: /**
123: * Creates a new GetMapHandler object.
124: *
125: * @param configuration
126: * @param request
127: * request to perform
128: */
129: public DefaultGetMapHandler(WMSConfigurationType configuration,
130: GetMap request) {
131: this .request = request;
132: this .configuration = configuration;
133:
134: try {
135: // get copyright image if possible
136: copyrightImg = ImageUtils.loadImage(configuration
137: .getDeegreeParams().getCopyRight());
138: } catch (Exception e) {
139: // don't use copyright
140: }
141:
142: }
143:
144: /**
145: * returns the configuration used by the handler
146: *
147: * @return the configuration document
148: */
149: public WMSConfigurationType getConfiguration() {
150: return configuration;
151: }
152:
153: /**
154: * performs a GetMap request and retruns the result encapsulated within a <tt>GetMapResult</tt>
155: * object.
156: * <p>
157: * The method throws an WebServiceException that only shall be thrown if an fatal error occurs
158: * that makes it imposible to return a result. If something wents wrong performing the request
159: * (none fatal error) The exception shall be encapsulated within the response object to be
160: * returned to the client as requested (GetMap-Request EXCEPTION-Parameter).
161: *
162: * @return response to the GetMap response
163: */
164: public OGCWebServiceResponse performGetMap()
165: throws OGCWebServiceException {
166:
167: // some initialization is done here because the constructor is called by reflection
168: // and the exceptions won't be properly handled in that case
169: try {
170: reqCRS = CRSFactory.create(request.getSrs().toLowerCase());
171: } catch (Exception e) {
172: throw new InvalidSRSException(Messages.getMessage(
173: "WMS_UNKNOWN_CRS", request.getSrs()));
174: }
175:
176: version130 = "1.3.0".equals(request.getVersion());
177:
178: // exceeds the max allowed map width ?
179: int maxWidth = configuration.getDeegreeParams()
180: .getMaxMapWidth();
181: if ((maxWidth != 0) && (request.getWidth() > maxWidth)) {
182: throw new InconsistentRequestException(Messages.getMessage(
183: "WMS_EXCEEDS_WIDTH", new Integer(maxWidth)));
184: }
185:
186: // exceeds the max allowed map height ?
187: int maxHeight = configuration.getDeegreeParams()
188: .getMaxMapHeight();
189: if ((maxHeight != 0) && (request.getHeight() > maxHeight)) {
190: throw new InconsistentRequestException(Messages.getMessage(
191: "WMS_EXCEEDS_HEIGHT", new Integer(maxHeight)));
192: }
193:
194: try {
195: double pixelSize = 1;
196: if (version130) {
197: // required because for WMS 1.3.0 'scale' represents the ScaleDenominator
198: // and for WMS < 1.3.0 it represents the size of a pixel diagonal in meter
199: pixelSize = MapUtils.DEFAULT_PIXEL_SIZE;
200: }
201:
202: scale = MapUtils.calcScale(request.getWidth(), request
203: .getHeight(), request.getBoundingBox(), reqCRS,
204: pixelSize);
205:
206: LOG.logInfo("OGC WMS scale: " + scale);
207: } catch (Exception e) {
208: LOG.logError(e.getMessage(), e);
209: throw new OGCWebServiceException(Messages
210: .getMessage("WMS_SCALECALC"));
211: }
212:
213: GetMap.Layer[] ls = request.getLayers();
214:
215: // if 1.3.0, check for maximum allowed layers
216: if (version130) {
217: WMSConfiguration_1_3_0 cfg = (WMSConfiguration_1_3_0) configuration;
218: if (ls.length > cfg.getLayerLimit()) {
219: String ms = Messages.getMessage("WMS_EXCEEDS_NUMBER",
220: new Integer(cfg.getLayerLimit()));
221: throw new InconsistentRequestException(ms);
222: }
223: }
224:
225: Layer[] oldLayers = ls;
226: ls = validateLayers(ls);
227:
228: LOG.logDebug("Validated " + ls.length + " layers.");
229:
230: StyledLayerDescriptor sld = toSLD(oldLayers, request
231: .getStyledLayerDescriptor());
232:
233: AbstractLayer[] layers = sld.getLayers();
234:
235: LOG.logDebug("After SLD consideration, found " + layers.length
236: + " layers.");
237:
238: List<Callable<Object>> themes = new LinkedList<Callable<Object>>();
239:
240: for (int i = 0; i < layers.length; i++) {
241:
242: if (layers[i] instanceof NamedLayer) {
243: String styleName = null;
244: if (i < request.getLayers().length) {
245: styleName = request.getLayers()[i].getStyleName();
246: }
247: invokeNamedLayer(layers[i], styleName, themes);
248: } else {
249: double sc = scale;
250: if (!version130) {
251: // required because for WMS 1.3.0 'scale' represents the ScaleDenominator
252: // and for WMS < 1.3.0 it represents the size of a pixel diagonal in meter
253: sc = scale / MapUtils.DEFAULT_PIXEL_SIZE;
254: }
255: themes.add(new GetMapServiceInvokerForUL(this ,
256: (UserLayer) layers[i], sc));
257: }
258: }
259:
260: Executor executor = Executor.getInstance();
261: try {
262: List<ExecutionFinishedEvent<Object>> results;
263: results = executor.performSynchronously(themes,
264: configuration.getDeegreeParams()
265: .getRequestTimeLimit());
266:
267: GetMapResult res = renderMap(results);
268: return res;
269: } catch (InterruptedException e) {
270: LOG.logError(e.getMessage(), e);
271: String s = Messages.getMessage("WMS_WAITING");
272: throw new OGCWebServiceException(getClass().getName(), s);
273: }
274: }
275:
276: /**
277: * this methods validates layer in two ways:<br>
278: * a) are layers available from the current WMS<br>
279: * b) If a layer is selected that includes other layers determine all its sublayers having
280: * <Name>s and return them instead
281: *
282: * @param ls
283: * @return the layers
284: * @throws LayerNotDefinedException
285: * @throws InvalidSRSException
286: */
287: private Layer[] validateLayers(Layer[] ls)
288: throws LayerNotDefinedException, InvalidSRSException {
289:
290: List<Layer> layer = new ArrayList<Layer>(ls.length);
291: for (int i = 0; i < ls.length; i++) {
292: org.deegree.ogcwebservices.wms.capabilities.Layer l = configuration
293: .getLayer(ls[i].getName());
294:
295: if (l == null) {
296: throw new LayerNotDefinedException(Messages.getMessage(
297: "WMS_UNKNOWNLAYER", ls[i].getName()));
298: }
299:
300: validateSRS(l.getSrs(), ls[i].getName());
301:
302: layer.add(ls[i]);
303: if (l.getLayer() != null) {
304: layer = addNestedLayers(l.getLayer(), ls[i]
305: .getStyleName(), layer);
306: }
307: }
308:
309: return layer.toArray(new Layer[layer.size()]);
310: }
311:
312: /**
313: * adds all direct and none direct sub-layers of the passed WMS capabilities layer as
314: *
315: * @see GetMap.Layer to the passed list.
316: * @param layer
317: * @param reqLayer
318: * @param list
319: * @return all sublayers
320: * @throws InvalidSRSException
321: */
322: private List<Layer> addNestedLayers(
323: org.deegree.ogcwebservices.wms.capabilities.Layer[] ll,
324: String styleName, List<Layer> list)
325: throws InvalidSRSException {
326:
327: for (int j = 0; j < ll.length; j++) {
328: if (ll[j].getName() != null) {
329: String name = ll[j].getName();
330: validateSRS(ll[j].getSrs(), name);
331: list.add(GetMap.createLayer(name, styleName));
332: }
333: if (ll[j].getLayer() != null) {
334: list = addNestedLayers(ll[j].getLayer(), styleName,
335: list);
336: }
337:
338: }
339: return list;
340: }
341:
342: /**
343: * throws an exception if the requested SRS is not be supported by the passed layer (name)
344: *
345: * @param srs
346: * @param name
347: * @throws InvalidSRSException
348: */
349: private void validateSRS(String[] srs, String name)
350: throws InvalidSRSException {
351: boolean validSRS = false;
352: for (int k = 0; k < srs.length; k++) {
353: validSRS = srs[k].equalsIgnoreCase(reqCRS.getIdentifier());
354: if (validSRS)
355: break;
356: }
357: if (!validSRS) {
358: String s = Messages.getMessage("WMS_UNKNOWN_CRS_FOR_LAYER",
359: reqCRS.getIdentifier(), name);
360: throw new InvalidSRSException(s);
361: }
362: }
363:
364: private void invokeNamedLayer(AbstractLayer layer,
365: String styleName, List<Callable<Object>> tasks)
366: throws OGCWebServiceException {
367:
368: org.deegree.ogcwebservices.wms.capabilities.Layer lay = configuration
369: .getLayer(layer.getName());
370:
371: LOG.logDebug("Invoked layer " + layer.getName());
372:
373: if (validate(lay, layer.getName())) {
374:
375: UserStyle us = getStyles((NamedLayer) layer, styleName);
376: AbstractDataSource[] ds = lay.getDataSource();
377:
378: if (ds.length == 0) {
379: LOG.logDebug("No datasources for layer "
380: + layer.getName());
381: } else {
382: for (int j = 0; j < ds.length; j++) {
383:
384: LOG.logDebug("Invoked datasource "
385: + ds[j].getClass() + " for layer "
386: + layer.getName());
387:
388: ScaleHint scaleHint = ds[j].getScaleHint();
389: if (scale >= scaleHint.getMin()
390: && scale < scaleHint.getMax()
391: && isValidArea(ds[j].getValidArea())) {
392: double sc = scale;
393: if (!version130) {
394: // required because for WMS 1.3.0 'scale' represents the
395: // ScaleDenominator
396: // and for WMS < 1.3.0 it represents the size of a pixel diagonal in
397: // meter
398: sc = scale / MapUtils.DEFAULT_PIXEL_SIZE;
399: }
400:
401: GetMapServiceInvokerForNL si = new GetMapServiceInvokerForNL(
402: this , (NamedLayer) layer, ds[j], us, sc);
403: tasks.add(si);
404: } else {
405: LOG.logDebug("Not showing layer "
406: + layer.getName() + " due to scale");
407: }
408: }
409: }
410: }
411: }
412:
413: /**
414: * returns true if the requested boundingbox intersects with the valid area of a datasource
415: *
416: * @param validArea
417: */
418: private boolean isValidArea(Geometry validArea) {
419:
420: if (validArea != null) {
421: try {
422: Envelope env = request.getBoundingBox();
423: Geometry geom = GeometryFactory.createSurface(env,
424: reqCRS);
425: if (!reqCRS.getIdentifier()
426: .equals(
427: validArea.getCoordinateSystem()
428: .getIdentifier())) {
429: // if requested CRS is not identical to the CRS of the valid area
430: // a transformation must be performed before intersection can
431: // be checked
432: GeoTransformer gt = new GeoTransformer(validArea
433: .getCoordinateSystem());
434: geom = gt.transform(geom);
435: }
436: return geom.intersects(validArea);
437: } catch (Exception e) {
438: // should never happen
439: LOG.logError("Could not validate WMS datasource area",
440: e);
441: }
442: }
443: return true;
444: }
445:
446: /**
447: * creates a StyledLayerDocument containing all requested layer, nested layers if required and
448: * assigend styles. Not considered are nested layers for mixed requests (LAYERS- and SLD(_BODY)-
449: * parameter has been defined)
450: *
451: * @param layers
452: * @param inSLD
453: * @return a combined SLD object
454: * @throws InvalidSRSException
455: */
456: private StyledLayerDescriptor toSLD(GetMap.Layer[] layers,
457: StyledLayerDescriptor inSLD) throws InvalidSRSException {
458: StyledLayerDescriptor sld = null;
459:
460: if (layers != null && layers.length > 0 && inSLD == null) {
461: // if just a list of layers has been requested
462:
463: // create a SLD from the requested LAYERS and assigned STYLES
464: List<AbstractLayer> al = new ArrayList<AbstractLayer>(
465: layers.length * 2);
466: for (int i = 0; i < layers.length; i++) {
467: AbstractStyle[] as = new AbstractStyle[] { new NamedStyle(
468: layers[i].getStyleName()) };
469: al.add(new NamedLayer(layers[i].getName(), null, as));
470:
471: // collect all named nested layers
472: org.deegree.ogcwebservices.wms.capabilities.Layer lla;
473: lla = configuration.getLayer(layers[i].getName());
474: List<GetMap.Layer> list = new ArrayList<GetMap.Layer>();
475: addNestedLayers(lla.getLayer(), layers[i]
476: .getStyleName(), list);
477:
478: // add nested layers to list of layers to be handled
479: for (int j = 0; j < list.size(); j++) {
480: GetMap.Layer nestedLayer = list.get(j);
481: as = new AbstractStyle[] { new NamedStyle(
482: nestedLayer.getStyleName()) };
483: al.add(new NamedLayer(nestedLayer.getName(), null,
484: as));
485: }
486: }
487: sld = new StyledLayerDescriptor(al
488: .toArray(new AbstractLayer[al.size()]), "1.0.0");
489: } else if (layers != null && layers.length > 0 && inSLD != null) {
490: // if layers not null and sld is not null then SLD layers just be
491: // considered if present in the layers list
492: // TODO
493: // layer with nested layers are not handled correctly and I think
494: // it really causes a lot of problems to use them in such a way
495: // because the style assigned to the mesting layer must be
496: // applicable for all nested layers.
497: List<String> list = new ArrayList<String>();
498: for (int i = 0; i < layers.length; i++) {
499: list.add(layers[i].getName());
500: }
501:
502: List<AbstractLayer> newList = new ArrayList<AbstractLayer>(
503: 20);
504: AbstractLayer[] al = inSLD.getLayers();
505: for (int i = 0; i < al.length; i++) {
506: if (list.contains(al[i].getName())) {
507: newList.add(al[i]);
508: }
509: }
510: al = new AbstractLayer[newList.size()];
511: sld = new StyledLayerDescriptor(newList.toArray(al), inSLD
512: .getVersion());
513:
514: // add nested layers for mixed case, nested from original sld
515: AbstractLayer[] as = inSLD.getLayers();
516: for (AbstractLayer l : as) {
517: addNestedLayers(l, sld);
518: }
519: } else {
520: // if no layers but a SLD is defined ...
521: AbstractLayer[] as = inSLD.getLayers();
522: for (AbstractLayer l : as) {
523: addNestedLayers(l, inSLD);
524: }
525:
526: sld = inSLD;
527: }
528:
529: return sld;
530: }
531:
532: // adds the nested layers to the sld
533: private void addNestedLayers(AbstractLayer l,
534: StyledLayerDescriptor sld) {
535: if (!(l instanceof NamedLayer)) {
536: return;
537: }
538: if (configuration.getLayer(l.getName()) == null) {
539: return;
540: }
541:
542: org.deegree.ogcwebservices.wms.capabilities.Layer[] ls;
543: ls = configuration.getLayer(l.getName()).getLayer();
544: for (org.deegree.ogcwebservices.wms.capabilities.Layer lay : ls) {
545: NamedStyle sty = new NamedStyle(lay.getStyles()[0]
546: .getName());
547: AbstractStyle[] newSty = new AbstractStyle[] { sty };
548: NamedLayer newLay = new NamedLayer(lay.getName(), null,
549: newSty);
550: sld.addLayer(newLay);
551: }
552: }
553:
554: /**
555: * returns the <tt>UserStyle</tt>s assigned to a named layer
556: *
557: * @param sldLayer
558: * layer to get the styles for
559: * @param styleName
560: * requested stylename (from the KVP encoding)
561: */
562: private UserStyle getStyles(NamedLayer sldLayer, String styleName)
563: throws OGCWebServiceException {
564:
565: AbstractStyle[] styles = sldLayer.getStyles();
566: UserStyle us = null;
567:
568: // to avoid retrieving the layer again for each style
569: org.deegree.ogcwebservices.wms.capabilities.Layer layer = null;
570: layer = configuration.getLayer(sldLayer.getName());
571: int i = 0;
572: while (us == null && i < styles.length) {
573: if (styles[i] instanceof NamedStyle) {
574: // styles will be taken from the WMS's style repository
575: us = getPredefinedStyle(styles[i].getName(), sldLayer
576: .getName(), layer);
577: } else {
578: // if the requested style fits the name of the defined style or
579: // if the defined style is marked as default and the requested
580: // style if 'default' the condition is true. This includes that
581: // if more than one style with the same name or more than one
582: // style is marked as default always the first will be choosen
583: if (styleName == null
584: || (styles[i].getName() != null && styles[i]
585: .getName().equals(styleName))
586: || (styleName.equalsIgnoreCase("$DEFAULT") && ((UserStyle) styles[i])
587: .isDefault())) {
588: us = (UserStyle) styles[i];
589: }
590: }
591: i++;
592: }
593: if (us == null) {
594: // this may happens if the SLD contains a named layer but not
595: // a style! yes this is valid according to SLD spec 1.0.0
596: us = getPredefinedStyle(styleName, sldLayer.getName(),
597: layer);
598: }
599: return us;
600: }
601:
602: /**
603: *
604: * @param styleName
605: * @param layerName
606: * @param layer
607: * @return the style
608: * @throws StyleNotDefinedException
609: */
610: private UserStyle getPredefinedStyle(String styleName,
611: String layerName,
612: org.deegree.ogcwebservices.wms.capabilities.Layer layer)
613: throws StyleNotDefinedException {
614: UserStyle us = null;
615: if ("default".equals(styleName)) {
616: us = layer.getStyle(styleName);
617: }
618:
619: if (us == null) {
620: if (styleName == null || styleName.length() == 0
621: || styleName.equals("$DEFAULT")
622: || styleName.equals("default")) {
623: styleName = "default:" + layerName;
624: }
625: }
626:
627: us = layer.getStyle(styleName);
628:
629: if (us == null && !(styleName.startsWith("default"))
630: && !(styleName.startsWith("$DEFAULT"))) {
631: String s = Messages.getMessage("WMS_STYLENOTDEFINED",
632: styleName, layer);
633: throw new StyleNotDefinedException(s);
634: }
635: return us;
636: }
637:
638: /**
639: * validates if the requested layer matches the conditions of the request if not a
640: * <tt>WebServiceException</tt> will be thrown. If the layer matches the request, but isn't
641: * able to deviever data for the requested area and/or scale false will be returned. If the
642: * layer matches the request and contains data for the requested area and/or scale true will be
643: * returned.
644: *
645: * @param layer
646: * layer as defined at the capabilities/configuration
647: * @param name
648: * name of the layer (must be submitted seperatly because the layer parameter can be
649: * <tt>null</tt>
650: */
651: private boolean validate(
652: org.deegree.ogcwebservices.wms.capabilities.Layer layer,
653: String name) throws OGCWebServiceException {
654:
655: // check if layer is available
656: if (layer == null) {
657: throw new LayerNotDefinedException(Messages.getMessage(
658: "WMS_UNKNOWNLAYER", name));
659: }
660:
661: // check bounding box
662: try {
663: Envelope bbox = request.getBoundingBox();
664: Envelope layerBbox = layer.getLatLonBoundingBox();
665: if (!request.getSrs().equalsIgnoreCase("EPSG:4326")) {
666: // transform the bounding box of the request to EPSG:4326
667: GeoTransformer gt = new GeoTransformer(CRSFactory
668: .create("epsg:4326"));
669: bbox = gt.transform(bbox, reqCRS);
670: }
671: if (!bbox.intersects(layerBbox)) {
672: LOG
673: .logDebug("Not showing layer because the request is out of the bounding box.");
674: return false;
675: }
676:
677: } catch (Exception e) {
678: LOG.logError(e.getMessage(), e);
679: throw new OGCWebServiceException(Messages
680: .getMessage("WMS_BBOXCOMPARSION"));
681: }
682:
683: return true;
684: }
685:
686: /**
687: * renders the map from the <tt>DisplayElement</tt>s
688: */
689: private GetMapResult renderMap(
690: List<ExecutionFinishedEvent<Object>> results) {
691:
692: GetMapResult response = null;
693: OGCWebServiceException exce = null;
694:
695: ArrayList<Object> list = new ArrayList<Object>(50);
696: for (ExecutionFinishedEvent<Object> evt : results) {
697: Object o = null;
698:
699: // exception handling might be handled in a better way
700: try {
701: o = evt.getResult();
702: } catch (CancellationException e) {
703: exce = new OGCWebServiceException(getClass().getName(),
704: e.toString());
705: } catch (Throwable e) {
706: exce = new OGCWebServiceException(getClass().getName(),
707: e.toString());
708: }
709:
710: if (o instanceof Exception) {
711: exce = new OGCWebServiceException(getClass().getName(),
712: o.toString());
713: }
714: if (o instanceof OGCWebServiceException) {
715: exce = (OGCWebServiceException) o;
716: break;
717: }
718: if (o != null) {
719: list.add(o);
720: }
721: }
722:
723: String mime = MimeTypeMapper.toMimeType(request.getFormat());
724:
725: // get target object for rendering
726: Object target = GraphicContextFactory.createGraphicTarget(mime,
727: request.getWidth(), request.getHeight());
728:
729: // get graphic context of the target
730: Graphics g = GraphicContextFactory.createGraphicContext(mime,
731: target);
732: if (exce == null) {
733: // only if no exception occured
734: try {
735: Theme[] th = list.toArray(new Theme[list.size()]);
736: org.deegree.graphics.MapView map = null;
737: if (th.length > 0) {
738: map = MapFactory.createMapView("deegree WMS",
739: request.getBoundingBox(), reqCRS, th,
740: MapUtils.DEFAULT_PIXEL_SIZE);
741: }
742: g
743: .setClip(0, 0, request.getWidth(), request
744: .getHeight());
745:
746: if (!request.getTransparency()) {
747: if (g instanceof Graphics2D) {
748: // this ensures real clearing (rendering modifies the color ever so
749: // slightly)
750: ((Graphics2D) g).setBackground(request
751: .getBGColor());
752: g.clearRect(0, 0, request.getWidth(), request
753: .getHeight());
754: } else {
755: g.setColor(request.getBGColor());
756: g.fillRect(0, 0, request.getWidth(), request
757: .getHeight());
758: }
759: }
760:
761: if (map != null) {
762: Theme[] thms = map.getAllThemes();
763: map.addOptimizer(new LabelOptimizer(thms));
764: // antialiasing must be switched of for gif output format
765: // because the antialiasing may create more than 255 colors
766: // in the map/image, even just a few colors are defined in
767: // the styles
768: if (!request.getFormat().equalsIgnoreCase(
769: "image/gif")) {
770: if (configuration.getDeegreeParams()
771: .isAntiAliased()) {
772: ((Graphics2D) g).setRenderingHint(
773: RenderingHints.KEY_ANTIALIASING,
774: RenderingHints.VALUE_ANTIALIAS_ON);
775: ((Graphics2D) g)
776: .setRenderingHint(
777: RenderingHints.KEY_TEXT_ANTIALIASING,
778: RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
779: }
780: }
781: map.paint(g);
782: }
783: } catch (Exception e) {
784: LOG.logError(e.getMessage(), e);
785: exce = new OGCWebServiceException(
786: "GetMapHandler_Impl: renderMap", e.toString());
787: }
788: }
789:
790: // print a copyright note at the left lower corner of the map
791: printCopyright(g, request.getHeight());
792:
793: if (mime.equals("image/svg+xml")
794: || mime.equals("image/svg xml")) {
795: Element root = ((SVGGraphics2D) g).getRoot();
796: root.setAttribute("xmlns:xlink",
797: "http://www.w3.org/1999/xlink");
798: response = WMSProtocolFactory.createGetMapResponse(request,
799: exce, root);
800: } else {
801: response = WMSProtocolFactory.createGetMapResponse(request,
802: exce, target);
803: }
804: g.dispose();
805:
806: return response;
807: }
808:
809: /**
810: * prints a copyright note at left side of the map bottom. The copyright note will be extracted
811: * from the WMS capabilities/configuration
812: *
813: * @param g
814: * graphic context of the map
815: * @param heigth
816: * height of the map in pixel
817: */
818: private void printCopyright(Graphics g, int heigth) {
819: WMSDeegreeParams dp = configuration.getDeegreeParams();
820: String copyright = dp.getCopyRight();
821: if (copyrightImg != null) {
822: g.drawImage(copyrightImg, 8, heigth
823: - copyrightImg.getHeight() - 5, null);
824: } else {
825: if (copyright != null) {
826: g.setFont(new Font("SANSSERIF", Font.PLAIN, 14));
827: g.setColor(Color.BLACK);
828: g.drawString(copyright, 8, heigth - 15);
829: g.drawString(copyright, 10, heigth - 15);
830: g.drawString(copyright, 8, heigth - 13);
831: g.drawString(copyright, 10, heigth - 13);
832: g.setColor(Color.WHITE);
833: g.setFont(new Font("SANSSERIF", Font.PLAIN, 14));
834: g.drawString(copyright, 9, heigth - 14);
835: }
836: }
837:
838: }
839:
840: /**
841: * @return the request that is being handled
842: */
843: protected GetMap getRequest() {
844: return request;
845: }
846:
847: /**
848: * @return the requests coordinate system
849: */
850: protected CoordinateSystem getRequestCRS() {
851: return reqCRS;
852: }
853:
854: }
|