Package org.geoserver.wcs.response

Source Code of org.geoserver.wcs.response.DescribeCoverageTransformer$WCS111DescribeCoverageTranslator

/* 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.response;

import static org.geoserver.ows.util.ResponseUtils.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import net.opengis.wcs11.DescribeCoverageType;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageDimensionInfo;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.MetadataLinkInfo;
import org.geoserver.ows.URLMangler.URLType;
import org.geoserver.ows.util.RequestUtils;
import org.geoserver.wcs.WCSInfo;
import org.geoserver.wcs.kvp.GridType;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.LinearTransform;
import org.geotools.util.NumberRange;
import org.geotools.util.logging.Logging;
import org.geotools.xml.transform.TransformerBase;
import org.geotools.xml.transform.Translator;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.Matrix;
import org.vfny.geoserver.wcs.WcsException;
import org.vfny.geoserver.wcs.WcsException.WcsExceptionCode;
import org.vfny.geoserver.wcs.responses.CoverageResponseDelegate;
import org.vfny.geoserver.wcs.responses.CoverageResponseDelegateFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.AttributesImpl;

/**
* Based on the <code>org.geotools.xml.transform</code> framework, does the
* job of encoding a WCS 1.1.1 DescribeCoverage document.
*
* @author Andrea Aime, TOPP
*/
public class DescribeCoverageTransformer extends TransformerBase {
    private static final Logger LOGGER = Logging.getLogger(DescribeCoverageTransformer.class
            .getPackage().getName());

    private static final String WCS_URI = "http://www.opengis.net/wcs/1.1.1";

    private static final String XSI_PREFIX = "xsi";

    private static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";

    private static final Map<String, String> METHOD_NAME_MAP = new HashMap<String, String>();

    static {
        METHOD_NAME_MAP.put("nearest neighbor", "nearest");
        METHOD_NAME_MAP.put("bilinear", "linear");
        METHOD_NAME_MAP.put("bicubic", "cubic");
    }

    private WCSInfo wcs;

    private Catalog catalog;

    /**
     * Creates a new WFSCapsTransformer object.
     */
    public DescribeCoverageTransformer(WCSInfo wcs, Catalog catalog) {
        super();
        this.wcs = wcs;
        this.catalog = catalog;
        setNamespaceDeclarationEnabled(false);
    }

    public Translator createTranslator(ContentHandler handler) {
        return new WCS111DescribeCoverageTranslator(handler);
    }

    private class WCS111DescribeCoverageTranslator extends TranslatorSupport {
        private DescribeCoverageType request;

        private String proxifiedBaseUrl;

        /**
         * Creates a new WFSCapsTranslator object.
         *
         * @param handler
         *            DOCUMENT ME!
         */
        public WCS111DescribeCoverageTranslator(ContentHandler handler) {
            super(handler, null, null);
        }

        /**
         * Encode the object.
         *
         * @param o
         *            The Object to encode.
         *
         * @throws IllegalArgumentException
         *             if the Object is not encodeable.
         */
        public void encode(Object o) throws IllegalArgumentException {
            // try {
            if (!(o instanceof DescribeCoverageType)) {
                throw new IllegalArgumentException(new StringBuffer("Not a GetCapabilitiesType: ")
                        .append(o).toString());
            }

            this.request = (DescribeCoverageType) o;

            final AttributesImpl attributes = new AttributesImpl();
            attributes.addAttribute("", "xmlns:wcs", "xmlns:wcs", "", WCS_URI);

            attributes.addAttribute("", "xmlns:xlink", "xmlns:xlink", "",
                    "http://www.w3.org/1999/xlink");
            attributes.addAttribute("", "xmlns:ogc", "xmlns:ogc", "", "http://www.opengis.net/ogc");
            attributes.addAttribute("", "xmlns:ows", "xmlns:ows", "",
                    "http://www.opengis.net/ows/1.1");
            attributes.addAttribute("", "xmlns:gml", "xmlns:gml", "", "http://www.opengis.net/gml");

            final String prefixDef = new StringBuffer("xmlns:").append(XSI_PREFIX).toString();
            attributes.addAttribute("", prefixDef, prefixDef, "", XSI_URI);

            final String locationAtt = new StringBuffer(XSI_PREFIX).append(":schemaLocation")
                    .toString();

             final String locationDef = buildSchemaURL(request.getBaseUrl()"wcs/1.1.1/wcsDescribeCoverage.xsd");
           
            attributes.addAttribute("", locationAtt, locationAtt, "", locationDef);

            start("wcs:CoverageDescriptions", attributes);
            for (Iterator it = request.getIdentifier().iterator(); it.hasNext();) {
                String coverageId = (String) it.next();

                // check the coverage is known
                LayerInfo layer = catalog.getLayerByName(coverageId);
        if (layer == null || layer.getType() != LayerInfo.Type.RASTER) {
                    throw new WcsException("Could not find the specified coverage: "
                            + coverageId, WcsExceptionCode.InvalidParameterValue, "identifiers");
                }

                CoverageInfo ci = catalog.getCoverageByName(coverageId);
                try {
                    handleCoverageDescription(ci);
                } catch (Exception e) {
                    throw new RuntimeException(
                            "Unexpected error occurred during describe coverage xml encoding", e);
                }

            }
            end("wcs:CoverageDescriptions");
        }

        void handleCoverageDescription(CoverageInfo ci) throws Exception {
            start("wcs:CoverageDescription");
            element("ows:Title", ci.getTitle());
            element("ows:Abstract", ci.getDescription());
            handleKeywords(ci.getKeywords());
            element("wcs:Identifier", ci.getStore().getWorkspace().getName() + ":" + ci.getName());
            handleMetadataLinks(ci.getMetadataLinks(), "simple");
            handleDomain(ci);
            handleRange(ci);
            handleSupportedCRSs(ci);
            handleSupportedFormats(ci);
            end("wcs:CoverageDescription");
        }

        // TODO: find a way to share this with the capabilities transfomer
        private void handleMetadataLinks(List<MetadataLinkInfo> links, String linkType) {
          for (MetadataLinkInfo mdl : links) {
            if (mdl != null) {
                    AttributesImpl attributes = new AttributesImpl();

                    if ((mdl.getAbout() != null) && (mdl.getAbout() != "")) {
                        attributes.addAttribute("", "about", "about", "", mdl.getAbout());
                    }

                    if ((mdl.getMetadataType() != null) && (mdl.getMetadataType() != "")) {
                        attributes.addAttribute("", "xlink:type", "xlink:type", "", linkType);
                    }

                    if (attributes.getLength() > 0) {
                        element("ows:Metadata", null, attributes);
                    }
                }
      }
        }

        // TODO: find a way to share this with the capabilities transfomer
        private void handleKeywords(List kwords) {
            start("ows:Keywords");

            if (kwords != null) {
                for (Iterator it = kwords.iterator(); it.hasNext();) {
                    element("ows:Keyword", it.next().toString());
                }
            }

            end("ows:Keywords");
        }

        private void handleDomain(CoverageInfo ci) throws Exception {
            start("wcs:Domain");
            start("wcs:SpatialDomain");
            handleBoundingBox(ci.getLatLonBoundingBox(), true);
            handleBoundingBox(ci.boundingBox(), false);
            handleGridCRS(ci);
            end("wcs:SpatialDomain");
            end("wcs:Domain");
        }

        private void handleGridCRS(CoverageInfo ci) throws Exception {
            start("wcs:GridCRS");
            element("wcs:GridBaseCRS", urnIdentifier(ci.getCRS()));
            element("wcs:GridType", GridType.GT2dGridIn2dCrs.getXmlConstant());
            // TODO: go back to using the metadata once they can be trusted
            final LinearTransform tx = (LinearTransform) ci.getGrid().getGridToCRS();
            final Matrix matrix = tx.getMatrix();
            // origin
            StringBuffer origins = new StringBuffer();
            for (int i = 0; i < matrix.getNumRow() - 1; i++) {
                origins.append(matrix.getElement(i, matrix.getNumCol() - 1));
                if (i < matrix.getNumRow() - 2)
                    origins.append(" ");
            }
            element("wcs:GridOrigin", origins.toString());
            // offsets
            StringBuffer offsets = new StringBuffer();
            for (int i = 0; i < matrix.getNumRow() - 1; i++) {
                for (int j = 0; j < matrix.getNumCol() - 1; j++) {
                    offsets.append(matrix.getElement(i, j));
                    if (j < matrix.getNumCol() - 2)
                        offsets.append(" ");
                }
                if (i < matrix.getNumRow() - 2)
                    offsets.append(" ");

            }
            element("wcs:GridOffsets", offsets.toString());
            element("wcs:GridCS", "urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS");
            end("wcs:GridCRS");
        }

        private void handleBoundingBox(ReferencedEnvelope encodedEnvelope, boolean wgsLonLat)
                throws Exception {
            final AttributesImpl attributes = new AttributesImpl();
            final CoordinateReferenceSystem crs = encodedEnvelope.getCoordinateReferenceSystem();
            if (wgsLonLat) {
                attributes.addAttribute("", "crs", "crs", "", "urn:ogc:def:crs:OGC:1.3:CRS84");
            } else {
                String urnIdentifier = urnIdentifier(crs);
                CoordinateReferenceSystem latlonCrs = CRS.decode(urnIdentifier);
                encodedEnvelope = new ReferencedEnvelope(CRS.transform(CRS.findMathTransform(crs, latlonCrs, true),
                        encodedEnvelope));
                attributes.addAttribute("", "crs", "crs", "", urnIdentifier);
            }
            attributes.addAttribute("", "dimensions", "dimensions", "", Integer.toString(crs
                    .getCoordinateSystem().getDimension()));
            start("ows:BoundingBox", attributes);
            element("ows:LowerCorner", new StringBuffer(Double.toString(encodedEnvelope
                    .getLowerCorner().getOrdinate(0))).append(" ").append(
                    encodedEnvelope.getLowerCorner().getOrdinate(1)).toString());
            element("ows:UpperCorner", new StringBuffer(Double.toString(encodedEnvelope
                    .getUpperCorner().getOrdinate(0))).append(" ").append(
                    encodedEnvelope.getUpperCorner().getOrdinate(1)).toString());
            end("ows:BoundingBox");
        }

        private void handleRange(CoverageInfo ci) {
            start("wcs:Range");
            // at the moment we only handle single field coverages
            start("wcs:Field");
            List<CoverageDimensionInfo> dimensions = ci.getDimensions();
            element("wcs:Identifier", "contents");
            // the output domain of the field
            start("wcs:Definition");
            NumberRange range = getCoverageRange(dimensions);
            if (range == null || range.isEmpty()) {
                element("wcs:AnyValue", "");
            } else {
                start("ows:AllowedValues");
                start("ows:Range");
                element("ows:MinimumValue", Double.toString(range.getMinimum()));
                element("ows:MaximumValue", Double.toString(range.getMaximum()));
                end("ows:Range");
                end("ows:AllowedValues");
            }
            end("wcs:Definition");
            handleNullValues(dimensions);
            handleInterpolationMethods(ci);
            handleAxis(ci);
            end("wcs:Field");
            end("wcs:Range");
        }

        private void handleAxis(CoverageInfo ci) {
            final AttributesImpl attributes = new AttributesImpl();
            attributes.addAttribute("", "identifier", "identifier", "", "Bands");
            start("wcs:Axis", attributes);
            start("wcs:AvailableKeys");
            List<CoverageDimensionInfo> dimensions = ci.getDimensions();
            for (CoverageDimensionInfo cd : dimensions) {
                element("wcs:Key", cd.getName().replace(' ', '_'));
            }
            end("wcs:AvailableKeys");
            end("wcs:Axis");
        }

        /**
         * Given a set of sample dimensions, this will return a valid range only
         * if all sample dimensions have one, otherwise null
         *
         * @param dimensions
         * @return
         */
        private NumberRange getCoverageRange(List<CoverageDimensionInfo> dimensions) {
            NumberRange range = null;
            for (CoverageDimensionInfo dimension : dimensions) {
              if (dimension.getRange() == null)
                    return null;
                else if (range == null)
                    range = dimension.getRange();
                else
                    range.union(dimension.getRange());
      }
            return range;
        }

        private void handleNullValues(List<CoverageDimensionInfo> dimensions) {
          for (CoverageDimensionInfo cd : dimensions) {
                List<Double> nulls = cd.getNullValues();
                if(nulls == null)
                    return;
                if (nulls.size() == 1) {
                    element("wcs:NullValue", nulls.get(0).toString());
                } else if (nulls.size() >= 1) {
                    // the new specification allows only for a list of values,
                    // Can we assume min and max are two integer numbers and
                    // make up a list out of them? For the moment, just fail
                    throw new IllegalArgumentException("Cannot encode a range of null values, "
                            + "only single values are handled");
                }
            }
        }

        private void handleInterpolationMethods(CoverageInfo ci) {
            start("wcs:InterpolationMethods");
            for (Iterator it = ci.getInterpolationMethods().iterator(); it.hasNext();) {
                String method = (String) it.next();
                String converted = METHOD_NAME_MAP.get(method);
                if (converted != null)
                    element("wcs:InterpolationMethod", converted);

            }
            elementIfNotEmpty("wcs:Default", ci.getDefaultInterpolationMethod());
            end("wcs:InterpolationMethods");
        }

        private void handleSupportedFormats(CoverageInfo ci) throws Exception {
            // gather all the formats for this coverage
            Set<String> formats = new HashSet<String>();
            for (Iterator it = ci.getSupportedFormats().iterator(); it.hasNext();) {
                String format = (String) it.next();
                // wcs 1.1 requires mime types, not format names
                try  {
                    CoverageResponseDelegate delegate = CoverageResponseDelegateFactory
                            .encoderFor(format);
                    String formatMime = delegate.getMimeFormatFor(format);
                    if(formatMime != null)
                        formats.add(formatMime);
                } catch(Exception e) {
                    // no problem, we just want to avoid people writing HALLABALOOLA in the
                    // supported formats section of the coverage config and then break the
                    // describe response
                }
            }
            // sort them
            List<String> sortedFormats = new ArrayList<String>(formats);
            Collections.sort(sortedFormats);
            for (String format : sortedFormats) {
                element("wcs:SupportedFormat", format);
            }
           
        }

        private void handleSupportedCRSs(CoverageInfo ci) throws Exception {
            Set supportedCRSs = new LinkedHashSet();
            if (ci.getRequestSRS() != null)
                supportedCRSs.addAll(ci.getRequestSRS());
            if (ci.getResponseSRS() != null)
                supportedCRSs.addAll(ci.getResponseSRS());
            for (Iterator it = supportedCRSs.iterator(); it.hasNext();) {
                String crsName = (String) it.next();
                CoordinateReferenceSystem crs = CRS.decode(crsName);
                element("wcs:SupportedCRS", urnIdentifier(crs));
                element("wcs:SupportedCRS", crsName);
            }
        }

        private String urnIdentifier(final CoordinateReferenceSystem crs) throws FactoryException {
            String authorityAndCode = CRS.lookupIdentifier(crs, false);
            String code = authorityAndCode.substring(authorityAndCode.lastIndexOf(":") + 1);
            // we don't specify the version, but we still need to put a space
            // for it in the urn form, that's why we have :: before the code
            return "urn:ogc:def:crs:EPSG::" + code;
        }

        /**
         * Writes the element if and only if the content is not null and not
         * empty
         *
         * @param elementName
         * @param content
         */
        private void elementIfNotEmpty(String elementName, String content) {
            if (content != null && !"".equals(content.trim()))
                element(elementName, content);
        }
    }

}
TOP

Related Classes of org.geoserver.wcs.response.DescribeCoverageTransformer$WCS111DescribeCoverageTranslator

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.