    001    /*----------------------------------------------------------------------------
    002     This file is part of deegree, http://deegree.org/
    003     Copyright (C) 2001-2009 by:
    004       Department of Geography, University of Bonn
    005     and
    006       lat/lon GmbH
    007
    008     This library is free software; you can redistribute it and/or modify it under
    009     the terms of the GNU Lesser General Public License as published by the Free
    010     Software Foundation; either version 2.1 of the License, or (at your option)
    011     any later version.
    012     This library is distributed in the hope that it will be useful, but WITHOUT
    013     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    014     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    015     details.
    016     You should have received a copy of the GNU Lesser General Public License
    017     along with this library; if not, write to the Free Software Foundation, Inc.,
    018     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    019
    020     Contact information:
    021
    022     lat/lon GmbH
    023     Aennchenstr. 19, 53177 Bonn
    024     Germany
    025     http://lat-lon.de/
    026
    027     Department of Geography, University of Bonn
    028     Prof. Dr. Klaus Greve
    029     Postfach 1147, 53001 Bonn
    030     Germany
    031     http://www.geographie.uni-bonn.de/deegree/
    032
    033     e-mail: info@deegree.org
    034    ----------------------------------------------------------------------------*/
    035
    036    package org.deegree.ogcwebservices.wcts.operation;
    037
    038    import static org.deegree.framework.xml.XMLTools.getElement;
    039    import static org.deegree.framework.xml.XMLTools.getElements;
    040    import static org.deegree.framework.xml.XMLTools.getNodeAsBoolean;
    041    import static org.deegree.framework.xml.XMLTools.getNodeAsString;
    042    import static org.deegree.framework.xml.XMLTools.getStringValue;
    043    import static org.deegree.ogcbase.CommonNamespaces.DEEGREEWCTS;
    044    import static org.deegree.ogcbase.CommonNamespaces.DEEGREEWCTS_PREFIX;
    045    import static org.deegree.ogcbase.CommonNamespaces.GML_PREFIX;
    046    import static org.deegree.ogcbase.CommonNamespaces.OWS_1_1_0PREFIX;
    047    import static org.deegree.ogcbase.CommonNamespaces.WCS_1_2_0_PREFIX;
    048
    049    import java.util.ArrayList;
    050    import java.util.List;
    051
    052    import javax.vecmath.Point3d;
    053
    054    import org.deegree.crs.transformations.Transformation;
    055    import org.deegree.framework.log.ILogger;
    056    import org.deegree.framework.log.LoggerFactory;
    057    import org.deegree.framework.xml.XMLParsingException;
    058    import org.deegree.framework.xml.XMLTools;
    059    import org.deegree.i18n.Messages;
    060    import org.deegree.model.crs.CRSFactory;
    061    import org.deegree.model.crs.CoordinateSystem;
    062    import org.deegree.model.crs.UnknownCRSException;
    063    import org.deegree.model.feature.FeatureCollection;
    064    import org.deegree.model.feature.GMLFeatureCollectionDocument;
    065    import org.deegree.model.spatialschema.GMLGeometryAdapter;
    066    import org.deegree.model.spatialschema.Geometry;
    067    import org.deegree.model.spatialschema.GeometryException;
    068    import org.deegree.ogcbase.CommonNamespaces;
    069    import org.deegree.ogcbase.ExceptionCode;
    070    import org.deegree.ogcwebservices.OGCWebServiceException;
    071    import org.deegree.ogcwebservices.wcts.WCTSExceptionCode;
    072    import org.deegree.ogcwebservices.wcts.WCTService;
    073    import org.deegree.ogcwebservices.wcts.WCTServiceFactory;
    074    import org.deegree.ogcwebservices.wcts.capabilities.Content;
    075    import org.deegree.ogcwebservices.wcts.capabilities.FeatureAbilities;
    076    import org.deegree.ogcwebservices.wcts.capabilities.InputOutputFormat;
    077    import org.deegree.ogcwebservices.wcts.configuration.WCTSConfiguration;
    078    import org.deegree.ogcwebservices.wcts.data.FeatureCollectionData;
    079    import org.deegree.ogcwebservices.wcts.data.GeometryData;
    080    import org.deegree.ogcwebservices.wcts.data.SimpleData;
    081    import org.deegree.ogcwebservices.wcts.data.TransformableData;
    082    import org.deegree.owscommon_1_1_0.Manifest;
    083    import org.deegree.owscommon_1_1_0.ManifestDocument;
    084    import org.w3c.dom.Element;
    085    import org.w3c.dom.Node;
    086
    087    /**
    088     * <code>WCTSTransformDocument</code> is a helper class which supplies a constructor to parse wcts Transform requests
    089     * version 0.4.0.
    090     * <p>
    091     * Following elements are currently not supported:
    092     * <ul>
    093     * <li>wcts:transformation</li>
    094     * <li>wcs:GridCRS</li>
    095     * <li>wcts:InterpolationType, which is of type wcs:InterpolationMethodBaseType</li>
    096     * </ul>
    097     * </p>
    098     *
    099     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
    100     *
    101     * @author last edited by: $Author:$
    102     *
    103     * @version $Revision:$, $Date:$
    104     *
    105     */
    106    public class TransformDocument extends WCTSRequestBaseDocument {
    107        private static ILogger LOG = LoggerFactory.getLogger( TransformDocument.class );
    108
    109        private static final long serialVersionUID = 1343985893563449983L;
    110
    111        private final Transform transformRequest;
    112
    113        /**
    114         * @param requestId
    115         * @param rootElement
    116         *            should not be <code>null</code>
    117         * @throws OGCWebServiceException
    118         *             if an {@link XMLParsingException} occurred or a mandatory element/attribute is missing.
    119         */
    120        public TransformDocument( String requestId, Element rootElement ) throws OGCWebServiceException {
    121            super( rootElement );
    122            String version = parseVersion();
    123
    124            // check for valid request.
    125            parseService();
    126
    127            try {
    128                String sCRS = getNodeAsString( getRootElement(), PRE + "SourceCRS", nsContext, null );
    129                String tCRS = getNodeAsString( getRootElement(), PRE + "TargetCRS", nsContext, null );
    130                CoordinateSystem sourceCRS = null;
    131                CoordinateSystem targetCRS = null;
    132                TransformationReference transformationReference = null;
    133
    134                /**
    135                 * Try to parse the xml choice.
    136                 */
    137                if ( ( sCRS != null && tCRS == null ) || ( sCRS == null && tCRS != null ) ) {
    138                    throw new OGCWebServiceException(
    139                                                      Messages.getMessage(
    140                                                                           "WCTS_ISTRANSFORMABLE_MISSING_CRS",
    141                                                                           ( ( sCRS == null ) ? "TargetCRS" : "SourceCRS" ),
    142                                                                           ( ( sCRS == null ) ? "SourceCRS" : "TargetCRS" ) ),
    143                                                      ExceptionCode.INVALIDPARAMETERVALUE );
    144                }
    145                if ( sCRS != null && tCRS != null ) {
    146                    sourceCRS = CRSFactory.create( WCTService.CRS_PROVIDER, sCRS );
    147                    targetCRS = CRSFactory.create( WCTService.CRS_PROVIDER, tCRS );
    148                } else {
    149                    // Check for supported transformation element.
    150                    Element transformation = getElement( getRootElement(), PRE + "Transformation", nsContext );
    151                    if ( transformation != null ) {
    152                        transformationReference = handleTransformation( transformation );
    153                    }
    154                    if ( transformationReference == null ) {
    155                        throw new OGCWebServiceException(
    156                                                          Messages.getMessage( "WCTS_NOT_VALID_XML_CHOICE",
    157                                                                               PRE + "SourceCRS/TargetCRS and " + PRE
    158                                                                                                       + "Transformation" ),
    159                                                          ExceptionCode.MISSINGPARAMETERVALUE );
    160                    }
    161                }
    162                // Check for not supported gridcrs.
    163                Element gridCRS = getElement( getRootElement(), WCS_1_2_0_PREFIX + ":GridCRS", nsContext );
    164                if ( gridCRS != null ) {
    165                    throw new OGCWebServiceException( Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
    166                                                                           "Definition of output GridCRS ("
    167                                                                                                   + WCS_1_2_0_PREFIX
    168                                                                                                   + ":GridCRS element)" ),
    169                                                      ExceptionCode.OPERATIONNOTSUPPORTED );
    170                }
    171
    172                Element inputDataElement = getElement( getRootElement(), OWS_1_1_0PREFIX + ":InputData", nsContext );
    173                Manifest inputData = null;
    174                TransformableData<?> transformableData = null;
    175                int dataPresentation = Transform.MULTIPART;
    176                if ( inputDataElement != null ) {
    177                    ManifestDocument doc = new ManifestDocument();
    178                    inputData = doc.parseManifestType( inputDataElement );
    179                    /**
    180                     * get deegree specific elements. The featurecollections provided by the mime/multiparts were put
    181                     * beneath the d_wcts:InsertedMultiparts.
    182                     */
    183                    Element multiParts = getElement( inputDataElement, DEEGREEWCTS_PREFIX + ":MultiParts", nsContext );
    184                    if ( multiParts != null ) {
    185                        List<FeatureCollection> allData = parseFeatureCollectionData( multiParts );
    186                        transformableData = new FeatureCollectionData( allData );
    187                    }
    188                } else {
    189                    LOG.logDebug( "Found no " + OWS_1_1_0PREFIX
    190                                  + ":InputData element, now checking for the deegree element" );
    191                    inputDataElement = getElement( getRootElement(), DEEGREEWCTS_PREFIX + ":InputData", nsContext );
    192                    if ( inputDataElement != null ) {
    193                        ManifestDocument doc = new ManifestDocument();
    194                        inputData = doc.parseManifestType( inputDataElement );
    195                        Element inlineData = getElement( inputDataElement, DEEGREEWCTS_PREFIX + ":InlineData", nsContext );
    196                        if ( inlineData != null ) {
    197                            if ( sourceCRS == null ) {
    198                                WCTSConfiguration config = WCTServiceFactory.getConfiguration();
    199                                Content cont = config.getContents();
    200                                if ( transformationReference == null ) {
    201                                    throw new OGCWebServiceException(
    202                                                                      Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
    203                                                                                           " transforming of simple data without a transformation or source CRS " ),
    204                                                                      ExceptionCode.OPERATIONNOTSUPPORTED );
    205                                }
    206                                Transformation trans = cont.getTransformations().get(
    207                                                                                      transformationReference.gettransformationId() );
    208                                if ( trans == null || trans.getSourceCRS() == null ) {
    209                                    throw new OGCWebServiceException(
    210                                                                      Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
    211                                                                                           " transforming of simple data without a transformation or source CRS " ),
    212                                                                      ExceptionCode.OPERATIONNOTSUPPORTED );
    213                                }
    214                                transformableData = parseInlineData( CRSFactory.create( trans.getSourceCRS() ), inlineData );
    215                            } else {
    216                                transformableData = parseInlineData( sourceCRS, inlineData );
    217                            }
    218                            dataPresentation = Transform.INLINE;
    219                        } else {
    220                            // Handle the xlink:href attributes of the inputdata/referencegroup/reference@xlink:href.
    221                        }
    222                    }
    223                }
    224                if ( inputData == null || transformableData == null ) {
    225                    throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_MISSING_DATA" ),
    226                                                      WCTSExceptionCode.NO_INPUT_DATA );
    227                }
    228
    229                // Check for not supported interpolationType.
    230                Element interpolationType = getElement( getRootElement(), PRE + "InterpolationType", nsContext );
    231                if ( interpolationType != null ) {
    232                    throw new OGCWebServiceException(
    233                                                      Messages.getMessage(
    234                                                                           "WCTS_OPERATION_NOT_SUPPORTED",
    235                                                                           "Defining an InterpolationType ("
    236                                                                                                   + PRE
    237                                                                                                   + "InterpolationType element)" ),
    238                                                      ExceptionCode.OPERATIONNOTSUPPORTED );
    239                }
    240
    241                String outputFormat = getNodeAsString( getRootElement(), PRE + "OutputFormat", nsContext, null );
    242                if ( outputFormat != null && !"".equals( outputFormat.trim() )
    243                     && !"text/xml; gmlVersion=3.1.1".equalsIgnoreCase( outputFormat.trim() ) ) {
    244                    WCTSConfiguration config = WCTServiceFactory.getConfiguration();
    245                    boolean outputFormatDefined = false;
    246                    if ( config != null ) {
    247                        Content content = config.getContents();
    248                        if ( content != null ) {
    249                            FeatureAbilities fa = content.getFeatureAbilities();
    250                            if ( fa != null ) {
    251                                List<InputOutputFormat> formats = fa.getFeatureFormats();
    252                                if ( formats != null ) {
    253                                    for ( InputOutputFormat format : formats ) {
    254                                        if ( outputFormatDefined && format != null && format.canOutput() ) {
    255                                            outputFormat.equals( format.getValue() );
    256                                            outputFormatDefined = true;
    257                                        }
    258                                    }
    259                                }
    260                            }
    261                        }
    262                    }
    263                    if ( !outputFormatDefined ) {
    264                        throw new OGCWebServiceException( Messages.getMessage( "WCTS_REQUESTED_OUTPUTFORMAT_NOT_KNOWN",
    265                                                                               outputFormat, "Transform" ),
    266                                                          ExceptionCode.INVALIDPARAMETERVALUE );
    267                    }
    268
    269                } else {
    270                    outputFormat = "text/xml";
    271                }
    272                boolean store = getNodeAsBoolean( getRootElement(), "@store", nsContext, true );
    273                this.transformRequest = new Transform( version, requestId, store, sourceCRS, targetCRS,
    274                                                       transformationReference, inputData, transformableData, outputFormat,
    275                                                       dataPresentation );
    276
    277            } catch ( XMLParsingException e ) {
    278                LOG.logError( e.getMessage(), e );
    279                throw new OGCWebServiceException( e.getMessage(), ExceptionCode.NOAPPLICABLECODE );
    280            } catch ( UnknownCRSException e ) {
    281                LOG.logError( e.getMessage(), e );
    282                throw new OGCWebServiceException( e.getMessage(), ExceptionCode.NOAPPLICABLECODE );
    283            }
    284        }
    285
    286        /**
    287         * @param rootElement
    288         * @return the transform reference.
    289         *
    290         * @throws XMLParsingException
    291         *             if the xlink:href was not given.
    292         */
    293        private TransformationReference handleTransformation( Element rootElement )
    294                                throws XMLParsingException {
    295            if ( rootElement == null ) {
    296                LOG.logDebug( "No transformation element given, using standard transformation type." );
    297                return null;
    298            }
    299            String id = rootElement.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), "href" );
    300            String sourceID = null;
    301            String targetID = null;
    302            if ( id == null || "".equals( id.trim() ) ) {
    303                Element sCRSNode = XMLTools.getElement( rootElement, PRE + "sourceCRS", nsContext );
    304                Element tCRSNode = XMLTools.getElement( rootElement, PRE + "targetCRS", nsContext );
    305                if ( ( sCRSNode == null && tCRSNode != null ) || ( sCRSNode != null && tCRSNode == null ) ) {
    306                    throw new XMLParsingException(
    307                                                   Messages.getMessage(
    308                                                                        "WCTS_ISTRANSFORMABLE_MISSING_CRS",
    309                                                                        ( ( sCRSNode == null ) ? "TargetCRS" : "SourceCRS" ),
    310                                                                        ( ( tCRSNode == null ) ? "SourceCRS" : "TargetCRS" ) ) );
    311                }
    312                if ( sCRSNode != null ) {
    313                    sourceID = sCRSNode.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), "href" );
    314                }
    315                if ( tCRSNode != null ) {
    316                    targetID = tCRSNode.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), "href" );
    317                }
    318                LOG.logDebug( "The evaluation os supplied sourceID: ", sourceID, " and/or targetID: ", targetID,
    319                              " are currently not supported." );
    320                throw new XMLParsingException( "Currently only referencing of transformations is supported." );
    321            }
    322
    323            return new TransformationReference( id );
    324
    325        }
    326
    327        /**
    328         * Parses the deegree inlinedata element.
    329         *
    330         * @param sourceCRS
    331         *            of the data.
    332         * @param targetCRS
    333         *            in which the data is to be transformed.
    334         * @param inlineData
    335         *            element to extract the data from.
    336         * @return a {@link TransformableData} element instantiated with the right type.
    337         * @throws OGCWebServiceException
    338         *             if for any reason the data could not be parsed or processed.
    339         */
    340        private TransformableData<?> parseInlineData( CoordinateSystem sourceCRS, Node inlineData )
    341                                throws OGCWebServiceException {
    342            Node firstChild = null;
    343            try {
    344                firstChild = getElement( inlineData, "*[1]", nsContext );
    345            } catch ( XMLParsingException e ) {
    346                LOG.logError( e.getMessage(), e );
    347            }
    348            if ( firstChild != null ) {
    349                LOG.logDebug( "Incoming inlineData has localname: " + inlineData.getLocalName()
    350                              + " has a firstchild with localname: " + firstChild.getLocalName() );
    351                String prefix = firstChild.getPrefix();
    352                String nameSpace = firstChild.getNamespaceURI();
    353                if ( prefix != null ) {
    354                    String tmp = firstChild.lookupNamespaceURI( prefix );
    355                    if ( tmp != null && !"".equals( tmp ) ) {
    356                        nameSpace = tmp;
    357                    }
    358                }
    359                if ( nameSpace == null ) {
    360                    nameSpace = "";
    361                }
    362                LOG.logDebug( "Firstchild is bound to namespace: " + nameSpace );
    363                if ( !DEEGREEWCTS.toASCIIString().equalsIgnoreCase( nameSpace.trim() ) ) {
    364                    LOG.logError( "The node beneath an " + DEEGREEWCTS_PREFIX
    365                                  + ":inlineData element must be bound to the deegree-wcts (" + DEEGREEWCTS.toASCIIString()
    366                                  + ") name space, found following namespace: " + nameSpace );
    367                } else {
    368                    String localName = firstChild.getLocalName();
    369                    if ( localName != null ) {
    370                        localName = localName.trim();
    371                        if ( "SimpleData".equals( localName ) ) {
    372                            SimpleData result = parseSimpleData( sourceCRS, (Element) firstChild );
    373                            if ( result == null ) {
    374                                result = new SimpleData();
    375                            }
    376                            return result;
    377                        } else if ( "GeometryData".equals( localName ) ) {
    378                            return new GeometryData( parseGeometryData( sourceCRS.getIdentifier(), (Element) firstChild ) );
    379                        } else if ( "FeatureCollectionData".equals( localName ) ) {
    380                            return new FeatureCollectionData( parseFeatureCollectionData( (Element) firstChild ) );
    381                        } else {
    382                            throw new OGCWebServiceException(
    383                                                              Messages.getMessage( "WCTS_TRANSFORM_UNKNOWN_INLINE_DATA",
    384                                                                                   localName,
    385                                                                                   "SimpleData, GeometryData or FeatureCollectionData" ),
    386                                                              ExceptionCode.INVALIDPARAMETERVALUE );
    387                        }
    388
    389                    }
    390                }
    391            }
    392            throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_MISSING_DATA" ),
    393                                              WCTSExceptionCode.NO_INPUT_DATA );
    394        }
    395
    396        /**
    397         * @param simpleData
    398         *            the dom-xml element to be parsed.
    399         * @return a list of point3d's or <code>null</code> if the given parameter <code>null</code>.
    400         * @throws OGCWebServiceException
    401         *             if the number of points is not congruent with the dimension.
    402         */
    403        private SimpleData parseSimpleData( CoordinateSystem sourceCRS, Element simpleData )
    404                                throws OGCWebServiceException {
    405            if ( simpleData == null ) {
    406                return null;
    407            }
    408
    409            String cs = simpleData.getAttribute( "cs" );
    410            if ( cs == null || "".equals( cs ) ) {
    411                cs = ",";
    412            }
    413            String ts = simpleData.getAttribute( "ts" );
    414            if ( ts == null || "".equals( ts ) ) {
    415                ts = " ";
    416            }
    417            String values = getStringValue( simpleData );
    418            List<Point3d> points = SimpleData.parseData( values, sourceCRS.getDimension(), cs, ts, "." );
    419            if ( points.size() == 0 ) {
    420                throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_MISSING_DATA" ),
    421                                                  WCTSExceptionCode.NO_INPUT_DATA );
    422            }
    423            return new SimpleData( points, cs, ts );
    424        }
    425
    426        /**
    427         * Parse the featurecollections from the given featureCollectionsData element.
    428         *
    429         * @param featureCollectionData
    430         *            (a deegreewcts:inlineElement/deegreewcts:FeatureCollectionData or a deegreewcts:mulipart element).
    431         * @return the list of feature collections.
    432         * @throws OGCWebServiceException
    433         *             if no feature collections were found or an xml parsing exception occurred.
    434         */
    435        private List<FeatureCollection> parseFeatureCollectionData( Element featureCollectionData )
    436                                throws OGCWebServiceException {
    437            if ( featureCollectionData == null ) {
    438                return null;
    439            }
    440            List<FeatureCollection> transformableData = new ArrayList<FeatureCollection>();
    441            try {
    442                List<Element> fcElements = getElements( featureCollectionData, GML_PREFIX + ":FeatureCollection", nsContext );
    443                if ( fcElements == null || fcElements.size() == 0 ) {
    444                    LOG.logError( "Could not find any feature collections, this is strange!" );
    445                    throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_NO_DATA_FOUND",
    446                                                                           "gml:FeatureCollection" ),
    447                                                      WCTSExceptionCode.NO_INPUT_DATA );
    448                }
    449                GMLFeatureCollectionDocument fd = new GMLFeatureCollectionDocument( true, true );
    450                for ( Element fc : fcElements ) {
    451                    fd.setRootElement( fc );
    452                    FeatureCollection data = fd.parse();
    453                    if ( data != null ) {
    454                        transformableData.add( data );
    455                    }
    456                }
    457            } catch ( XMLParsingException e ) {
    458                LOG.logError( e.getMessage(), e );
    459                throw new OGCWebServiceException( e.getMessage(), ExceptionCode.NOAPPLICABLECODE );
    460            }
    461            return transformableData;
    462        }
    463
    464        /**
    465         * Parse the geometries from the given geometries data element.
    466         *
    467         * @param sourceCRSID
    468         *            needed for the wrap function of the GMLGeometrieAdapter.
    469         * @param geometryData
    470         *            (an deegreewcts:inlineElement/deegreewcts:GeometryData or a deegreewcts:mulipart element).
    471         * @return the list of geometries.
    472         * @throws OGCWebServiceException
    473         *             if no feature collections were found or an xml parsing exception occurred.
    474         */
    475        private List<Geometry> parseGeometryData( String sourceCRSID, Element geometryData )
    476                                throws OGCWebServiceException {
    477            if ( geometryData == null ) {
    478                return null;
    479            }
    480            List<Geometry> transformableData = new ArrayList<Geometry>();
    481            try {
    482                List<Element> geomElements = getElements( geometryData, "*", nsContext );
    483                if ( geomElements == null || geomElements.size() == 0 ) {
    484                    LOG.logError( "Could not find any geometries, this is strange!" );
    485                    throw new OGCWebServiceException(
    486                                                      Messages.getMessage( "WCTS_TRANSFORM_NO_DATA_FOUND", "gml:Geometries" ),
    487                                                      WCTSExceptionCode.NO_INPUT_DATA );
    488                }
    489                for ( Element fc : geomElements ) {
    490                    try {
    491                        Geometry data = GMLGeometryAdapter.wrap( fc, sourceCRSID );
    492                        if ( data != null ) {
    493                            transformableData.add( data );
    494                        }
    495                    } catch ( GeometryException e ) {
    496                        LOG.logError( e.getMessage(), e );
    497                    }
    498                }
    499            } catch ( XMLParsingException e ) {
    500                LOG.logError( e.getMessage(), e );
    501                throw new OGCWebServiceException( e.getMessage(), ExceptionCode.NOAPPLICABLECODE );
    502            }
    503            return transformableData;
    504        }
    505
    506        /**
    507         * @return the transformRequest may be <code>null</code>.
    508         */
    509        public final Transform getTransformRequest() {
    510            return transformRequest;
    511        }
    512
    513    }