
org.integratedmodelling.engine.geospace.coverage.raster.WCSCoverage Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (C) 2007, 2015:
*
* - Ferdinando Villa - integratedmodelling.org - any
* other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite, meant to enable
* modular, collaborative, integrated development of interoperable data and model
* components. For details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the Affero General Public License Version 3 or any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA. The license is also available at:
* https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.engine.geospace.coverage.raster;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
import java.util.Properties;
import javax.media.jai.iterator.RandomIterFactory;
import org.apache.jcs.access.exception.CacheException;
import org.geotools.coverage.grid.GeneralGridEnvelope;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.monitoring.Messages;
import org.integratedmodelling.api.network.API;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.utils.FileUtils;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.coverage.ICoverage;
import org.integratedmodelling.engine.geospace.extents.Area;
import org.integratedmodelling.engine.geospace.extents.Grid;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.integratedmodelling.exceptions.KlabInternalErrorException;
import org.integratedmodelling.exceptions.KlabValidationException;
public class WCSCoverage extends AbstractRasterCoverage {
public static final String WCS_SERVICE_PROPERTY = "wcs.service.url";
public static final String WCS_FORMAT_PROPERTY = "wcs.service.format";
String wcsService = "http://127.0.0.1:8080/geoserver/wcs";
String wcsFormat = "geotiff";
String description = null;
// read from kvp in coverage keywords
Properties properties = new Properties();
IMonitor monitor;
String authentication;
static class CachedDescriptor implements Serializable {
private static final long serialVersionUID = 1453574401114688492L;
double x1, x2, y1, y2;
int sx1, sx2, sy1, sy2;
String srs;
}
private boolean readFromCache() throws KlabException {
String key = wcsService + "#" + layerName;
CachedDescriptor cd = (CachedDescriptor) Geospace.get().getWCSCache().get(key);
if (cd != null) {
try {
this.crs = Geospace.getCRSFromID(cd.srs);
} catch (Exception e) {
KLAB.error(layerName + ": " + e.getMessage());
}
this.xCellSize = (cd.x2 - cd.x1) / (cd.sx2 - cd.sx1);
this.yCellSize = (cd.y2 - cd.y1) / (cd.sy2 - cd.sy1);
this.boundingBox = new ReferencedEnvelope(cd.x1, cd.x2, cd.y1, cd.y2, crs);
this.gridGeometry = new GridGeometry2D(new GeneralGridEnvelope(new int[] {
cd.sx1,
cd.sy1 }, new int[] { cd.sx2, cd.sy2 }, false), boundingBox);
return true;
}
return false;
}
/**
* This constructor reads the WCS coverage descriptor and initializes all fields from
* it. Data are not loaded until loadData(), so the coverage is null.
*
* @param coverageID
*
* @param properties should contain the URL of the WCS service; if null, geoserver on
* localhost:8080 is used (not elegant, but OK for now).
* @param monitor
* @throws KlabException
*/
public WCSCoverage(String coverageID, Properties properties, IMonitor monitor, String authentication)
throws KlabException {
this.authentication = authentication;
if (properties != null) {
wcsService = properties.getProperty(WCS_SERVICE_PROPERTY, "http://127.0.0.1:8080/geoserver/wcs");
wcsFormat = properties.getProperty(WCS_FORMAT_PROPERTY, wcsFormat);
if (properties.containsKey(NODATA_PROPERTY)) {
String[] zz = properties.getProperty(NODATA_PROPERTY).split(",");
this.noData = new double[zz.length];
for (int i = 0; i < zz.length; i++)
this.noData[i] = Double.parseDouble(zz[i]);
}
}
layerName = coverageID;
if (!readFromCache()) {
WCS wcs = new WCS(wcsService);
if (!wcs.responds()) {
monitor.warn("connection to WCS failed: " + coverageID);
throw new KlabIOException("connection to WCS host failed for layer " + coverageID + "; service URL is " + wcsService);
}
try {
CachedDescriptor cd = parseDescriptor(wcs);
saveToCache(cd);
} catch (KlabException e) {
/*
* pass any exceptions through the monitor before throwing it.
*/
if (monitor != null) {
monitor.error(e);
}
throw e;
}
}
}
private void saveToCache(CachedDescriptor cd) throws KlabException {
String key = wcsService + "#" + layerName;
try {
Geospace.get().getWCSCache().put(key, cd);
} catch (CacheException e) {
throw new KlabIOException(e);
}
}
/**
* This constructor creates the coverage by reading the WCS coverage passed from the
* associated WCS service, reading data only for the specified extent.
*
* @param coverage
* @param extent
*/
public WCSCoverage(WCSCoverage coverage, Area extent) {
layerName = coverage.layerName;
authentication = coverage.authentication;
monitor = coverage.monitor;
}
private CachedDescriptor parseDescriptor(WCS wcs) throws KlabException {
Map map = wcs.describeCoverage(this.layerName, authentication, monitor);
try {
this.crs = Geospace.getCRSFromID(map.get(WCS.CRS).toString());
} catch (Exception e) {
// KLAB.error(layerName + ": " + e.getMessage());
throw new KlabInternalErrorException(e);
}
double x1 = (double) map.get(WCS.MINX);
double x2 = (double) map.get(WCS.MAXX);
double y1 = (double) map.get(WCS.MINY);
double y2 = (double) map.get(WCS.MAXY);
int xcells = (int) map.get(WCS.XCELLS);
int ycells = (int) map.get(WCS.YCELLS);
this.xCellSize = (x2 - x1) / xcells;
this.yCellSize = (y2 - y1) / ycells;
this.boundingBox = new ReferencedEnvelope(x1, x2, y1, y2, crs);
this.gridGeometry = new GridGeometry2D(new GeneralGridEnvelope(new int[] { 0, 0 }, new int[] {
xcells,
ycells }, false), boundingBox);
/*
* create and return descriptor for cache
*/
CachedDescriptor ret = new CachedDescriptor();
ret.x1 = x1;
ret.x2 = x2;
ret.y1 = y1;
ret.y2 = y2;
ret.sx1 = 0;
ret.sx2 = xcells;
ret.sy1 = 0;
ret.sy2 = ycells;
ret.srs = map.get(WCS.CRS).toString();
return ret;
}
private URL buildRetrieveUrl(Grid extent) throws KlabException {
URL url = null;
String rcrs = Geospace.getCRSIdentifier(extent.getCRS(), false);
int xc = extent.getXCells();
int yc = extent.getYCells();
if (extent.getXCells() == 0 && extent.getYCells() == 0) {
xc = (int) Math.ceil((extent.getEast() - extent.getWest()) / this.xCellSize);
yc = (int) Math.ceil((extent.getNorth() - extent.getSouth()) / this.yCellSize);
// System.out.println("computed raster size is " + xc + " x " + yc);
extent.setResolution(xc, yc);
}
String s = wcsService + "?service=WCS&version=1.0.0&request=GetCoverage&coverage=" + layerName
+ "&bbox=" + extent.getWest() + "," + extent.getSouth() + "," + extent.getEast() + ","
+ extent.getNorth() + "&crs=" + rcrs + "&responseCRS=" + rcrs + "&width=" + xc + "&height="
+ yc + "&format=" + wcsFormat;
try {
url = new URL(s);
} catch (MalformedURLException e) {
throw new KlabInternalErrorException(e);
}
KLAB.info("retrieving " + url);
return url;
}
// @Override
public void loadData() throws KlabException {
checkCoverage();
/*
* get rid of old image if we had one
*/
if (image != null) {
image = null;
}
image = coverage.getRenderedImage();
itera = RandomIterFactory.create(image, null);
_loaded = true;
}
private void checkCoverage() throws KlabException {
if (coverage == null) {
/*
* TODO we should read it as is, but typically we don't care for downloading a
* gigabyte from the net, so the case with coverage == null is normally an
* error - no specification of a subrange has been asked. For now let's just
* throw an error.
*/
throw new KlabValidationException("WCS coverage " + layerName
+ " being read in its entirety without subsetting: "
+ "this is most likely an error causing extremely long download times.");
}
}
@Override
public ICoverage requireMatch(Area arealExtent, IObserver observer, IMonitor monitor, boolean allowClassChange)
throws KlabException {
if (!(arealExtent instanceof Grid))
throw new KlabValidationException("coverage can only be reprojected on a grid extent for now");
URL getCov = buildRetrieveUrl((Grid) arealExtent);
String savUrl = getCov.toString();
ClassLoader clsl = null;
try {
if (monitor != null) {
monitor.info("requesting " + layerName + " as WCS", Messages.INFOCLASS_MODEL);
}
// clsl = KLABEngine.get().swapClassloader();
URLConnection connection = getCov.openConnection();
if (authentication != null) {
connection.setRequestProperty(API.AUTHENTICATION_HEADER, authentication);
}
File f = File.createTempFile("geo", ".tiff");
FileUtils.copyInputStreamToFile(connection.getInputStream(), f);
getCov = f.toURI().toURL();
GeoTiffReader reader = new GeoTiffReader(getCov, Geospace.get().getGeotoolsHints());
this.coverage = reader.read(null);
/*
* if the bounding box was read from a wcs coverage, keep it in the
* originalBoundingBox field so that we can check coverage inside thinklab
*/
if (this.originalBoundingBox == null) {
this.originalBoundingBox = this.boundingBox;
}
/*
* we obviously want it in the same CRS as the new one.
*/
if (this.originalBoundingBox != null) {
try {
this.originalBoundingBox = this.originalBoundingBox.transform(arealExtent.getCRS(), true);
} catch (Exception e) {
throw new KlabValidationException(e);
}
}
} catch (IOException e) {
throw new KlabIOException(layerName + ": " + e.getMessage() + ": url = " + savUrl);
} finally {
// KLABEngine.get().resetClassLoader(clsl);
}
setExtent((Grid) arealExtent);
/*
* recreate iterator - fix
*/
loadData();
return this;
}
private void setExtent(Grid e) {
this.xCellSize = e.getEWResolution();
this.yCellSize = e.getNSResolution();
this.boundingBox = e.getEnvelope();
this.gridGeometry = new GridGeometry2D(new GeneralGridEnvelope(new int[] {
e.getXMinCell(),
e.getYMinCell() }, new int[] { e.getXMaxCell(), e.getYMaxCell() }, false), boundingBox);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy