001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/WCSInvoker.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     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: apoth $
086     * 
087     * $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 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, boolean isElevationModelRequest ) {
111            super( owner );
112            this.id = id;
113            this.isElevationModelRequest = isElevationModelRequest;
114            this.requestFormat = requestFormat;
115        }
116    
117        @Override
118        public void invokeService( AbstractDataSource dataSource ) {
119    
120            if ( !( dataSource instanceof LocalWCSDataSource ) ) {
121                LOG.logError( "The given AbstractDataSource is no WCSDataSource instance. It is needed for a WCSInvoker" );
122                throw new RuntimeException( "DataSource should be a WCS-instance for a WCSInvoker" );
123            }
124    
125            WCService service = null;
126            try {
127                service = (WCService) dataSource.getOGCWebService();
128            } catch ( OGCWebServiceException ogcwe ) {
129                LOG.logError( ogcwe.getMessage() );
130                throw new RuntimeException( ogcwe );
131            }
132            if ( service == null ) {
133                throw new RuntimeException( "No Web Coverage Service instance available for WCSInvoker" );
134            }
135    
136            Object coverageResponse = null;
137    
138            // check if the admin has configured a minimal dgm resolution, if so the request and
139            // response resolution for the dgm must be set.
140            int requestWidth = resolutionStripe.getRequestWidthForBBox();
141            int requestHeight = resolutionStripe.getRequestHeightForBBox();
142            if ( isElevationModelRequest ) {
143                double minRes = ( (LocalWCSDataSource) dataSource ).getConfiguredMinimalDGMResolution();
144                LOG.logDebug( "configured minimalResolution: " + minRes );
145                if ( minRes > 0.0000001 ) {// 0d if not set
146                    Envelope env = resolutionStripe.getSurface().getEnvelope();
147                    if ( ( env.getWidth() / requestWidth ) < minRes ) {
148                        requestWidth = (int) ( env.getWidth() / minRes );
149                    }
150                    if ( ( env.getHeight() / requestHeight ) < minRes ) {
151                        requestHeight = (int) ( env.getHeight() / minRes );
152                    }
153                }
154            }
155    
156            try {
157                GetCoverage getCoverageRequest = createGetCoverageRequest(
158                                                                           ( (LocalWCSDataSource) dataSource ).getCoverageFilterCondition(),
159                                                                           ( (LocalWCSDataSource) dataSource ).getDefaultFormat(),
160                                                                           requestWidth, requestHeight );
161                LOG.logDebug( "WCS request:" + getCoverageRequest );
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(),
166                                                       wcse.getMessage() ) );
167                    if ( !isElevationModelRequest ) {
168                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id, wcse );
169                    }
170                }
171                return;
172            } catch ( OGCWebServiceException ogcwse ) {
173                if ( !Thread.currentThread().isInterrupted() ) {
174                    LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR", "OGCWebServiceException",
175                                                       dataSource.getName(), ogcwse.getMessage() ) );
176                    if ( !isElevationModelRequest ) {
177                        resolutionStripe.setTextureRetrievalException( dataSource.getName().getFormattedString() + id,
178                                                                       ogcwse );
179                    }
180                }
181                return;
182            } catch ( Throwable t ) {
183                if ( !Thread.currentThread().isInterrupted() ) {
184                    t.printStackTrace();
185                }
186                return;
187            }
188            if ( coverageResponse != null && coverageResponse instanceof ResultCoverage ) {
189    
190                LOG.logDebug( "\t -> a valid response\n" );
191                ResultCoverage response = (ResultCoverage) coverageResponse;
192                if ( response.getCoverage() != null && response.getCoverage() instanceof ImageGridCoverage ) {
193                    ImageGridCoverage igc = (ImageGridCoverage) response.getCoverage();
194    
195                    BufferedImage image = igc.getAsImage( requestWidth, requestHeight );
196                    if ( !isElevationModelRequest ) {
197                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
198                            try {
199                                File f = new File( "wcs_texture_response.png" );
200                                LOG.logDebug( "creating tmpfile for wcs texture response with name: " + f.toString() );
201                                f.deleteOnExit();
202                                ImageIO.write( image, "png", f );
203                            } catch ( IOException e ) {
204                                // TODO Auto-generated catch block
205                                e.printStackTrace();
206                            }
207                        }
208                        Color[] colors = ( (LocalWCSDataSource) dataSource ).getTransparentColors();
209                        if ( colors != null && colors.length > 0 ) {
210                            ImageUtils imgUtil = new ImageUtils( colors );
211                            Image img = imgUtil.filterImage( image );
212                            Graphics2D g2d = (Graphics2D) image.getGraphics();
213                            g2d.drawImage( img, 0, 0, null );
214                            g2d.dispose();
215                        }
216    
217                        if ( !resolutionStripe.addTexture( dataSource.getName().getFormattedString() + id, 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, TransposeDescriptor.FLIP_VERTICAL );
223                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
224                            try {
225                                File f = new File( "wcs_dgm_response.png" );
226                                LOG.logDebug( "creating tmpfile for wcs elevationmodel response with name: " + f.toString() );
227                                f.deleteOnExit();
228                                ImageIO.write( im2.getAsBufferedImage(), "png", f );
229                            } catch ( Exception e ) {
230                                // TODO Auto-generated catch block
231                                e.printStackTrace();
232                            }
233                        }
234                        resolutionStripe.setElevationModelFromHeightMap( im2.getAsBufferedImage() );
235                    }
236                } else {
237                    LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(),
238                                                         "an ImageGridCoverage" ) );
239                }
240            } else {
241                LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(), "a ResultCoverage" ) );
242            }
243    
244        }
245    
246        /**
247         * Creates a getCoverage request for the given surface
248         * 
249         * @param format
250         * 
251         * @param surface
252         *            the surface to be used as the bouding box
253         * @param requestWidth
254         *            the width of a request (which should take the configured dgm_res into account).
255         * @param requestHeight
256         *            the height of a request (which should take the configured dgm_res into account).
257         * @return a new GetCoverageRequest.
258         * @throws WCSException
259         * @throws OGCWebServiceException
260         */
261        private GetCoverage createGetCoverageRequest( GetCoverage filterCondition, String format, int requestWidth,
262                                                      int requestHeight )
263                                throws WCSException, OGCWebServiceException {
264    
265            // String format = "GeoTiff";
266            if ( !isElevationModelRequest ) {
267                if ( filterCondition.getOutput().getFormat() == null ) {
268                    // fallback if no output format has been defined for a
269                    // WCS datasource
270                    format = requestFormat;
271                } else {
272                    format = filterCondition.getOutput().getFormat().getCode();
273                }
274                int pos = format.indexOf( '/' );
275                if ( pos > -1 ) {
276                    format = format.substring( pos + 1, format.length() );
277                }
278    
279                if ( format.indexOf( "svg" ) > -1 ) {
280                    format = "png";
281                }
282            }
283            Output output = GetCoverage.createOutput( resolutionStripe.getCRSName().getFormattedString(), null, format,
284                                                      null );
285    
286            // put mising parts in this map:
287            Map<String, String> map = new HashMap<String, String>( 5 );
288    
289            StringBuffer sb = new StringBuffer( 1000 );
290            Envelope env = resolutionStripe.getSurface().getEnvelope();
291            Position p = env.getMin();
292            sb.append( p.getX() ).append( "," ).append( p.getY() ).append( "," );
293            p = env.getMax();
294            sb.append( p.getX() ).append( "," ).append( p.getY() );
295            map.put( "BBOX", sb.toString() );
296    
297            map.put( "WIDTH", String.valueOf( requestWidth ) );
298            map.put( "HEIGHT", String.valueOf( requestHeight ) );
299    
300            SpatialSubset sps = GetCoverage.createSpatialSubset( map, resolutionStripe.getCRSName().getFormattedString() );
301    
302            Code code = filterCondition.getDomainSubset().getRequestSRS();
303            DomainSubset domainSubset = new DomainSubset( code, sps, null );
304    
305            IDGenerator idg = IDGenerator.getInstance();
306    
307            GetCoverage getCoverageRequest = new GetCoverage( String.valueOf( idg.generateUniqueID() ),
308                                                              filterCondition.getVersion(),
309                                                              filterCondition.getSourceCoverage(), domainSubset, null,
310                                                              filterCondition.getInterpolationMethod(), output );
311    
312            return getCoverageRequest;
313        }
314    
315    }