001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wms/GetMapServiceInvokerForNL.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.Graphics;
047    import java.awt.image.BufferedImage;
048    import java.io.StringReader;
049    import java.net.URI;
050    import java.util.ArrayList;
051    import java.util.Iterator;
052    import java.util.List;
053    import java.util.Map;
054    import java.util.concurrent.Callable;
055    import java.util.concurrent.CancellationException;
056    
057    import org.deegree.datatypes.QualifiedName;
058    import org.deegree.datatypes.Types;
059    import org.deegree.framework.concurrent.DoServiceTask;
060    import org.deegree.framework.concurrent.Executor;
061    import org.deegree.framework.log.ILogger;
062    import org.deegree.framework.log.LoggerFactory;
063    import org.deegree.framework.util.CharsetUtils;
064    import org.deegree.framework.util.IDGenerator;
065    import org.deegree.framework.xml.XMLFragment;
066    import org.deegree.framework.xml.XMLTools;
067    import org.deegree.graphics.MapFactory;
068    import org.deegree.graphics.Theme;
069    import org.deegree.graphics.sld.NamedLayer;
070    import org.deegree.graphics.sld.StyleUtils;
071    import org.deegree.graphics.sld.UserStyle;
072    import org.deegree.i18n.Messages;
073    import org.deegree.model.coverage.grid.GridCoverage;
074    import org.deegree.model.coverage.grid.ImageGridCoverage;
075    import org.deegree.model.crs.CRSFactory;
076    import org.deegree.model.crs.CRSTransformationException;
077    import org.deegree.model.crs.GeoTransformer;
078    import org.deegree.model.crs.UnknownCRSException;
079    import org.deegree.model.feature.Feature;
080    import org.deegree.model.feature.FeatureCollection;
081    import org.deegree.model.feature.FeatureProperty;
082    import org.deegree.model.feature.schema.FeatureType;
083    import org.deegree.model.feature.schema.PropertyType;
084    import org.deegree.model.filterencoding.ComplexFilter;
085    import org.deegree.model.filterencoding.FeatureFilter;
086    import org.deegree.model.filterencoding.FeatureId;
087    import org.deegree.model.filterencoding.Filter;
088    import org.deegree.model.spatialschema.Envelope;
089    import org.deegree.model.spatialschema.GMLGeometryAdapter;
090    import org.deegree.model.spatialschema.Geometry;
091    import org.deegree.model.spatialschema.GeometryException;
092    import org.deegree.model.spatialschema.WKTAdapter;
093    import org.deegree.ogcbase.PropertyPath;
094    import org.deegree.ogcbase.PropertyPathFactory;
095    import org.deegree.ogcwebservices.InconsistentRequestException;
096    import org.deegree.ogcwebservices.OGCWebService;
097    import org.deegree.ogcwebservices.OGCWebServiceException;
098    import org.deegree.ogcwebservices.OGCWebServiceRequest;
099    import org.deegree.ogcwebservices.wcs.WCSException;
100    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
101    import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage;
102    import org.deegree.ogcwebservices.wfs.RemoteWFService;
103    import org.deegree.ogcwebservices.wfs.WFService;
104    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
105    import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType;
106    import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
107    import org.deegree.ogcwebservices.wfs.operation.GetFeature;
108    import org.deegree.ogcwebservices.wfs.operation.Query;
109    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
110    import org.deegree.ogcwebservices.wms.configuration.LocalWCSDataSource;
111    import org.deegree.ogcwebservices.wms.configuration.LocalWFSDataSource;
112    import org.deegree.ogcwebservices.wms.configuration.RemoteWMSDataSource;
113    import org.deegree.ogcwebservices.wms.operation.GetMap;
114    import org.deegree.ogcwebservices.wms.operation.GetMapResult;
115    import org.w3c.dom.Document;
116    
117    /**
118     * Class for accessing the data of one layers datasource and creating a <tt>Theme</tt> from it.
119     * 
120     * @version $Revision: 14370 $
121     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
122     * @author last edited by: $Author: aschmitz $
123     * 
124     * @version 1.0. $Revision: 14370 $, $Date: 2008-10-21 16:32:54 +0200 (Di, 21. Okt 2008) $
125     * 
126     * @since 2.0
127     */
128    public class GetMapServiceInvokerForNL extends GetMapServiceInvoker implements Callable<Object> {
129    
130        private static final ILogger LOG = LoggerFactory.getLogger( GetMapServiceInvokerForNL.class );
131    
132        private final GetMap request;
133    
134        private NamedLayer layer = null;
135    
136        private UserStyle style = null;
137    
138        private AbstractDataSource datasource = null;
139    
140        /**
141         * Creates a new ServiceInvokerForNL object.
142         * 
143         * @param handler
144         * @param layer
145         * @param datasource
146         * @param style
147         * @param index
148         */
149        GetMapServiceInvokerForNL( DefaultGetMapHandler handler, NamedLayer layer, AbstractDataSource datasource,
150                                   UserStyle style, double scale ) {
151    
152            super( handler, scale );
153    
154            this.layer = layer;
155            this.request = handler.getRequest();
156            this.style = style;
157            this.datasource = datasource;
158        }
159    
160        public Object call() {
161    
162            Object response = null;
163            if ( datasource != null ) {
164                OGCWebServiceRequest request = null;
165                try {
166                    int type = datasource.getType();
167                    switch ( type ) {
168                    case AbstractDataSource.LOCALWFS:
169                    case AbstractDataSource.REMOTEWFS: {
170                        request = createGetFeatureRequest( (LocalWFSDataSource) datasource );
171                        break;
172                    }
173                    case AbstractDataSource.LOCALWCS:
174                    case AbstractDataSource.REMOTEWCS: {
175                        request = createGetCoverageRequest( datasource, this.request );
176                        break;
177                    }
178                    case AbstractDataSource.REMOTEWMS: {
179                        String styleName = null;
180    
181                        if ( style != null ) {
182                            styleName = style.getName();
183                        }
184    
185                        request = GetMap.createGetMapRequest( datasource, handler.getRequest(), styleName, layer.getName() );
186                        LOG.logDebug( "GetMap request: " + request.toString() );
187                        break;
188                    }
189                    }
190                } catch ( Exception e ) {
191                    e.printStackTrace();
192                    OGCWebServiceException exce = new OGCWebServiceException( getClass().getName(),
193                                                                              Messages.getMessage( "WMS_ERRORQUERYCREATE",
194                                                                                                   e ) );
195                    // exception can't be re-thrown because responsible GetMapHandler
196                    // must collect all responses of all datasources
197                    response = exce;
198                    LOG.logError( e.getMessage(), e );
199                }
200    
201                try {
202                    // start reading data with a limited time frame. The time limit
203                    // readed from the datasource muts be multiplied by 1000 because
204                    // the method expects milliseconds as timelimit
205                    Executor executor = Executor.getInstance();
206                    DoServiceTask<Object> task = new DoServiceTask<Object>( datasource.getOGCWebService(), request );
207                    Object o = executor.performSynchronously( task, datasource.getRequestTimeLimit() * 1000 );
208                    response = handleResponse( o );
209                } catch ( CancellationException e ) {
210                    // exception can't be re-thrown because responsible GetMapHandler
211                    // must collect all responses of all datasources
212                    String s = Messages.getMessage( "WMS_TIMEOUTDATASOURCE", new Integer( datasource.getRequestTimeLimit() ) );
213                    LOG.logError( s, e );
214                    if ( datasource.isFailOnException() ) {
215                        OGCWebServiceException exce = new OGCWebServiceException( getClass().getName(), s );
216                        response = exce;
217                    } else {
218                        response = null;
219                    }
220                } catch ( Throwable e ) {
221                    // exception can't be re-thrown because responsible GetMapHandler
222                    // must collect all responses of all datasources
223                    String s = Messages.getMessage( "WMS_ERRORDOSERVICE", e.getMessage() );
224                    LOG.logError( s, e );
225                    if ( datasource.isFailOnException() ) {
226                        OGCWebServiceException exce = new OGCWebServiceException( getClass().getName(), s );
227                        response = exce;
228                    } else {
229                        response = null;
230                    }
231                }
232            }
233    
234            LOG.logDebug( "Layer " + layer.getName() + " returned." );
235    
236            return response;
237        }
238    
239        /**
240         * creates a getFeature request considering the getMap request and the filterconditions defined in the submitted
241         * <tt>DataSource</tt> object. The request will be encapsualted within a <tt>OGCWebServiceEvent</tt>.
242         * 
243         * @param ds
244         * @return GetFeature request object
245         * @throws Exception
246         */
247        private GetFeature createGetFeatureRequest( LocalWFSDataSource ds )
248                                throws Exception {
249    
250            Envelope bbox = transformBBOX( ds );
251    
252            List<PropertyPath> pp = null;
253            if ( style != null ) {
254                List<UserStyle> styleList = new ArrayList<UserStyle>();
255                styleList.add( style );
256                pp = StyleUtils.extractRequiredProperties( styleList, scaleDen );
257            } else {
258                pp = new ArrayList<PropertyPath>();
259            }
260            PropertyPath geomPP = PropertyPathFactory.createPropertyPath( ds.getGeometryProperty() );
261            if ( !pp.contains( geomPP ) ) {
262                pp.add( geomPP );
263            }
264    
265            LOG.logDebug( "required properties: ", pp );
266            Map<String, URI> namesp = extractNameSpaceDef( pp );
267    
268            // no filter condition has been defined
269            StringBuffer sb = new StringBuffer( 5000 );
270            sb.append( "<?xml version='1.0' encoding='" + CharsetUtils.getSystemCharset() + "'?>" );
271            sb.append( "<GetFeature xmlns='http://www.opengis.net/wfs' " );
272            sb.append( "xmlns:ogc='http://www.opengis.net/ogc' " );
273            sb.append( "xmlns:gml='http://www.opengis.net/gml' " );
274            sb.append( "xmlns:" ).append( ds.getName().getPrefix() ).append( '=' );
275            sb.append( "'" ).append( ds.getName().getNamespace() ).append( "' " );
276            Iterator<String> iter = namesp.keySet().iterator();
277            while ( iter.hasNext() ) {
278                String pre = iter.next();
279                URI nsp = namesp.get( pre );
280                if ( !pre.equals( "xmlns" ) && !pre.equals( ds.getName().getPrefix() ) ) {
281                    sb.append( "xmlns:" ).append( pre ).append( "='" );
282                    sb.append( nsp.toASCIIString() ).append( "' " );
283                }
284            }
285    
286            sb.append( "service='WFS' version='1.1.0' " );
287            if ( ds.getType() == AbstractDataSource.LOCALWFS ) {
288                sb.append( "outputFormat='FEATURECOLLECTION'>" );
289            } else {
290                sb.append( "outputFormat='text/xml; subtype=gml/3.1.1'>" );
291            }
292            sb.append( "<Query typeName='" + ds.getName().getPrefixedName() + "'>" );
293    
294            for ( int j = 0; j < pp.size(); j++ ) {
295                if ( !pp.get( j ).getAsString().endsWith( "$SCALE" ) ) {
296                    // $SCALE is a dynamicly created property of each feature
297                    // and can not be requested
298                    sb.append( "<PropertyName>" ).append( pp.get( j ).getAsString() );
299                    sb.append( "</PropertyName>" );
300                }
301            }
302    
303            Query query = ds.getQuery();
304            if ( query == null ) {
305                sb.append( "<ogc:Filter><ogc:BBOX>" );
306                sb.append( "<PropertyName>" );
307                sb.append( ds.getGeometryProperty().getPrefixedName() );
308                sb.append( "</PropertyName>" );
309                sb.append( GMLGeometryAdapter.exportAsBox( bbox ) );
310                sb.append( "</ogc:BBOX>" );
311                sb.append( "</ogc:Filter></Query></GetFeature>" );
312            } else {
313                Filter filter = query.getFilter();
314                sb.append( "<ogc:Filter>" );
315                if ( filter instanceof ComplexFilter ) {
316                    sb.append( "<ogc:And>" );
317                    sb.append( "<ogc:BBOX>" );
318                    sb.append( "<PropertyName>" );
319                    sb.append( ds.getGeometryProperty().getPrefixedName() );
320                    sb.append( "</PropertyName>" );
321                    sb.append( GMLGeometryAdapter.exportAsBox( bbox ) );
322                    sb.append( "</ogc:BBOX>" );
323    
324                    // add filter as defined in the layers datasource description
325                    // to the filter expression
326                    org.deegree.model.filterencoding.Operation op = ( (ComplexFilter) filter ).getOperation();
327                    sb.append( op.toXML() ).append( "</ogc:And>" );
328                } else {
329                    ArrayList<FeatureId> featureIds = ( (FeatureFilter) filter ).getFeatureIds();
330                    if ( featureIds.size() > 1 ) {
331                        sb.append( "<ogc:And>" );
332                    }
333                    for ( int i = 0; i < featureIds.size(); i++ ) {
334                        FeatureId fid = featureIds.get( i );
335                        sb.append( fid.toXML() );
336                    }
337                    if ( featureIds.size() > 1 ) {
338                        sb.append( "</ogc:And>" );
339                    }
340                }
341                sb.append( "</ogc:Filter></Query></GetFeature>" );
342            }
343    
344            // create dom representation of the request
345            Document doc = XMLTools.parse( new StringReader( sb.toString() ) );
346    
347            LOG.logDebug( "GetFeature request: " + new XMLFragment( doc, "http://www.systemid.org" ).getAsPrettyString() );
348    
349            // create OGCWebServiceEvent object
350            IDGenerator idg = IDGenerator.getInstance();
351            GetFeature gfr = GetFeature.create( "" + idg.generateUniqueID(), doc.getDocumentElement() );
352    
353            return gfr;
354        }
355    
356        /**
357         * transforms the requested BBOX into the DefaultSRS of the assigend feature type
358         * 
359         * @param ds
360         * @return the envelope
361         * @throws OGCWebServiceException
362         * @throws CRSTransformationException
363         * @throws UnknownCRSException
364         */
365        private Envelope transformBBOX( LocalWFSDataSource ds )
366                                throws OGCWebServiceException, CRSTransformationException, UnknownCRSException {
367            Envelope bbox = request.getBoundingBox();
368            // transform request bounding box to the coordinate reference
369            // system the WFS holds the data if requesting CRS and WFS-Data
370            // crs are different
371            OGCWebService service = ds.getOGCWebService();
372            WFSCapabilities capa;
373            if ( service instanceof RemoteWFService ) {
374                RemoteWFService wfs = (RemoteWFService) service;
375                capa = wfs.getWFSCapabilities();
376            } else {
377                WFService wfs = (WFService) service;
378                capa = wfs.getCapabilities();
379            }
380            // WFSCapabilities capa = (WFSCapabilities)wfs.getWFSCapabilities();
381            QualifiedName gn = ds.getName();
382            WFSFeatureType ft = capa.getFeatureTypeList().getFeatureType( gn );
383    
384            if ( ft == null ) {
385                throw new OGCWebServiceException( Messages.getMessage( "WMS_UNKNOWNFT", ds.getName() ) );
386            }
387    
388            // enable different formatations of the crs encoding for GML geometries
389            String GML_SRS = "http://www.opengis.net/gml/srs/";
390            String old_gml_srs = ft.getDefaultSRS().toASCIIString();
391            String old_srs;
392            if ( old_gml_srs.startsWith( GML_SRS ) ) {
393                old_srs = old_gml_srs.substring( 31 ).replace( '#', ':' ).toUpperCase();
394            } else {
395                old_srs = old_gml_srs;
396            }
397    
398            String new_srs = request.getSrs();
399            String new_gml_srs;
400            if ( old_gml_srs.startsWith( GML_SRS ) ) {
401                new_gml_srs = GML_SRS + new_srs.replace( ':', '#' ).toLowerCase();
402            } else {
403                new_gml_srs = new_srs;
404            }
405    
406            if ( !( old_srs.equalsIgnoreCase( new_gml_srs ) ) ) {
407                GeoTransformer transformer = new GeoTransformer( CRSFactory.create( old_srs ) );
408                bbox = transformer.transform( bbox, this.handler.getRequestCRS() );
409            }
410            return bbox;
411        }
412    
413        /**
414         * creates a getCoverage request considering the getMap request and the filterconditions defined in the submitted
415         * <tt>DataSource</tt> object The request will be encapsualted within a <tt>OGCWebServiceEvent</tt>.
416         * 
417         * @param ds
418         * @return GetCoverage request object
419         * @throws InconsistentRequestException
420         */
421        protected static GetCoverage createGetCoverageRequest( AbstractDataSource ds, GetMap request )
422                                throws InconsistentRequestException {
423    
424            Envelope bbox = request.getBoundingBox();
425    
426            GetCoverage gcr = ( (LocalWCSDataSource) ds ).getGetCoverageRequest();
427    
428            String crs = request.getSrs();
429            // if (gcr != null && gcr.getDomainSubset().getRequestSRS() != null) {
430            // crs = gcr.getDomainSubset().getRequestSRS().getCode();
431            // }
432            String format = request.getFormat();
433            int pos = format.indexOf( '/' );
434            if ( pos > -1 )
435                format = format.substring( pos + 1, format.length() );
436            if ( gcr != null && !"%default%".equals( gcr.getOutput().getFormat().getCode() ) ) {
437                format = gcr.getOutput().getFormat().getCode();
438            }
439            if ( format.indexOf( "svg" ) > -1 ) {
440                format = "tiff";
441            }
442    
443            String version = "1.0.0";
444            if ( gcr != null && gcr.getVersion() != null ) {
445                version = gcr.getVersion();
446            }
447            String lay = ds.getName().getPrefixedName();
448            if ( gcr != null && !"%default%".equals( gcr.getSourceCoverage() ) ) {
449                lay = gcr.getSourceCoverage();
450            }
451            String ipm = null;
452            if ( gcr != null && gcr.getInterpolationMethod() != null ) {
453                ipm = gcr.getInterpolationMethod().value;
454            }
455    
456            // TODO
457            // handle rangesets e.g. time and elevation
458            StringBuffer sb = new StringBuffer( 1000 );
459            sb.append( "service=WCS&request=GetCoverage" );
460            sb.append( "&version=" ).append( version );
461            sb.append( "&COVERAGE=" ).append( lay );
462            sb.append( "&crs=" ).append( crs );
463            sb.append( "&response_crs=" ).append( crs );
464            sb.append( "&BBOX=" ).append( bbox.getMin().getX() ).append( ',' );
465            sb.append( bbox.getMin().getY() ).append( ',' ).append( bbox.getMax().getX() );
466            sb.append( ',' ).append( bbox.getMax().getY() );
467            sb.append( "&WIDTH=" ).append( request.getWidth() );
468            sb.append( "&HEIGHT=" ).append( request.getHeight() );
469            sb.append( "&FORMAT=" ).append( format );
470            sb.append( "&INTERPOLATIONMETHOD=" ).append( ipm );
471            try {
472                IDGenerator idg = IDGenerator.getInstance();
473                gcr = GetCoverage.create( "id" + idg.generateUniqueID(), sb.toString() );
474            } catch ( WCSException e ) {
475                throw new InconsistentRequestException( e.getMessage() );
476            } catch ( org.deegree.ogcwebservices.OGCWebServiceException e ) {
477                throw new InconsistentRequestException( e.getMessage() );
478            }
479    
480            LOG.logDebug( "GetCoverage request: " + sb.toString() );
481    
482            return gcr;
483    
484        }
485    
486        /**
487         * 
488         * @param result
489         * @return the response objects
490         * @throws Exception
491         */
492        private Object handleResponse( Object result )
493                                throws Exception {
494    
495            Object theme = null;
496            if ( result instanceof ResultCoverage ) {
497                theme = handleGetCoverageResponse( (ResultCoverage) result );
498            } else if ( result instanceof FeatureResult ) {
499                theme = handleGetFeatureResponse( (FeatureResult) result );
500            } else if ( result instanceof GetMapResult ) {
501                theme = handleGetMapResponse( (GetMapResult) result );
502            } else {
503                String s = Messages.getMessage( "WMS_UNKNOWNRESPONSEFORMAT" );
504                if ( datasource.isFailOnException() ) {
505                    OGCWebServiceException exce = new OGCWebServiceException( getClass().getName(), s );
506                    theme = exce;
507                } else {
508                    theme = null;
509                }
510            }
511            return theme;
512        }
513    
514        /**
515         * replaces all pixels within the passed image having a color that is defined to be transparent within their
516         * datasource with a transparent color.
517         * 
518         * @param img
519         * @return modified image
520         */
521        private BufferedImage setTransparentColors( BufferedImage img ) {
522    
523            Color[] colors = null;
524            if ( datasource.getType() == AbstractDataSource.LOCALWCS ) {
525                LocalWCSDataSource ds = (LocalWCSDataSource) datasource;
526                colors = ds.getTransparentColors();
527            } else {
528                RemoteWMSDataSource ds = (RemoteWMSDataSource) datasource;
529                colors = ds.getTransparentColors();
530            }
531    
532            if ( colors != null && colors.length > 0 ) {
533    
534                int[] clrs = new int[colors.length];
535                for ( int i = 0; i < clrs.length; i++ ) {
536                    clrs[i] = colors[i].getRGB();
537                }
538    
539                if ( img.getType() != BufferedImage.TYPE_INT_ARGB ) {
540                    // if the incoming image does not allow transparency
541                    // it must be copyed to a image of ARGB type
542                    BufferedImage tmp = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB );
543                    Graphics g = tmp.getGraphics();
544                    g.drawImage( img, 0, 0, null );
545                    g.dispose();
546                    img = tmp;
547                }
548    
549                // TODO
550                // should be replaced by a JAI operation
551                int w = img.getWidth();
552                int h = img.getHeight();
553                for ( int i = 0; i < w; i++ ) {
554                    for ( int j = 0; j < h; j++ ) {
555                        int col = img.getRGB( i, j );
556                        if ( shouldBeTransparent( colors, col ) ) {
557                            img.setRGB( i, j, 0x00FFFFFF );
558                        }
559                    }
560                }
561    
562            }
563    
564            return img;
565        }
566    
567        /**
568         * @return true if the distance between the image color and at least of the colors to be truned to be transparent is
569         *         less than 3 in an int RGB cube
570         * 
571         * @param colors
572         * @param color
573         */
574        private boolean shouldBeTransparent( Color[] colors, int color ) {
575            Color c2 = new Color( color );
576            int r = c2.getRed();
577            int g = c2.getGreen();
578            int b = c2.getBlue();
579            for ( int i = 0; i < colors.length; i++ ) {
580                int r1 = colors[i].getRed();
581                int g1 = colors[i].getGreen();
582                int b1 = colors[i].getBlue();
583                if ( Math.sqrt( ( r1 - r ) * ( r1 - r ) + ( g1 - g ) * ( g1 - g ) + ( b1 - b ) * ( b1 - b ) ) < 3 ) {
584                    return true;
585                }
586            }
587            return false;
588        }
589    
590        /**
591         * handles the response of a cascaded WMS and calls a factory to create <tt>DisplayElement</tt> and a <tt>Theme</tt>
592         * from it
593         * 
594         * @param response
595         * @return the response objects
596         * @throws Exception
597         */
598        private Object handleGetMapResponse( GetMapResult response )
599                                throws Exception {
600    
601            BufferedImage bi = (BufferedImage) response.getMap();
602    
603            bi = setTransparentColors( bi );
604            GridCoverage gc = new ImageGridCoverage( null, request.getBoundingBox(), bi );
605            org.deegree.graphics.Layer rl = MapFactory.createRasterLayer( layer.getName(), gc );
606            Theme theme = MapFactory.createTheme( datasource.getName().getPrefixedName(), rl, new UserStyle[] { style } );
607            return theme;
608    
609        }
610    
611        /**
612         * handles the response of a WFS and calls a factory to create <tt>DisplayElement</tt> and a <tt>Theme</tt> from it
613         * 
614         * @param response
615         * @return the response objects
616         * @throws Exception
617         */
618        private Object handleGetFeatureResponse( FeatureResult response )
619                                throws Exception {
620    
621            FeatureCollection fc = null;
622    
623            Object o = response.getResponse();
624            if ( o instanceof FeatureCollection ) {
625                fc = (FeatureCollection) o;
626            } else {
627                throw new Exception( Messages.getMessage( "WMS_UNKNOWNDATAFORMATFT" ) );
628            }
629            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
630                LOG.logDebug( "result: " + fc );
631                for ( int i = 0; i < fc.size(); ++i ) {
632                    outputGeometries( fc.getFeature( i ) );
633                }
634            }
635    
636            org.deegree.graphics.Layer fl = MapFactory.createFeatureLayer( layer.getName(), this.handler.getRequestCRS(),
637                                                                           fc );
638    
639            return MapFactory.createTheme( datasource.getName().getPrefixedName(), fl, new UserStyle[] { style } );
640        }
641    
642        private void outputGeometries( Feature feature ) {
643            if ( feature == null ) {
644                return;
645            }
646            FeatureType ft = feature.getFeatureType();
647            PropertyType[] propertyTypes = ft.getProperties();
648            for ( PropertyType pt : propertyTypes ) {
649                if ( pt.getType() == Types.FEATURE ) {
650                    FeatureProperty[] fp = feature.getProperties( pt.getName() );
651                    if ( fp != null ) {
652                        for ( int i = 0; i < fp.length; i++ ) {
653                            outputGeometries( (Feature) fp[i].getValue() );
654                        }
655                    }
656                } else if ( pt.getType() == Types.GEOMETRY ) {
657                    Geometry g = feature.getDefaultGeometryPropertyValue();
658                    if ( g != null ) {
659                        try {
660                            LOG.logDebug( "geometrie: " + WKTAdapter.export( g ).toString() );
661                        } catch ( GeometryException e ) {
662                            LOG.logDebug( "Geometry couldn't be converted to Well Known Text: " + g );
663                        }
664                    }
665                }
666            }
667        }
668    
669        /**
670         * handles the response of a WCS and calls a factory to create <tt>DisplayElement</tt> and a <tt>Theme</tt> from it
671         * 
672         * @param response
673         * @return the response objects
674         * @throws Exception
675         */
676        private Object handleGetCoverageResponse( ResultCoverage response )
677                                throws Exception {
678            ImageGridCoverage gc = (ImageGridCoverage) response.getCoverage();
679            Object ro = null;
680            if ( gc != null ) {
681                BufferedImage bi = gc.getAsImage( -1, -1 );
682    
683                bi = setTransparentColors( bi );
684    
685                gc = new ImageGridCoverage( null, request.getBoundingBox(), bi );
686    
687                org.deegree.graphics.Layer rl = MapFactory.createRasterLayer( layer.getName(), gc );
688    
689                ro = MapFactory.createTheme( datasource.getName().getPrefixedName(), rl, new UserStyle[] { style } );
690            } else {
691                throw new OGCWebServiceException( getClass().getName(), Messages.getMessage( "WMS_NOCOVERAGE",
692                                                                                             datasource.getName() ) );
693            }
694            return ro;
695        }
696    
697    }