001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wpvs/WCSInvoker.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.ogcwebservices.wpvs;
038    
039    import java.awt.Color;
040    import java.awt.Graphics2D;
041    import java.awt.Image;
042    import java.awt.image.BufferedImage;
043    import java.io.File;
044    import java.io.IOException;
045    import java.util.HashMap;
046    import java.util.Map;
047    
048    import javax.imageio.ImageIO;
049    import javax.media.jai.JAI;
050    import javax.media.jai.PlanarImage;
051    import javax.media.jai.operator.TransposeDescriptor;
052    
053    import org.deegree.datatypes.Code;
054    import org.deegree.framework.log.ILogger;
055    import org.deegree.framework.log.LoggerFactory;
056    import org.deegree.framework.util.IDGenerator;
057    import org.deegree.i18n.Messages;
058    import org.deegree.model.coverage.grid.ImageGridCoverage;
059    import org.deegree.model.spatialschema.Envelope;
060    import org.deegree.model.spatialschema.Position;
061    import org.deegree.ogcwebservices.OGCWebServiceException;
062    import org.deegree.ogcwebservices.wcs.WCSException;
063    import org.deegree.ogcwebservices.wcs.WCService;
064    import org.deegree.ogcwebservices.wcs.getcoverage.DomainSubset;
065    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
066    import org.deegree.ogcwebservices.wcs.getcoverage.Output;
067    import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage;
068    import org.deegree.ogcwebservices.wcs.getcoverage.SpatialSubset;
069    import org.deegree.ogcwebservices.wpvs.configuration.AbstractDataSource;
070    import org.deegree.ogcwebservices.wpvs.configuration.LocalWCSDataSource;
071    import org.deegree.ogcwebservices.wpvs.utils.ImageUtils;
072    import org.deegree.ogcwebservices.wpvs.utils.ResolutionStripe;
073    
074    /**
075     * Invoker for a Web Coverage Service.
076     *
077     * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
078     * @author last edited by: $Author: mschneider $
079     *
080     * $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $
081     */
082    public class WCSInvoker extends GetViewServiceInvoker {
083    
084        private static final ILogger LOG = LoggerFactory.getLogger( WCSInvoker.class );
085    
086        /* the rank represent the order in whoch the image will be painted */
087        private int id;
088    
089        /* whether the image will be used as texture or as data for the elevation model */
090        private final boolean isElevationModelRequest;
091    
092        private String requestFormat;
093    
094        /**
095         * Creates a new instance of this class.
096         *
097         * @param owner
098         *            the handler that owns this invoker
099         * @param id
100         * @param requestFormat
101         * @param isElevationModelRequest
102         */
103        public WCSInvoker( ResolutionStripe owner, int id, String requestFormat, boolean isElevationModelRequest ) {
104            super( owner );
105            this.id = id;
106            this.isElevationModelRequest = isElevationModelRequest;
107            this.requestFormat = requestFormat;
108        }
109    
110        @Override
111        public void invokeService( AbstractDataSource dataSource ) {
112    
113            if ( !( dataSource instanceof LocalWCSDataSource ) ) {
114                LOG.logError( "The given AbstractDataSource is no WCSDataSource instance. It is needed for a WCSInvoker" );
115                throw new RuntimeException( "DataSource should be a WCS-instance for a WCSInvoker" );
116            }
117    
118            WCService service = null;
119            try {
120                service = (WCService) dataSource.getOGCWebService();
121            } catch ( OGCWebServiceException ogcwe ) {
122                LOG.logError( ogcwe.getMessage() );
123                throw new RuntimeException( ogcwe );
124            }
125            if ( service == null ) {
126                throw new RuntimeException( "No Web Coverage Service instance available for WCSInvoker" );
127            }
128    
129            Object coverageResponse = null;
130    
131            // check if the admin has configured a minimal dgm resolution, if so the request and
132            // response resolution for the dgm must be set.
133            int requestWidth = resolutionStripe.getRequestWidthForBBox();
134            int requestHeight = resolutionStripe.getRequestHeightForBBox();
135            if ( isElevationModelRequest ) {
136                double minRes = ( (LocalWCSDataSource) dataSource ).getConfiguredMinimalDGMResolution();
137                LOG.logDebug( "configured minimalResolution: " + minRes );
138                if ( minRes > 0.0000001 ) {// 0d if not set
139                    Envelope env = resolutionStripe.getSurface().getEnvelope();
140                    if ( ( env.getWidth() / requestWidth ) < minRes ) {
141                        requestWidth = (int) ( env.getWidth() / minRes );
142                    }
143                    if ( ( env.getHeight() / requestHeight ) < minRes ) {
144                        requestHeight = (int) ( env.getHeight() / minRes );
145                    }
146                }
147            }
148    
149            try {
150                GetCoverage getCoverageRequest = createGetCoverageRequest(
151                                                                           ( (LocalWCSDataSource) dataSource ).getCoverageFilterCondition(),
152                                                                           ( (LocalWCSDataSource) dataSource ).getDefaultFormat(),
153                                                                           requestWidth, requestHeight );
154                LOG.logDebug( "WCS request:" + getCoverageRequest );
155                coverageResponse = service.doService( getCoverageRequest );
156            } catch ( WCSException wcse ) {
157                if ( !Thread.currentThread().isInterrupted() ) {
158                    LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR", "WCSException", dataSource.getName(),
159                                                       wcse.getMessage() ) );
160                    if ( !isElevationModelRequest ) {
161                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id, wcse );
162                    }
163                }
164                return;
165            } catch ( OGCWebServiceException ogcwse ) {
166                if ( !Thread.currentThread().isInterrupted() ) {
167                    LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR", "OGCWebServiceException",
168                                                       dataSource.getName(), ogcwse.getMessage() ) );
169                    if ( !isElevationModelRequest ) {
170                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id,
171                                                                       ogcwse );
172                    }
173                }
174                return;
175            } catch ( Throwable t ) {
176                if ( !Thread.currentThread().isInterrupted() ) {
177                    t.printStackTrace();
178                }
179                return;
180            }
181            if ( coverageResponse != null && coverageResponse instanceof ResultCoverage ) {
182    
183                LOG.logDebug( "\t -> a valid response\n" );
184                ResultCoverage response = (ResultCoverage) coverageResponse;
185                if ( response.getCoverage() != null && response.getCoverage() instanceof ImageGridCoverage ) {
186                    ImageGridCoverage igc = (ImageGridCoverage) response.getCoverage();
187    
188                    BufferedImage image = igc.getAsImage( requestWidth, requestHeight );
189                    if ( !isElevationModelRequest ) {
190                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
191                            try {
192                                File f = new File( "wcs_texture_response.png" );
193                                LOG.logDebug( "creating tmpfile for wcs texture response with name: " + f.toString() );
194                                f.deleteOnExit();
195                                ImageIO.write( image, "png", f );
196                            } catch ( IOException e ) {
197                                // TODO Auto-generated catch block
198                                e.printStackTrace();
199                            }
200                        }
201                        Color[] colors = ( (LocalWCSDataSource) dataSource ).getTransparentColors();
202                        if ( colors != null && colors.length > 0 ) {
203                            ImageUtils imgUtil = new ImageUtils( colors );
204                            Image img = imgUtil.filterImage( image );
205                            Graphics2D g2d = (Graphics2D) image.getGraphics();
206                            g2d.drawImage( img, 0, 0, null );
207                            g2d.dispose();
208                        }
209    
210                        if ( !resolutionStripe.addTexture( dataSource.getName().getFormattedString() + id, image ) ) {
211                            LOG.logDebug( "could not add the texture" );
212                        }
213                    } else {
214                        // the heightdata is in x and -y coordinates, they must be flipped before using
215                        PlanarImage im2 = JAI.create( "transpose", image, TransposeDescriptor.FLIP_VERTICAL );
216                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
217                            try {
218                                File f = new File( "wcs_dgm_response.png" );
219                                LOG.logDebug( "creating tmpfile for wcs elevationmodel response with name: " + f.toString() );
220                                f.deleteOnExit();
221                                ImageIO.write( im2.getAsBufferedImage(), "png", f );
222                            } catch ( Exception e ) {
223                                // TODO Auto-generated catch block
224                                e.printStackTrace();
225                            }
226                        }
227                        resolutionStripe.setElevationModelFromHeightMap( im2.getAsBufferedImage() );
228                    }
229                } else {
230                    LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(),
231                                                         "an ImageGridCoverage" ) );
232                }
233            } else {
234                LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(), "a ResultCoverage" ) );
235            }
236    
237        }
238    
239        /**
240         * Creates a getCoverage request for the given surface
241         *
242         * @param filterCondition
243         * @param format
244         * @param requestWidth
245         *            the width of a request (which should take the configured dgm_res into account).
246         * @param requestHeight
247         *            the height of a request (which should take the configured dgm_res into account).
248         * @return a new GetCoverageRequest.
249         * @throws WCSException
250         * @throws OGCWebServiceException
251         */
252        private GetCoverage createGetCoverageRequest( GetCoverage filterCondition, String format, int requestWidth,
253                                                      int requestHeight )
254                                throws WCSException, OGCWebServiceException {
255    
256            // String format = "GeoTiff";
257            if ( !isElevationModelRequest ) {
258                if ( filterCondition.getOutput().getFormat() == null ) {
259                    // fallback if no output format has been defined for a
260                    // WCS datasource
261                    format = requestFormat;
262                } else {
263                    format = filterCondition.getOutput().getFormat().getCode();
264                }
265                int pos = format.indexOf( '/' );
266                if ( pos > -1 ) {
267                    format = format.substring( pos + 1, format.length() );
268                }
269    
270                if ( format.indexOf( "svg" ) > -1 ) {
271                    format = "png";
272                }
273            }
274            Output output = GetCoverage.createOutput( resolutionStripe.getCRSName().getFormattedString(), null, format,
275                                                      null );
276    
277            // put mising parts in this map:
278            Map<String, String> map = new HashMap<String, String>( 5 );
279    
280            StringBuffer sb = new StringBuffer( 1000 );
281            Envelope env = resolutionStripe.getSurface().getEnvelope();
282            Position p = env.getMin();
283            sb.append( p.getX() ).append( "," ).append( p.getY() ).append( "," );
284            p = env.getMax();
285            sb.append( p.getX() ).append( "," ).append( p.getY() );
286            map.put( "BBOX", sb.toString() );
287    
288            map.put( "WIDTH", String.valueOf( requestWidth ) );
289            map.put( "HEIGHT", String.valueOf( requestHeight ) );
290    
291            SpatialSubset sps = GetCoverage.createSpatialSubset( map, resolutionStripe.getCRSName().getFormattedString() );
292    
293            Code code = filterCondition.getDomainSubset().getRequestSRS();
294            DomainSubset domainSubset = new DomainSubset( code, sps, null );
295    
296            IDGenerator idg = IDGenerator.getInstance();
297    
298            GetCoverage getCoverageRequest = new GetCoverage( String.valueOf( idg.generateUniqueID() ),
299                                                              filterCondition.getVersion(),
300                                                              filterCondition.getSourceCoverage(), domainSubset, null,
301                                                              filterCondition.getInterpolationMethod(), output );
302    
303            return getCoverageRequest;
304        }
305    
306    }