//$HeadURL$
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2008 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.igeo.dataadapter.wcs;
import static org.deegree.framework.util.MapUtils.DEFAULT_PIXEL_SIZE;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.HttpUtils;
import org.deegree.framework.util.ImageUtils;
import org.deegree.framework.util.MapUtils;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.XMLFragment;
import org.deegree.framework.xml.XMLParsingException;
import org.deegree.framework.xml.XMLTools;
import org.deegree.igeo.ApplicationContainer;
import org.deegree.igeo.dataadapter.DataAccessException;
import org.deegree.igeo.dataadapter.GridCoverageAdapter;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.Datasource;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.igeo.mapmodel.WCSDatasource;
import org.deegree.igeo.settings.WCSGridCoverageAdapterSettings;
import org.deegree.model.Identifier;
import org.deegree.model.coverage.grid.GridCoverage;
import org.deegree.model.coverage.grid.ImageGridCoverage;
import org.deegree.model.crs.CRSTransformationException;
import org.deegree.model.crs.GeoTransformer;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.ogcwebservices.OGCWebServiceException;
import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
import org.xml.sax.SAXException;
/**
* Concrete implementation of {@link GridCoverageAdapter} for reading raster data from a WCS
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class WCSGridCoverageAdapter extends GridCoverageAdapter {
private static final ILogger LOG = LoggerFactory.getLogger( WCSGridCoverageAdapter.class );
private int timeout = 25000;
private URL getCoverageHttpGetURL;
private WCSGridCoverageAdapterSettings wcsSet;
private String version;
private static Map<String, XMLFragment> capabilitiesCache;
static {
if ( capabilitiesCache == null ) {
capabilitiesCache = new HashMap<String, XMLFragment>();
}
}
/**
* @param cmmDatasource
* @param cmmLayer
* @param cmmMapModel
*/
public WCSGridCoverageAdapter( Datasource cmmDatasource, Layer cmmLayer, MapModel cmmMapModel, URL baseURL ) {
super( cmmDatasource, cmmLayer, cmmMapModel );
Envelope bbox = mapModel.getEnvelope();
datasource.setExtent( bbox );
wcsSet = mapModel.getApplicationContainer().getSettings().getWCSGridCoveragesAdapter();
// wcsSet = mapModel.getApplicationContainer().getSettings().getWC
// read request timeout from deegree configuration
timeout = wcsSet.getTimeout();
// read target URLs (and WCS version) from WCS capabilities
readURLs( baseURL );
}
/**
* @param baseURL
*/
private void readURLs( URL baseURL ) {
XMLFragment xml;
String capabilitiesUrl = null;
try {
ApplicationContainer<?> appCont = mapModel.getApplicationContainer();
capabilitiesUrl = baseURL.toURI().toASCIIString();
String tmp = HttpUtils.normalizeURL( capabilitiesUrl );
capabilitiesUrl = HttpUtils.addAuthenticationForKVP( capabilitiesUrl, appCont.getUser(),
appCont.getPassword(), appCont.getCertificate( tmp ) );
if ( capabilitiesCache.containsKey( capabilitiesUrl ) ) {
xml = capabilitiesCache.get( capabilitiesUrl );
LOG.logInfo( "read capabilities from cache: ", capabilitiesUrl );
} else {
InputStream is = HttpUtils.performHttpGet( capabilitiesUrl, null, timeout, appCont.getUser(),
appCont.getPassword(), null ).getResponseBodyAsStream();
xml = new XMLFragment();
xml.load( is, capabilitiesUrl );
capabilitiesCache.put( capabilitiesUrl, xml );
}
} catch ( SAXException e ) {
LOG.logError( e.getMessage(), e );
String s = StringTools.stackTraceToString( e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10106", capabilitiesUrl ) + s );
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
String s = StringTools.stackTraceToString( e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$$DG10107", capabilitiesUrl ) + s );
}
try {
version = XMLTools.getRequiredAttrValue( "version", null, xml.getRootElement() );
} catch ( XMLParsingException e ) {
LOG.logError( e.getMessage(), e );
LOG.logError( xml.getAsPrettyString() );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10108", capabilitiesUrl,
xml.getAsPrettyString() ) );
}
String className = wcsSet.getCapabilitiesEvaluator( version );
Class<?> clzz = null;
try {
clzz = Class.forName( className );
} catch ( ClassNotFoundException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10109", className ) );
}
WCSCapabilitiesEvaluator evaluator = null;
try {
evaluator = (WCSCapabilitiesEvaluator) clzz.newInstance();
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10110", className ) );
}
evaluator.setCapabilities( xml );
try {
getCoverageHttpGetURL = evaluator.getGetCoverageHTTPGetURL();
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( e.getMessage(), e );
}
}
@Override
public GridCoverage getCoverage() {
readCoverageImage();
return this.coverage;
}
/**
*
*/
private void readCoverageImage() {
fireStartLoadingEvent();
// update GetCoverage request with current state of the map model
Envelope bbox = mapModel.getEnvelope();
int width = mapModel.getTargetDevice().getPixelWidth();
int height = mapModel.getTargetDevice().getPixelHeight();
String srs = mapModel.getCoordinateSystem().getPrefixedName();
GeoTransformer transformBack = null;
if ( !datasource.getNativeCoordinateSystem().equals( mapModel.getCoordinateSystem() ) ) {
// perform CRS transformation of the request bounding box and resizing of the requested image
// to enable transformation and cutting the result of a GetCoverage request back to the CRS of
// the map model without lost of data at the image boundaries
srs = datasource.getNativeCoordinateSystem().getPrefixedName();
GeoTransformer transformer = new GeoTransformer( datasource.getNativeCoordinateSystem() );
transformBack = new GeoTransformer( mapModel.getCoordinateSystem() );
try {
bbox = transformer.transform( bbox, mapModel.getCoordinateSystem(), true );
} catch ( CRSTransformationException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( e.getMessage() );
}
double scale = MapUtils.calcScale( width, height, mapModel.getEnvelope(), mapModel.getCoordinateSystem(),
DEFAULT_PIXEL_SIZE );
double newScale = MapUtils.calcScale( width, height, bbox, datasource.getNativeCoordinateSystem(),
DEFAULT_PIXEL_SIZE );
double ratio = scale / newScale;
width = (int) Math.round( width * ratio );
height = (int) Math.round( height * ratio );
}
Map<String, String> map = new HashMap<String, String>();
// ensure that GetCoverage request will be created for version read from WCS capabilities
map.put( "ID", new Identifier().getAsQualifiedString() );
map.put( "VERSION", version );
map.put( "COVERAGE", ( (WCSDatasource) datasource ).getCoverage().getLocalName() );
map.put( "WIDTH", Integer.toString( width ) );
map.put( "HEIGHT", Integer.toString( height ) );
map.put( "FORMAT", ( (WCSDatasource) datasource ).getFormat() );
map.put( "CRS", srs );
map.put( "BBOX", bbox.getMin().getX() + "," + bbox.getMin().getY() + ',' + bbox.getMax().getX() + ','
+ bbox.getMax().getY() );
if ( ( (WCSDatasource) datasource ).getTime() != null ) {
map.put( "TIME", ( (WCSDatasource) datasource ).getTime() );
}
GetCoverage baseRequest;
try {
baseRequest = GetCoverage.create( map );
} catch ( Exception e ) {
LOG.logError( e );
throw new DataAccessException( e );
}
InputStream is = null;
URL baseURL = null;
try {
ApplicationContainer<?> appCont = mapModel.getApplicationContainer();
String getCoveragUrl = getCoverageHttpGetURL.toURI().toASCIIString();
String param = HttpUtils.addAuthenticationForKVP( baseRequest.getRequestParameter(), appCont.getUser(),
appCont.getPassword(),
appCont.getCertificate( getCoveragUrl ) );
LOG.logDebug( "base WCS URL ", getCoveragUrl );
LOG.logDebug( "WCS GetCoverage parameter ", param );
is = HttpUtils.performHttpGet( getCoveragUrl, param, timeout, appCont.getUser(), appCont.getPassword(),
null ).getResponseBodyAsStream();
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
fireLoadingExceptionEvent();
try {
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10111", baseURL,
baseRequest.getRequestParameter() ) );
} catch ( OGCWebServiceException e1 ) {
e1.printStackTrace();
}
}
// read data from WCS into a byte array to enable debugging and detailed error messages
// if result can not be parsed as image
ByteArrayOutputStream bos = new ByteArrayOutputStream( 100000 );
byte[] b = new byte[100000];
try {
int c = is.read( b );
do {
bos.write( b, 0, c );
c = is.read( b );
} while ( c > 0 );
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
try {
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10112", baseURL,
baseRequest.getRequestParameter(), e.getMessage() ) );
} catch ( OGCWebServiceException e1 ) {
e1.printStackTrace();
}
}
BufferedImage image = null;
try {
image = ImageUtils.loadImage( new ByteArrayInputStream( bos.toByteArray() ) );
bos.close();
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
try {
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10112", baseURL,
baseRequest.getRequestParameter(),
new String( bos.toByteArray() ) ) );
} catch ( OGCWebServiceException e1 ) {
e1.printStackTrace();
}
}
if ( !datasource.getNativeCoordinateSystem().equals( mapModel.getCoordinateSystem() ) ) {
// perform transformation and cutting of the result of a GetCoverage request if map model CRS and
// CRS supported by requested layer(s) are not the same
try {
image = transformBack.transform( image, bbox, mapModel.getEnvelope(),
mapModel.getTargetDevice().getPixelWidth(),
mapModel.getTargetDevice().getPixelHeight(), 25, 3, null );
} catch ( CRSTransformationException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( e.getMessage() );
}
}
this.coverage = new ImageGridCoverage( null, mapModel.getEnvelope(), image );
fireLoadingFinishedEvent();
}
@Override
public void refresh() {
// TODO Auto-generated method stub
}
@Override
public void refresh( boolean forceReload ) {
// TODO Auto-generated method stub
}
@Override
public void commitChanges()
throws IOException {
// TODO Auto-generated method stub
}
}