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