001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/WCSInvoker.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 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     Aennchenstraße 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    
044    package org.deegree.ogcwebservices.wpvs;
045    
046    import java.awt.Color;
047    import java.awt.Graphics2D;
048    import java.awt.Image;
049    import java.awt.image.BufferedImage;
050    import java.io.File;
051    import java.io.IOException;
052    import java.util.HashMap;
053    import java.util.Map;
054    
055    import javax.imageio.ImageIO;
056    import javax.media.jai.JAI;
057    import javax.media.jai.PlanarImage;
058    import javax.media.jai.operator.TransposeDescriptor;
059    
060    import org.deegree.datatypes.Code;
061    import org.deegree.framework.log.ILogger;
062    import org.deegree.framework.log.LoggerFactory;
063    import org.deegree.framework.util.IDGenerator;
064    import org.deegree.i18n.Messages;
065    import org.deegree.model.coverage.grid.ImageGridCoverage;
066    import org.deegree.model.spatialschema.Envelope;
067    import org.deegree.model.spatialschema.Position;
068    import org.deegree.ogcwebservices.OGCWebServiceException;
069    import org.deegree.ogcwebservices.wcs.WCSException;
070    import org.deegree.ogcwebservices.wcs.WCService;
071    import org.deegree.ogcwebservices.wcs.getcoverage.DomainSubset;
072    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
073    import org.deegree.ogcwebservices.wcs.getcoverage.Output;
074    import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage;
075    import org.deegree.ogcwebservices.wcs.getcoverage.SpatialSubset;
076    import org.deegree.ogcwebservices.wpvs.configuration.AbstractDataSource;
077    import org.deegree.ogcwebservices.wpvs.configuration.LocalWCSDataSource;
078    import org.deegree.ogcwebservices.wpvs.utils.ImageUtils;
079    import org.deegree.ogcwebservices.wpvs.utils.ResolutionStripe;
080    
081    /**
082     * Invoker for a Web Coverage Service.
083     * 
084     * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
085     * @author last edited by: $Author: bezema $
086     * 
087     * $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
088     */
089    public class WCSInvoker extends GetViewServiceInvoker {
090    
091        private static final ILogger LOG = LoggerFactory.getLogger( WCSInvoker.class );
092    
093        /* the rank represent the order in whoch the image will be painted */
094        private int id;
095    
096        /* whether the image will be used as texture or as data for the elevation model */
097        private final boolean isElevationModelRequest;
098    
099        private String requestFormat;
100    
101        /**
102         * Creates a new instance of this class.
103         * 
104         * @param owner
105         *            the handler that owns this invoker
106         * @param id
107         * @param requestFormat
108         * @param isElevationModelRequest
109         */
110        public WCSInvoker( ResolutionStripe owner, int id, String requestFormat,
111                          boolean isElevationModelRequest ) {
112            super( owner );
113            this.id = id;
114            this.isElevationModelRequest = isElevationModelRequest;
115            this.requestFormat = requestFormat;
116        }
117    
118        @Override
119        public void invokeService( AbstractDataSource dataSource ) {
120    
121            if ( !( dataSource instanceof LocalWCSDataSource ) ) {
122                LOG.logError( "The given AbstractDataSource is no WCSDataSource instance. It is needed for a WCSInvoker" );
123                throw new RuntimeException( "DataSource should be a WCS-instance for a WCSInvoker" );
124            }
125    
126            WCService service = null;
127            try {
128                service = (WCService) dataSource.getOGCWebService();
129            } catch ( OGCWebServiceException ogcwe ) {
130                LOG.logError( ogcwe.getMessage() );
131                throw new RuntimeException( ogcwe );
132            }
133            if ( service == null ) {
134                throw new RuntimeException( "No Web Coverage Service instance available for WCSInvoker" );
135            }
136    
137            Object coverageResponse = null;
138    
139            // check if the admin has configured a minimal dgm resolution, if so the request and
140            // response resolution for the dgm must be set.
141            int requestWidth = resolutionStripe.getRequestWidthForBBox();
142            int requestHeight = resolutionStripe.getRequestHeightForBBox();
143            if ( isElevationModelRequest ) {
144                double minRes = ( (LocalWCSDataSource) dataSource ).getConfiguredMinimalDGMResolution();
145                LOG.logDebug( "configured minimalResolution: " + minRes );
146                if ( minRes > 0.0000001 ) {// 0d if not set
147                    Envelope env = resolutionStripe.getSurface().getEnvelope();
148                    if ( ( env.getWidth() / requestWidth ) < minRes ) {
149                        requestWidth = (int) ( env.getWidth() / minRes );
150                    }
151                    if ( ( env.getHeight() / requestHeight ) < minRes ) {
152                        requestHeight = (int) ( env.getHeight() / minRes );
153                    }
154                }
155            }
156    
157            try {
158                GetCoverage getCoverageRequest = createGetCoverageRequest(
159                                                                           ( (LocalWCSDataSource) dataSource ).getCoverageFilterCondition(),
160                                                                           requestWidth, requestHeight );
161                LOG.logDebug( "Sending wcs request:" + dataSource.getName() );
162                coverageResponse = service.doService( getCoverageRequest );
163            } catch ( WCSException wcse ) {
164                if ( !Thread.currentThread().isInterrupted() ) {
165                    LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR" , "WCSException", dataSource.getName(), wcse.getMessage() ) );
166                    if( !isElevationModelRequest ){
167                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id, wcse );
168                    }
169                }
170                return;
171            } catch ( OGCWebServiceException ogcwse ) {
172                if ( !Thread.currentThread().isInterrupted() ) {
173                    LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR" , "OGCWebServiceException", dataSource.getName(), ogcwse.getMessage() ) );
174                    if( !isElevationModelRequest ){
175                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id, ogcwse );
176                    }            
177                }
178                return;
179            } catch ( Throwable t ) {
180                if ( !Thread.currentThread().isInterrupted() ) {
181                    t.printStackTrace();
182                }
183                return;
184            }
185            if ( coverageResponse != null && coverageResponse instanceof ResultCoverage ) {
186    
187                LOG.logDebug( "\t -> a valid response\n" );
188                ResultCoverage response = (ResultCoverage) coverageResponse;
189                if ( response.getCoverage() != null
190                     && response.getCoverage() instanceof ImageGridCoverage ) {
191                    ImageGridCoverage igc = (ImageGridCoverage) response.getCoverage();
192    
193                    BufferedImage image = igc.getAsImage( requestWidth, requestHeight );
194                    if ( !isElevationModelRequest ) {
195                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
196                            try {
197                                File f = new File( "wcs_texture_response.png" );
198                                LOG.logDebug( "creating tmpfile for wcs texture response with name: "
199                                              + f.toString() );
200                                f.deleteOnExit();
201                                ImageIO.write( image, "png", f );
202                            } catch ( IOException e ) {
203                                // TODO Auto-generated catch block
204                                e.printStackTrace();
205                            }
206                        }
207                        Color[] colors = ( (LocalWCSDataSource) dataSource ).getTransparentColors();
208                        if ( colors != null && colors.length > 0 ) {
209                            ImageUtils imgUtil = new ImageUtils( colors );
210                            Image img = imgUtil.filterImage( image );
211                            Graphics2D g2d = (Graphics2D) image.getGraphics();
212                            g2d.drawImage( img, 0, 0, null );
213                            g2d.dispose();
214                        }
215    
216                        if ( !resolutionStripe.addTexture( dataSource.getName().getFormattedString() + id,
217                                                           image ) ) {
218                            LOG.logDebug( "could not add the texture" );
219                        }
220                    } else {
221                        // the heightdata is in x and -y coordinates, they must be flipped before using
222                        PlanarImage im2 = JAI.create( "transpose", image,
223                                                      TransposeDescriptor.FLIP_VERTICAL );
224                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
225                            try {
226                                File f = new File( "wcs_dgm_response.png" );
227                                LOG.logDebug( "creating tmpfile for wcs elevationmodel response with name: "
228                                              + f.toString() );
229                                f.deleteOnExit();
230                                ImageIO.write( im2.getAsBufferedImage(), "png", f );
231                            } catch ( Exception e ) {
232                                // TODO Auto-generated catch block
233                                e.printStackTrace();
234                            }
235                        }
236                        resolutionStripe.setElevationModelFromHeightMap( im2.getAsBufferedImage() );
237                    }
238                } else {
239                    LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE",
240                                                         dataSource.getName(), "an ImageGridCoverage" ) );
241                }
242            } else {
243                LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(),
244                                                     "a ResultCoverage" ) );
245            }
246    
247        }
248    
249        /**
250         * Creates a getCoverage request for the given surface
251         * 
252         * @param surface
253         *            the surface to be used as the bouding box
254         * @param requestWidth
255         *            the width of a request (which should take the configured dgm_res into account).
256         * @param requestHeight
257         *            the height of a request (which should take the configured dgm_res into account).
258         * @return a new GetCoverageRequest.
259         * @throws WCSException
260         * @throws OGCWebServiceException
261         */
262        private GetCoverage createGetCoverageRequest( GetCoverage filterCondition, int requestWidth,
263                                                     int requestHeight )
264                                throws WCSException, OGCWebServiceException {
265    
266            String format = "GeoTiff";
267    
268            if ( !isElevationModelRequest ) {
269                if ( filterCondition.getOutput().getFormat() == null ) {
270                    // fallback if no output format has been defined for a
271                    // WCS datasource
272                    format = requestFormat;
273                } else {
274                    format = filterCondition.getOutput().getFormat().getCode();
275                }
276                int pos = format.indexOf( '/' );
277                if ( pos > -1 ) {
278                    format = format.substring( pos + 1, format.length() );
279                }
280    
281                if ( format.indexOf( "svg" ) > -1 ) {
282                    format = "png";
283                }
284            }
285            Output output = GetCoverage.createOutput( resolutionStripe.getCRSName().getFormattedString(),
286                                                      null, format, null );
287    
288            // put mising parts in this map:
289            Map<String, String> map = new HashMap<String, String>( 5 );
290    
291            StringBuffer sb = new StringBuffer( 1000 );
292            Envelope env = resolutionStripe.getSurface().getEnvelope();
293            Position p = env.getMin();
294            sb.append( p.getX() ).append( "," ).append( p.getY() ).append( "," );
295            p = env.getMax();
296            sb.append( p.getX() ).append( "," ).append( p.getY() );
297            map.put( "BBOX", sb.toString() );
298    
299            map.put( "WIDTH", String.valueOf( requestWidth ) );
300            map.put( "HEIGHT", String.valueOf( requestHeight ) );
301    
302            SpatialSubset sps = GetCoverage.createSpatialSubset(
303                                                                 map,
304                                                                 resolutionStripe.getCRSName().getFormattedString());
305    
306            Code code = filterCondition.getDomainSubset().getRequestSRS();
307            DomainSubset domainSubset = new DomainSubset( code, sps, null );
308    
309            IDGenerator idg = IDGenerator.getInstance();
310    
311            GetCoverage getCoverageRequest = new GetCoverage( String.valueOf( idg.generateUniqueID() ),
312                                                              filterCondition.getVersion(),
313                                                              filterCondition.getSourceCoverage(),
314                                                              domainSubset, null,
315                                                              filterCondition.getInterpolationMethod(),
316                                                              output );
317    
318            return getCoverageRequest;
319        }
320    
321    }