001    //$HeadURL: $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.ogcwebservices.wcts.operation;
038    
039    import java.util.List;
040    import java.util.Map;
041    
042    import javax.vecmath.Point3d;
043    
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.i18n.Messages;
047    import org.deegree.model.crs.CRSFactory;
048    import org.deegree.model.crs.CoordinateSystem;
049    import org.deegree.model.crs.UnknownCRSException;
050    import org.deegree.ogcbase.ExceptionCode;
051    import org.deegree.ogcwebservices.OGCWebServiceException;
052    import org.deegree.ogcwebservices.wcts.WCTSExceptionCode;
053    import org.deegree.ogcwebservices.wcts.WCTService;
054    import org.deegree.ogcwebservices.wcts.data.FeatureCollectionData;
055    import org.deegree.ogcwebservices.wcts.data.GeometryData;
056    import org.deegree.ogcwebservices.wcts.data.SimpleData;
057    import org.deegree.ogcwebservices.wcts.data.TransformableData;
058    import org.deegree.owscommon_1_1_0.Manifest;
059    
060    /**
061     * <code>Transform</code> is an encapsulation of a Transform request defined in the wcts 0.4.0 specification.
062     *
063     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
064     *
065     * @author last edited by: $Author:$
066     *
067     * @version $Revision:$, $Date:$
068     *
069     */
070    public class Transform extends WCTSRequestBase {
071    
072        /**
073         * Signals that the data was presented inline.
074         */
075        public final static int INLINE = 0;
076    
077        /**
078         * Signals that the data was presented in multiparts.
079         */
080        public final static int MULTIPART = 1;
081    
082        private static ILogger LOG = LoggerFactory.getLogger( Transform.class );
083    
084        private static final long serialVersionUID = -7695383750627152056L;
085    
086        private final boolean store;
087    
088        private final CoordinateSystem sourceCRS;
089    
090        private final CoordinateSystem targetCRS;
091    
092        private final Manifest inputData;
093    
094        private final String inputDataString;
095    
096        private final String outputFormat;
097    
098        private final TransformableData<?> transformableData;
099    
100        private String requestIP = "Unknown IP";
101    
102        private final boolean extensiveLogging = false;
103    
104        private final int dataPresentation;
105    
106        private final TransformationReference transformationReference;
107    
108        /**
109         * @param version
110         *            of the request (0.4.0)
111         * @param requestID
112         *            internal id of the request.
113         * @param store
114         * @param sourceCRS
115         * @param targetCRS
116         * @param transformationReference
117         *            a bean holding the reference to a configured (or user defined) reference or
118         * @param inputData
119         * @param transformableData
120         *            an encapsulation of all kinds of possible transformable data.
121         * @param outputFormat
122         * @param dataPresentation
123         *            a flag signaling the way the data was presented to the wcts. Valid values are {@link #INLINE} and
124         *            {@link #MULTIPART}. If another value is given, {@link #MULTIPART} is assumed.
125         * @throws IllegalArgumentException
126         *             if the transformableData was <code>null</code>.
127         */
128        public Transform( String version, String requestID, boolean store, CoordinateSystem sourceCRS,
129                          CoordinateSystem targetCRS, TransformationReference transformationReference, Manifest inputData,
130                          TransformableData<?> transformableData, String outputFormat, int dataPresentation )
131                                throws IllegalArgumentException {
132            super( version, requestID, null );
133            this.store = store;
134            this.sourceCRS = sourceCRS;
135            this.targetCRS = targetCRS;
136            this.transformationReference = transformationReference;
137            if ( sourceCRS == null && targetCRS == null && transformationReference == null ) {
138                throw new IllegalArgumentException( Messages.getMessage( "WCTS_INVALID_CONSTRUCT",
139                                                                         "Source/Target, TransformationReference" ) );
140            }
141    
142            this.inputData = inputData;
143            this.inputDataString = null;
144            this.outputFormat = outputFormat;
145            if ( transformableData == null ) {
146                throw new IllegalArgumentException( Messages.getMessage( "WCTS_MISSING_ARGUMENT", transformableData ) );
147            }
148            this.transformableData = transformableData;
149            if ( dataPresentation != INLINE && dataPresentation != MULTIPART ) {
150                dataPresentation = MULTIPART;
151            }
152            this.dataPresentation = dataPresentation;
153        }
154    
155        /**
156         * @return true if the transformed data should be stored.
157         */
158        public final boolean mustStore() {
159            return store;
160        }
161    
162        /**
163         * @return the sourceCRS.
164         */
165        public final CoordinateSystem getSourceCRS() {
166            return sourceCRS;
167        }
168    
169        /**
170         * @return the targetCRS.
171         */
172        public final CoordinateSystem getTargetCRS() {
173            return targetCRS;
174        }
175    
176        /**
177         * @return the inputData, may be <code>null</code>, if so, check {@link #getInputDataString()} to see if the
178         *         request defined a location by kvp.
179         */
180        public final Manifest getInputData() {
181            return inputData;
182        }
183    
184        /**
185         * @return the inputDataString, supplied by kvp. Maybe <code>null</code>, if so check {@link #getInputData()} to
186         *         see if an xml encoded inputdata object was supplied.
187         */
188        public final String getInputDataString() {
189            return inputDataString;
190        }
191    
192        /**
193         * @return the outputFormat.
194         */
195        public final String getOutputFormat() {
196            return outputFormat;
197        }
198    
199        /**
200         * Create a {@link Transform}-request by extracting the values from the map, and calling the constructor with these
201         * values.
202         *
203         * @param requestID
204         *            service internal id for this request.
205         * @param map
206         *            to extract requested values from.
207         * @return the bean representation
208         * @throws OGCWebServiceException
209         *             if the map is <code>null</code> or has size==0, or the service,request parameters have none
210         *             accepted values.
211         */
212        public static Transform create( String requestID, Map<String, String> map )
213                                throws OGCWebServiceException {
214            if ( map == null || map.size() == 0 ) {
215                throw new OGCWebServiceException( Messages.getMessage( "WCTS_REQUESTMAP_NULL" ),
216                                                  ExceptionCode.MISSINGPARAMETERVALUE );
217            }
218            String service = map.get( "SERVICE" );
219            if ( service == null || !"WCTS".equals( service ) ) {
220                throw new OGCWebServiceException( Messages.getMessage( "WCTS_NO_SERVICE_KVP", service ),
221                                                  ExceptionCode.MISSINGPARAMETERVALUE );
222            }
223            String request = map.get( "REQUEST" );
224            if ( request == null || !"Transform".equalsIgnoreCase( request ) ) {
225                throw new OGCWebServiceException( Messages.getMessage( "WCTS_NO_REQUEST_KVP", "Transform" ),
226                                                  ( request == null ? ExceptionCode.MISSINGPARAMETERVALUE
227                                                                   : ExceptionCode.OPERATIONNOTSUPPORTED ) );
228            }
229            String version = map.get( "VERSION" );
230            if ( version == null || !WCTService.version.equalsIgnoreCase( version ) ) {
231                throw new OGCWebServiceException( Messages.getMessage( "WCTS_NO_VERSION_KVP", version ),
232                                                  ExceptionCode.MISSINGPARAMETERVALUE );
233            }
234    
235            String sCRS = map.get( "SOURCECRS" );
236            String tCRS = map.get( "TARGETCRS" );
237            TransformationReference transformationReference = null;
238            if ( ( ( sCRS != null && !"".equals( sCRS.trim() ) ) && ( tCRS == null || "".equals( tCRS.trim() ) ) )
239                 || ( ( tCRS != null && !"".equals( tCRS.trim() ) ) && ( sCRS == null || "".equals( sCRS.trim() ) ) ) ) {
240                throw new OGCWebServiceException( Messages.getMessage( "WCTS_MISSING_MUTUAL_KEY_KVP",
241                                                                       ( ( sCRS == null ) ? "TargetCRS" : "SourceCRS" ),
242                                                                       ( ( sCRS == null ) ? "SourceCRS" : "TargetCRS" ) ),
243                                                  ExceptionCode.INVALIDPARAMETERVALUE );
244            }
245            if ( ( sCRS == null || "".equals( sCRS.trim() ) ) && ( tCRS == null || "".equals( tCRS.trim() ) ) ) {
246                String transformation = map.get( "TRANSFORMATION" );
247                if ( !( transformation == null || "".equals( transformation.trim() ) ) ) {
248                    transformationReference = new TransformationReference( transformation );
249                    //
250                    // throw new OGCWebServiceException(
251                    // Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
252                    // "defining of transformations (Transformation key)" ),
253                    // ExceptionCode.OPERATIONNOTSUPPORTED );
254                }
255                throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORMATION_NO_CRS_OR_TRANSFORM_KVP" ),
256                                                  ExceptionCode.MISSINGPARAMETERVALUE );
257    
258            }
259            CoordinateSystem sourceCRS = null;
260            CoordinateSystem targetCRS = null;
261            try {
262                sourceCRS = CRSFactory.create( WCTService.CRS_PROVIDER, sCRS );
263                targetCRS = CRSFactory.create( WCTService.CRS_PROVIDER, tCRS );
264            } catch ( UnknownCRSException e ) {
265                throw new OGCWebServiceException( e.getMessage(), WCTSExceptionCode.UNSUPPORTED_COMBINATION );
266            }
267    
268            int dataRepresentation = MULTIPART;
269            String inputData = map.get( "INPUTDATA" );
270            if ( inputData == null || "".equals( inputData ) ) {
271                throw new OGCWebServiceException( Messages.getMessage( "WCTS_MISSING_MANDATORY_KEY_KVP", "inputData" ),
272                                                  ExceptionCode.MISSINGPARAMETERVALUE );
273            }
274            TransformableData<?> theData = FeatureCollectionData.parseFeatureCollection( inputData );
275            if ( theData == null ) {
276                dataRepresentation = INLINE;
277                LOG.logDebug( "Could not generate a feature collection, trying GeometryData" );
278                theData = GeometryData.parseGeometryData( sourceCRS, inputData );
279                if ( theData == null ) {
280                    LOG.logDebug( "Could not generate a feature collection nor a geometry, trying SimpleData" );
281                    String cs = map.get( "CS" );
282                    if ( cs == null || "".equals( cs ) ) {
283                        LOG.logDebug( "CS is set to a space ' '." );
284                        cs = " ";
285                    }
286                    String ts = map.get( "TS" );
287                    if ( ts == null || "".equals( ts ) ) {
288                        LOG.logDebug( "TS is set to comma ','." );
289                        ts = ",";
290                    }
291                    String ds = map.get( "DS" );
292                    if ( ds == null || "".equals( ds ) ) {
293                        LOG.logDebug( "DS is set to point '.'." );
294                        ds = ".";
295                    }
296                    List<Point3d> points = SimpleData.parseData( inputData, sourceCRS.getDimension(), cs, ts, ds );
297                    if ( points.size() > 0 ) {
298                        theData = new SimpleData( points, cs, ts );
299                    } else {
300                        LOG.logError( "Didn't find any parsable data, this transform can not be handled." );
301                        throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_MISSING_DATA" ),
302                                                          WCTSExceptionCode.NO_INPUT_DATA );
303                    }
304                }
305            }
306    
307            String interPolationType = map.get( "INTERPOLATIONTYPE" );
308            if ( !( interPolationType == null || "".equals( interPolationType.trim() ) ) ) {
309                throw new OGCWebServiceException( Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
310                                                                       "InterpolationType (key)" ),
311                                                  ExceptionCode.OPERATIONNOTSUPPORTED );
312            }
313    
314            String outputFormat = map.get( "OUTPUTFORMAT" );
315    
316            String st = map.get( "STORE" );
317            boolean store = false;
318    
319            if ( st != null && !"".equals( st.trim() ) ) {
320                store = "true".equalsIgnoreCase( st ) || "yes".equalsIgnoreCase( st ) || "1".equalsIgnoreCase( st );
321            }
322            return new Transform( version, requestID, store, sourceCRS, targetCRS, transformationReference, null, theData,
323                                  outputFormat, dataRepresentation );
324        }
325    
326        /**
327         * @return the transformableData, as an encapsulation of a
328         */
329        public final TransformableData<?> getTransformableData() {
330            return transformableData;
331        }
332    
333        /**
334         * @param requestIP
335         *            or <code>null</code> if not known.
336         */
337        public void setRequestIP( String requestIP ) {
338            if ( requestIP != null && !"".equals( requestIP.trim() ) ) {
339                this.requestIP = requestIP;
340            }
341    
342        }
343    
344        /**
345         * @return the requestIP or 'Unknown IP' if the ip-address of the request was not set/known.
346         */
347        public final String getRequestIP() {
348            return requestIP;
349        }
350    
351        /**
352         * @return true if the logging should be extensive.
353         */
354        public final boolean extensiveLogging() {
355            return extensiveLogging;
356        }
357    
358        /**
359         * @return a flag signaling the way the data was presented to the wcts. Valid values are {@link #INLINE} and
360         *         {@link #MULTIPART}.
361         */
362        public final int getDataPresentation() {
363            return dataPresentation;
364        }
365    
366        /**
367         * @return the transformationReference which references a transformation, may be <code>null</code>
368         */
369        public final TransformationReference getTransformationReference() {
370            return transformationReference;
371        }
372    
373    }