Package org.geoserver.wcs.kvp

Source Code of org.geoserver.wcs.kvp.Wcs10GetCoverageRequestReader

/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.wcs.kvp;

import static org.vfny.geoserver.wcs.WcsException.WcsExceptionCode.InvalidParameterValue;
import static org.vfny.geoserver.wcs.WcsException.WcsExceptionCode.MissingParameterValue;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import net.opengis.gml.CodeType;
import net.opengis.gml.DirectPositionType;
import net.opengis.gml.Gml4wcsFactory;
import net.opengis.gml.PointType;
import net.opengis.gml.RectifiedGridType;
import net.opengis.gml.TimePositionType;
import net.opengis.gml.VectorType;
import net.opengis.wcs10.AxisSubsetType;
import net.opengis.wcs10.DomainSubsetType;
import net.opengis.wcs10.GetCoverageType;
import net.opengis.wcs10.IntervalType;
import net.opengis.wcs10.OutputType;
import net.opengis.wcs10.RangeSubsetType;
import net.opengis.wcs10.SpatialSubsetType;
import net.opengis.wcs10.TimeSequenceType;
import net.opengis.wcs10.TypedLiteralType;
import net.opengis.wcs10.Wcs10Factory;

import org.geoserver.catalog.Catalog;
import org.geoserver.ows.kvp.EMFKvpRequestReader;
import org.geoserver.ows.util.KvpUtils;
import org.geoserver.ows.util.RequestUtils;
import org.geoserver.ows.util.KvpUtils.Tokenizer;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.vfny.geoserver.wcs.WcsException;
import org.vfny.geoserver.wcs.WcsException.WcsExceptionCode;

/**
* GetCoverage request reader for WCS 1.0.0
*
* @author Simone Giannecchini, GeoSolutions SAS
*
*/
public class Wcs10GetCoverageRequestReader extends EMFKvpRequestReader {

    public static final String VERSION = "1.0.0";
  Catalog catalog;

    public Wcs10GetCoverageRequestReader(Catalog catalog) {
        super(GetCoverageType.class, Wcs10Factory.eINSTANCE);
        this.catalog = catalog;
    }

    @Override
    public Object read(Object request, Map kvp, Map rawKvp) throws Exception {
        GetCoverageType getCoverage = (GetCoverageType) super.read(request, kvp, rawKvp);

        // grab coverage info to perform further checks
        if (getCoverage.getSourceCoverage() == null) {
            if (kvp.get("coverage") == null)
                throw new WcsException("source coverage parameter is mandatory",
                        MissingParameterValue, "source coverage");
            else
                getCoverage.setSourceCoverage((String) ((List) kvp.get("coverage")).get(0));
        }
        // if not specified, throw a resounding exception (by spec)
        if (!getCoverage.isSetVersion())
            throw new WcsException("Version has not been specified",
                    WcsExceptionCode.MissingParameterValue, "version");

        // do the version negotiation dance
        List<String> provided = new ArrayList<String>();
        provided.add(Wcs10GetCoverageRequestReader.VERSION);
        List<String> accepted = null;
        if (getCoverage.getVersion() != null) {
            accepted = new ArrayList<String>();
            accepted.add(getCoverage.getVersion());
        }
        String version = RequestUtils.getVersionPreOws(provided, accepted);

        if (!Wcs10GetCoverageRequestReader.VERSION.equals(version)) {
            throw new WcsException("An invalid version number has been specified",
                    WcsExceptionCode.InvalidParameterValue, "version");
        }
        getCoverage.setVersion(Wcs10GetCoverageRequestReader.VERSION);

        // build the domain subset
        getCoverage.setDomainSubset(parseDomainSubset(kvp));

        // build the range subset
        getCoverage.setRangeSubset(parseRangeSubset(kvp, getCoverage.getSourceCoverage()));

        // build output element
        getCoverage.setOutput(parseOutputElement(kvp));

        return getCoverage;
    }

    /**
     *
     * @param kvp
     * @return
     */
    private DomainSubsetType parseDomainSubset(Map kvp) {
        final DomainSubsetType domainSubset = Wcs10Factory.eINSTANCE.createDomainSubsetType();
        final SpatialSubsetType spatialSubset = Wcs10Factory.eINSTANCE.createSpatialSubsetType();

        //
        // check for CRS
        //
        String crsName = (String) kvp.get("crs");
        if (crsName == null)
            throw new WcsException("CRS parameter is mandatory", MissingParameterValue, "crs");
        final CoordinateReferenceSystem crs = decodeCRS100(crsName);
        if(crs==null)
          throw new WcsException("CRS parameter is invalid:"+crsName,InvalidParameterValue , "crs");
//        final VerticalCRS verticalCRS = CRS.getVerticalCRS(crs);
//        final boolean hasVerticalCRS = verticalCRS != null;

        //
        // at least one between BBOX and TIME must be there
        //
        final GeneralEnvelope bbox = (GeneralEnvelope) kvp.get("BBOX");
        if (bbox == null)
            throw new WcsException("bbox parameter is mandatory", MissingParameterValue, "bbox");
       
        // afabiani: consider Elevation as band, forcing the bbox to be 2D only
        if (bbox.getDimension() != 2)
            throw new WcsException("Requested bounding box is not 2-dimensional: " + bbox.getDimension(), InvalidParameterValue, "bbox");
       
        final GeneralEnvelope envelope = new GeneralEnvelope(/* TODO: ignore 3D CRS for now crs */ bbox.getDimension() == 3 ? DefaultGeographicCRS.WGS84_3D : crs);
        if (/* TODO: ignore 3D CRS for now !hasVerticalCRS */ bbox.getDimension() == 2)
            envelope.setEnvelope(bbox.getLowerCorner().getOrdinate(0), bbox.getLowerCorner()
                    .getOrdinate(1), bbox.getUpperCorner().getOrdinate(0), bbox.getUpperCorner()
                    .getOrdinate(1));
//        else if (/* TODO: ignore 3D CRS for now hasVerticalCRS */ bbox.getDimension() == 3)
//            // 3D
//            envelope.setEnvelope(bbox.getLowerCorner().getOrdinate(0), bbox.getLowerCorner()
//                    .getOrdinate(1), bbox.getLowerCorner().getOrdinate(2), bbox.getUpperCorner()
//                    .getOrdinate(0), bbox.getUpperCorner().getOrdinate(1), bbox.getUpperCorner()
//                    .getOrdinate(2));
        else
            throw new WcsException("bbox not compliant with the specified CRS", InvalidParameterValue, "bbox");
       
        //
        // TIME
        //
        TimeSequenceType timeSequence = null;
        Object time = kvp.get("TIME");
        if (time != null && time instanceof TimeSequenceType) {
            timeSequence = (TimeSequenceType) time;
        } else if (time != null && time instanceof List) {
            timeSequence = Wcs10Factory.eINSTANCE.createTimeSequenceType();
            for (Date tPos : (List<Date>) time) {
                final TimePositionType timePosition = Gml4wcsFactory.eINSTANCE
                        .createTimePositionType();
                timePosition.setValue(tPos);
                timeSequence.getTimePosition().add(timePosition);
            }
        }
        if (timeSequence == null && bbox == null)
            throw new WcsException("Bounding box cannot be null, TIME has not been specified",
                    WcsExceptionCode.MissingParameterValue, "BBOX");

        //
        // GRID management
        //
        final RectifiedGridType grid = Gml4wcsFactory.eINSTANCE.createRectifiedGridType();
        final Object w = kvp.get("width");
        final Object h = kvp.get("height");
        if (w != null && h != null) {
            //
            // normal grid management, only the envelope and the raster dimensions have been specified,
          // we need to compute RESX, RESY, RESZ afterwards
            //

            // get W and H
            int width =  w instanceof Integer?((Integer)w):Integer.parseInt((String)w);
            int height =w instanceof Integer?((Integer)h):Integer.parseInt((String)h);
            grid.getAxisName().add("x");
            grid.getAxisName().add("y");

            final Object d = kvp.get("depth");
            if (d != null) {
                // afabiani: we consider 2D grdis only
                throw new WcsException("3D grids are not supported.", InvalidParameterValue, "depth");
//                // check that the envelope is 3D or throw an error
//                if (bbox.getDimension() != 3)
//                    throw new WcsException("Found depth but envelope is of dimension "
//                            + bbox.getDimension(), InvalidParameterValue, "");
//
//                // notice that as for the spec this element represents the number of ticks on the
//                // third dimension
//                grid.getAxisName().add("z");
//
//                final int depth = Integer.parseInt((String) d);
//                grid.setDimension(BigInteger.valueOf(3));
//                // notice that the third element indicates how many layers we do have requested on the third dimension
//                grid.setLimits(new GeneralGridEnvelope(new int[] { 0, 0, 0 }, new int[] {width, height, depth }, false));
//
//
//                // 3D grid
//                grid.setDimension(BigInteger.valueOf(3));
            } else {
                // 2d grid
                grid.setDimension(BigInteger.valueOf(2));
                grid.setLimits(new GridEnvelope2D(0, 0, width, height));

            }
        } else {
            //
            // we might be working with a rectified grid request there we need
            // to try and use that type. we cannot build a raster grid at this
            // stage yet since we have no idea about how the envelope will be intersected with the
            // native envelope for this raster
            //
            final Object rx = kvp.get("resx");
            final Object ry = kvp.get("resy");
            if (rx != null && ry != null) {
                // get resx e resy but correct also the sign for them taking into account
              final CoordinateSystem cs=crs.getCoordinateSystem();
              final AxisDirection northingDirection=cs.getAxis(1).getDirection();
              final int yAxisCorrection=AxisDirection.NORTH.equals(northingDirection)?-1:1;
              final AxisDirection eastingDirection=cs.getAxis(0).getDirection();
              final int xAxisCorrection=AxisDirection.EAST.equals(eastingDirection)?1:-1;
                final double resX = Double.parseDouble((String) rx)*xAxisCorrection;
                final double resY = Double.parseDouble((String) ry)*yAxisCorrection;
               

                // now compute offset vector for the transform from the envelope
                // Following ISO 19123 we use the CELL_CENTER convention but with the raster
                final double origX = envelope.getLowerCorner().getOrdinate(0)+resX/2;
                final double origY = envelope.getUpperCorner().getOrdinate(1)+resY/2;

                // create offset point
                final PointType origin = Gml4wcsFactory.eINSTANCE.createPointType();
                final DirectPositionType dp = Gml4wcsFactory.eINSTANCE.createDirectPositionType();
                origin.setPos(dp);
                origin.setSrsName(crsName);

                // create resolutions vector
                final VectorType resolutionVector = Gml4wcsFactory.eINSTANCE.createVectorType();

                //
                // Third dimension management
                //
                final Object rz = kvp.get("resz");
                if (rz != null) {
                    // afabiani: we consider 2D grdis only
                    throw new WcsException("3D grids are not supported.", InvalidParameterValue, "resz");
//                    // eventual depth
//                    final double resZ = Double.parseDouble((String) rz);
//                    // check that the envelope is 3D or throw an error
//                    if (bbox.getDimension() != 3)
//                        throw new WcsException("Found ResZ but envelope is of dimension "
//                                + bbox.getDimension(), InvalidParameterValue, "");
//                    final double origZ = bbox.getLowerCorner().getOrdinate(2);
//
//                    // 3D grid
//                    grid.setDimension(BigInteger.valueOf(3));
//                    // set the origin position
//                    dp.setDimension(grid.getDimension());
//                    dp.setValue(Arrays.asList(origX, origY, origZ));
//                    grid.setOrigin(origin);
//
//                    // set the resolution vector
//                    resolutionVector.setDimension(grid.getDimension());
//                    resolutionVector.setValue(Arrays.asList(resX, resY, resZ));
//                    grid.getOffsetVector().add(resolutionVector);
                } else {
                    // 2d grid
                    grid.setDimension(BigInteger.valueOf(2));
                    // set the origin position
                    dp.setDimension(grid.getDimension());
                    dp.setValue(Arrays.asList(origX, origY));
                    grid.setOrigin(origin);

                    // set the resolution vector
                    resolutionVector.setDimension(grid.getDimension());
                    resolutionVector.setValue(Arrays.asList(resX, resY));
                    grid.getOffsetVector().add(resolutionVector);
                }

            } else
                throw new WcsException("Could not recognize grid resolution",
                        InvalidParameterValue, "");
        }

        spatialSubset.getEnvelope().add(envelope);
        spatialSubset.getGrid().add(grid);
        domainSubset.setSpatialSubset(spatialSubset);
        domainSubset.setTemporalSubset(timeSequence);

        return domainSubset;
    }

    private RangeSubsetType parseRangeSubset(Map kvp, String coverageName) {
        final RangeSubsetType rangeSubset = Wcs10Factory.eINSTANCE.createRangeSubsetType();

        if (kvp.get("Band") != null) {
            Object axis = kvp.get("Band");
            if (axis instanceof AxisSubsetType) {
                rangeSubset.getAxisSubset().add(axis);
            } else
                checkTypeAxisRange(rangeSubset, axis, "Band");
        }
       
        if (kvp.get("ELEVATION") != null) {
            Object axis = kvp.get("ELEVATION");
            if (axis instanceof AxisSubsetType) {
                rangeSubset.getAxisSubset().add(axis);
            } else
                checkTypeAxisRange(rangeSubset, axis, "ELEVATION");
        }

        return rangeSubset;
    }

    /**
     * @param rangeSubset
     * @param axis
     */
    private void checkTypeAxisRange(final RangeSubsetType rangeSubset, Object axis, String axisName) {
        if (axis instanceof String) {
            String bands = (String) axis;
            if (bands != null) {
                if (bands.contains("/")) {
                    List<String> unparsed = KvpUtils.readFlat(bands, new Tokenizer("/"));

                    IntervalType interval = Wcs10Factory.eINSTANCE.createIntervalType();
                    TypedLiteralType min = Wcs10Factory.eINSTANCE.createTypedLiteralType();
                    TypedLiteralType max = Wcs10Factory.eINSTANCE.createTypedLiteralType();
                    TypedLiteralType res = Wcs10Factory.eINSTANCE.createTypedLiteralType();
                    if (unparsed.size() == 2) {
                        min.setValue(unparsed.get(0));
                        max.setValue(unparsed.get(1));

                        interval.setMin(min);
                        interval.setMax(max);
                    } else {
                        min.setValue(unparsed.get(0));
                        max.setValue(unparsed.get(1));
                        res.setValue(unparsed.get(2));

                        interval.setMin(min);
                        interval.setMax(max);
                        interval.setRes(res);
                    }

                    final AxisSubsetType axisSubset = Wcs10Factory.eINSTANCE.createAxisSubsetType();

                    axisSubset.setName(axisName);

                    axisSubset.getInterval().add(interval);

                    rangeSubset.getAxisSubset().add(axisSubset);

                } else {
                    List<String> unparsed = KvpUtils.readFlat(bands, KvpUtils.INNER_DELIMETER);

                    if (unparsed.size() == 0) {
                        throw new WcsException(
                                "Requested axis subset contains wrong number of values (should have at least 1): "
                                        + unparsed.size(), WcsExceptionCode.InvalidParameterValue,
                                "band");
                    }

                    final AxisSubsetType axisSubset = Wcs10Factory.eINSTANCE.createAxisSubsetType();

                    axisSubset.setName(axisName);

                    for (String bandValue : unparsed) {
                        TypedLiteralType singleValue = Wcs10Factory.eINSTANCE.createTypedLiteralType();
                        singleValue.setValue(bandValue);

                        axisSubset.getSingleValue().add(singleValue);

                    }
                    rangeSubset.getAxisSubset().add(axisSubset);
                }
            }
        } else if (axis instanceof Double || axis instanceof Integer) {
            final AxisSubsetType axisSubset = Wcs10Factory.eINSTANCE.createAxisSubsetType();

            axisSubset.setName(axisName);

            TypedLiteralType singleValue = Wcs10Factory.eINSTANCE.createTypedLiteralType();
            singleValue.setValue(String.valueOf(axis));

            axisSubset.getSingleValue().add(singleValue);

            rangeSubset.getAxisSubset().add(axisSubset);
        }
    }

    private OutputType parseOutputElement(final Map<String,String> kvp) throws Exception {
        final OutputType output = Wcs10Factory.eINSTANCE.createOutputType();
        final CodeType crsType = Gml4wcsFactory.eINSTANCE.createCodeType();
        final CodeType formatType = Gml4wcsFactory.eINSTANCE.createCodeType();

        // check and set format
        String format = (String) kvp.get("format");
        if (format == null)
            throw new WcsException("format parameter is mandatory", MissingParameterValue, "format");

        final String crsName = (String) (kvp.get("response_crs") != null ? kvp.get("response_crs") : kvp.get("crs"));
        CoordinateReferenceSystem crs = null;
        if (crsName != null) {
            crs = decodeCRS100(crsName);

            crsType.setValue(CRS.lookupIdentifier(crs, true));

            output.setCrs(crsType);
        }

        formatType.setValue(format);

        output.setFormat(formatType);

        return output;
    }

    /**
     * DEcode the requested CRS following the WCS 1.0 style with LON,LAT axes order.
     *
     * @param crsName
     * @return
     */
    private static CoordinateReferenceSystem decodeCRS100(String crsName) throws WcsException{
        if ("WGS84(DD)".equals(crsName)) {
            crsName = "EPSG:4326";
        }

        try {
            // in 100 we work with Lon,Lat always
            return CRS.decode(crsName, true);
        } catch (NoSuchAuthorityCodeException e) {
            throw new WcsException("Could not recognize crs " + crsName, InvalidParameterValue,"crs");
        } catch (FactoryException e) {
            throw new WcsException("Could not recognize crs " + crsName, InvalidParameterValue,"crs");
        }

    }

}
TOP

Related Classes of org.geoserver.wcs.kvp.Wcs10GetCoverageRequestReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.