001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/portal/standard/csw/control/ISO19115RequestFactory.java $
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.portal.standard.csw.control;
038    
039    import java.io.BufferedReader;
040    import java.io.InputStream;
041    import java.io.InputStreamReader;
042    import java.util.Properties;
043    
044    import org.deegree.datatypes.QualifiedName;
045    import org.deegree.enterprise.control.RPCStruct;
046    import org.deegree.framework.log.ILogger;
047    import org.deegree.framework.log.LoggerFactory;
048    import org.deegree.framework.util.StringTools;
049    import org.deegree.i18n.Messages;
050    import org.deegree.model.crs.CRSFactory;
051    import org.deegree.model.crs.CoordinateSystem;
052    import org.deegree.model.crs.GeoTransformer;
053    import org.deegree.model.crs.UnknownCRSException;
054    import org.deegree.model.filterencoding.Literal;
055    import org.deegree.model.filterencoding.Operation;
056    import org.deegree.model.filterencoding.OperationDefines;
057    import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
058    import org.deegree.model.filterencoding.PropertyIsLikeOperation;
059    import org.deegree.model.filterencoding.PropertyIsNullOperation;
060    import org.deegree.model.filterencoding.PropertyName;
061    import org.deegree.model.filterencoding.SpatialOperation;
062    import org.deegree.model.spatialschema.Envelope;
063    import org.deegree.model.spatialschema.Geometry;
064    import org.deegree.model.spatialschema.GeometryException;
065    import org.deegree.model.spatialschema.GeometryFactory;
066    import org.deegree.portal.standard.csw.CatalogClientException;
067    
068    /**
069     * A <code>${type_name}</code> class.<br/>
070     *
071     * class for creating a get GetRecord Request against a catalog based on OGC Stateless Web Service Catalog Profil and
072     * GDI NRW catalog specifications to access data metadata (ISO 19115).
073     * <p>
074     * The only public method of the class receives a 'model' represented by a <tt>HashMap</tt> that contains the request
075     * parameters as name-value-pairs. The names corresponds to the form-field-names. For common this will be the fields of
076     * a HTML-form but it can be any other form (e.g. swing-application)
077     * </p>
078     *
079     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
080     * @author last edited by: $Author: jmays $
081     *
082     * @version $Revision: 19183 $, $Date: 2009-08-17 18:05:15 +0200 (Mo, 17 Aug 2009) $
083     */
084    public class ISO19115RequestFactory extends CSWRequestFactory {
085    
086        private static final ILogger LOG = LoggerFactory.getLogger( ISO19115RequestFactory.class );
087    
088        static final String RPC_SIMPLESEARCH = "RPC_SIMPLESEARCH";
089    
090        private static final char WILDCARD = '*';
091    
092        // private static final String OUTPUTSCHEMA = "csw:profile";
093        private static final String OUTPUTSCHEMA = "http://www.isotc211.org/2005/gmd";
094    
095        private RPCStruct struct = null;
096    
097        private Properties requestElementsProps = new Properties();
098    
099        /**
100         *
101         */
102        public ISO19115RequestFactory() {
103            try {
104                InputStream is = ISO19115RequestFactory.class.getResourceAsStream( "ISO19115requestElements.properties" );
105                this.requestElementsProps.load( is );
106            } catch ( Exception e ) {
107                LOG.logError( e.getLocalizedMessage(), e );
108            }
109        }
110    
111        /**
112         * creates a GetRecord request that is conform to the OGC Stateless Web Service Catalog Profil and GDI NRW catalog
113         * specifications from a RPC struct.
114         *
115         * @param struct
116         *            RPC structure containing the request parameter
117         * @param resultType
118         * @return GetFeature request as a string
119         * @throws CatalogClientException
120         */
121        @Override
122        public String createRequest( RPCStruct struct, String resultType )
123                                throws CatalogClientException {
124    
125            this.struct = struct;
126            boolean isSearchRequest = false;
127            boolean isOverviewRequest = false;
128    
129            if ( "HITS".equals( resultType ) || "RESULTS".equals( resultType ) ) {
130                isSearchRequest = true;
131                LOG.logDebug( "request is searchRequest" );
132            } else if ( resultType == null ) {
133                LOG.logDebug( "request is overviewRequest" );
134                isOverviewRequest = true;
135            }
136    
137            InputStream is = null;
138            InputStreamReader ireader = null;
139            BufferedReader br = null;
140            StringBuffer sb = null;
141            String request = null;
142    
143            if ( isSearchRequest ) {
144                is = ISO19115RequestFactory.class.getResourceAsStream( "CSWGetRecordsTemplate.xml" );
145            } else if ( isOverviewRequest ) {
146                is = ISO19115RequestFactory.class.getResourceAsStream( "CSWGetRecordByIdTemplate.xml" );
147            }
148    
149            try {
150                ireader = new InputStreamReader( is );
151                br = new BufferedReader( ireader );
152                sb = new StringBuffer( 50000 );
153    
154                while ( ( request = br.readLine() ) != null ) {
155                    sb.append( request );
156                }
157                request = sb.toString();
158                br.close();
159    
160            } catch ( Exception e ) {
161                LOG.logError( e.getMessage(), e );
162            }
163    
164            if ( isSearchRequest ) {
165                try {
166                    request = replaceVarsInSearchRequest( request, resultType );
167                } catch ( UnknownCRSException e ) {
168                    throw new CatalogClientException( e.getMessage(), e );
169                }
170            } else if ( isOverviewRequest ) {
171                request = replaceVarsInOverviewRequest( request );
172            }
173    
174            return request;
175        }
176    
177        /**
178         * @param request
179         * @param resultType
180         * @return Returns the request, where all variables are replaced by values.
181         * @throws CatalogClientException
182         * @throws UnknownCRSException
183         */
184        private String replaceVarsInSearchRequest( String request, String resultType )
185                                throws CatalogClientException, UnknownCRSException {
186    
187            // replace variables from template
188    
189            String filter = createFilterEncoding();
190            request = request.replaceFirst( "\\$FILTER", filter );
191    
192            request = request.replaceFirst( "\\$OUTPUTSCHEMA", OUTPUTSCHEMA );
193    
194            request = request.replaceFirst( "\\$RESULTTYPE", resultType );
195    
196            // According to OGC CSW-spec default is 1
197            String startPos = "1";
198            if ( struct.getMember( RPC_STARTPOSITION ) != null ) {
199                startPos = (String) struct.getMember( RPC_STARTPOSITION ).getValue();
200            }
201            request = request.replaceFirst( "\\$STARTPOSITION", startPos );
202    
203            // According to OGC CSW-spec default is 10
204            String maxRecords = Integer.toString( config.getMaxRecords() );
205            request = request.replaceFirst( "\\$MAXRECORDS", maxRecords );
206    
207            // For 2.0.0
208            // String queryType = "csw:dataset"; // dataset, dataseries, application
209            // For 2.0.2
210            String queryType = "gmd:MD_Metadata"; // possible values are: csw:Records, gmd:MD_Metadata, csw:service
211            if ( struct.getMember( RPC_TYPENAME ) != null ) {
212                queryType = (String) struct.getMember( RPC_TYPENAME ).getValue();
213            }
214            /*
215             * if ( struct.getMember( RPC_TYPENAME ) != null ) { queryType = (String) struct.getMember( RPC_TYPENAME
216             * ).getValue(); if ( !"gmd:MD_Metadata".equals( queryType ) && !"csw:Record".equals( queryType )) {
217             * LOG.logError( StringTools.concat( 100, "typename ", queryType, " is not a supported type.", "Suuported types
218             * are: ", "gmd:MD_Metadata", "csw:Record" ) ); queryType = "gmd:MD_Metadata"; } }
219             */
220            request = request.replaceFirst( "\\$TYPENAME", queryType );
221    
222            String elementSet = "brief"; // brief, summary, full
223            if ( struct.getMember( RPC_ELEMENTSETNAME ) != null ) {
224                elementSet = (String) struct.getMember( RPC_ELEMENTSETNAME ).getValue();
225            }
226            request = request.replaceFirst( "\\$ELEMENTSETNAME", elementSet );
227    
228            return request;
229        }
230    
231        /**
232         * @param request
233         * @return Returns the request, where all variables are replaced by values.
234         * @throws CatalogClientException
235         */
236        private String replaceVarsInOverviewRequest( String request )
237                                throws CatalogClientException {
238    
239            String id = null;
240            if ( struct.getMember( Constants.RPC_IDENTIFIER ) != null ) {
241                id = (String) struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
242            } else {
243                throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_ID_NOT_SET" ) );
244            }
245            request = request.replaceFirst( "\\$IDENTIFIER", id );
246    
247            request = request.replaceFirst( "\\$OUTPUTSCHEMA", OUTPUTSCHEMA );
248    
249            String elementSet = "full"; // brief, summary, full
250            if ( struct.getMember( RPC_ELEMENTSETNAME ) != null ) {
251                elementSet = (String) struct.getMember( RPC_ELEMENTSETNAME ).getValue();
252            }
253            request = request.replaceFirst( "\\$ELEMENTSETNAME", elementSet );
254    
255            return request;
256        }
257    
258        /**
259         * takes RequestModel and builds a String result out of it. The result should be OGC FilterEncoding conformant.
260         *
261         * @return Returns the fragment for filter encoding.
262         * @throws CatalogClientException
263         * @throws UnknownCRSException
264         */
265        private String createFilterEncoding()
266                                throws CatalogClientException, UnknownCRSException {
267    
268            StringBuffer sb = new StringBuffer( 2000 );
269            int expCounter = 0;
270            LOG.logDebug( "in method createFilterEncoding" );
271            sb.append( "<csw:Constraint version='1.0.0'><ogc:Filter>" );
272    
273            // build filter encoding structure, handle all known fields sequentially
274            String s = handleFileIdentifier();
275            LOG.logDebug( "file identifier=", s );
276            if ( ( s != null ) && ( s.length() > 0 ) ) {
277                expCounter++;
278                sb.append( s );
279            }
280    
281            s = handleParentIdentifier();
282            LOG.logDebug( "parent identifier=", s );
283            if ( ( s != null ) && ( s.length() > 0 ) ) {
284                expCounter++;
285                sb.append( s );
286            }
287    
288            s = handleSimpleSearch();
289            LOG.logDebug( "simple search=", s );
290            if ( ( s != null ) && ( s.length() > 0 ) ) {
291                expCounter++;
292                sb.append( s );
293            }
294    
295            s = handleTopiccategory();
296            LOG.logDebug( "topic category=", s );
297            if ( ( s != null ) && ( s.length() > 0 ) ) {
298                expCounter++;
299                sb.append( s );
300            }
301    
302            s = handleKeywords();
303            LOG.logDebug( "handle keywords=", s );
304            if ( ( s != null ) && ( s.length() > 0 ) ) {
305                expCounter++;
306                sb.append( s );
307            }
308    
309            s = handleDate();
310            LOG.logDebug( "date=", s );
311            if ( ( s != null ) && ( s.length() > 0 ) ) {
312                expCounter++;
313                sb.append( s );
314            }
315    
316            s = handleBbox();
317            LOG.logDebug( "box=", s );
318            if ( ( s != null ) && ( s.length() > 0 ) ) {
319                expCounter++;
320                sb.append( s );
321            }
322    
323            s = handleMetadataType();
324            LOG.logDebug( "MetadataType=", s );
325            if ( ( s != null ) && ( s.length() > 0 ) ) {
326                expCounter++;
327                sb.append( s );
328            }
329    
330            if ( expCounter > 1 ) {
331                sb.insert( "<csw:Constraint version='1.0.0'><ogc:Filter>".length(), "<ogc:And>" );
332                sb.append( "</ogc:And>" );
333            }
334    
335            sb.append( "</ogc:Filter></csw:Constraint>" );
336    
337            return sb.toString();
338        }
339    
340        /**
341         * Build OGC Filterencoding fragment: use <code>CSWRequestmodel</code> field <b>fileIdentifier</b> to create
342         * Comparison Operation.
343         *
344         * @return Returns the fragment for fileIdentifier. May be empty.
345         */
346        private String handleFileIdentifier() {
347    
348            StringBuffer sb = new StringBuffer( 1000 );
349    
350            String id = null;
351            if ( struct.getMember( Constants.RPC_IDENTIFIER ) != null ) {
352                id = (String) struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
353            }
354    
355            if ( ( id != null ) && ( id.trim().length() > 0 ) ) {
356                String cf_props = requestElementsProps.getProperty( Constants.CONF_IDENTIFIER );
357                String[] cf = cf_props.split( ";" );
358    
359                sb = new StringBuffer( 1000 );
360                Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], id );
361                sb.append( op1.toXML() );
362            }
363    
364            return sb.toString();
365        }
366    
367        /**
368         * Build OGC Filterencoding fragment: use <code>CSWRequestmodel</code> field <b>parentIdentifier</b> to create
369         * Comparison Operation.
370         *
371         * @return Returns the fragment for apiiso:type property. May be empty
372         */
373        private String handleMetadataType() {
374    
375            StringBuffer sb = new StringBuffer( 50 );
376    
377            if ( ( struct.getMember( RPC_MDTYPE ) ) != null ) {
378                String rpc_mdType = (String) struct.getMember( RPC_MDTYPE ).getValue();
379                String[] mdTypes = null;
380                if ( rpc_mdType != null ) {
381                    mdTypes = rpc_mdType.split( "," );
382                }
383    
384                String property = requestElementsProps.getProperty( Constants.CONF_MDTYPE );
385                if ( mdTypes != null && mdTypes.length > 0 ) {
386                    if ( mdTypes.length > 1 && mdTypes.length <= 3 ) {
387                        sb.append( "<ogc:Or>" );
388                        for ( int i = 0; i < mdTypes.length; i++ ) {
389    
390                            Operation op = createOperation( OperationDefines.PROPERTYISEQUALTO, property, mdTypes[i] );
391                            sb.append( op.toXML() );
392                        }
393                        sb.append( "</ogc:Or>" );
394                    } else if ( mdTypes.length == 1 ) {
395                        Operation op = createOperation( OperationDefines.PROPERTYISEQUALTO, property, mdTypes[0] );
396                        sb.append( op.toXML() );
397                    } // else {
398                    // This block does nothing, I just added it for clarity.
399                    // This is the case, where the three metadata types are searched and in this case, no type filter
400                    // shall be added at all
401                    // Update: since no MD of type service shall be returned, we use the first if condition of this block
402                    /*
403                     * Operation op = createOperation( OperationDefines.PROPERTYISLIKE, property, "*" ); sb.append(
404                     * op.toXML() );
405                     */
406                    // }
407                }
408            }
409            return sb.toString();
410        }
411    
412        /**
413         * Build OGC Filterencoding fragment: use <code>CSWRequestmodel</code> field <b>parentIdentifier</b> to create
414         * Comparison Operation.
415         *
416         * @return Returns the fragment for parentIdentifier. May be empty.
417         */
418        private String handleParentIdentifier() {
419    
420            StringBuffer sb = new StringBuffer( 1000 );
421            String seriesIdentifier = null;
422            if ( struct.getMember( Constants.RPC_DATASERIES ) != null ) {
423                seriesIdentifier = (String) struct.getMember( Constants.RPC_DATASERIES ).getValue();
424            }
425    
426            if ( ( seriesIdentifier != null ) && ( seriesIdentifier.trim().length() > 0 ) ) {
427                String cf_props = requestElementsProps.getProperty( Constants.CONF_DATASERIES );
428                String[] cf = cf_props.split( ";" );
429    
430                sb = new StringBuffer( 1000 );
431                Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], seriesIdentifier );
432                sb.append( op1.toXML() );
433            }
434    
435            return sb.toString();
436        }
437    
438        /**
439         * Spread <code>CSWRequestmodel</code> field <b>terms</b> to several Comparison Operations with pre-defined
440         * Property names.
441         *
442         * @return Returns the fragment for the search string. May be empty.
443         */
444        private String handleSimpleSearch() {
445    
446            StringBuffer sb = new StringBuffer( 2000 );
447    
448            String[] keywords = null;
449            if ( struct.getMember( RPC_SIMPLESEARCH ) != null ) {
450                String rpcVal = (String) struct.getMember( RPC_SIMPLESEARCH ).getValue();
451                keywords = StringTools.toArray( rpcVal, ",;|", true );
452            }
453    
454            if ( ( keywords != null ) && ( keywords.length > 0 ) ) {
455                sb.append( "<ogc:Or>" );
456    
457                for ( int i = 0; i < keywords.length; i++ ) {
458                    // replace invalid chars
459                    if ( ( keywords[i] != null ) && ( keywords[i].length() > 0 ) ) {
460                        keywords[i] = StringTools.replace( keywords[i], "'", " ", true );
461                        keywords[i] = StringTools.replace( keywords[i], "\"", " ", true );
462    
463                        // determine the way to build FilterEncoding part
464                        String cf_props = requestElementsProps.getProperty( Constants.CONF_SIMPLESEARCH );
465                        String[] cf = cf_props.split( ";" );
466                        for ( int k = 0; k < cf.length; k++ ) {
467                            String strOp = keywords[i];
468    
469                            if ( ( strOp != null ) && ( strOp.length() > 0 ) ) {
470                                // LOWERCASE SECTION
471                                strOp = strOp.substring( 0, 1 ).toLowerCase() + strOp.substring( 1 );
472                                Operation op = createOperation( OperationDefines.PROPERTYISLIKE, cf[k], strOp );
473                                sb.append( op.toXML() );
474    
475                                // FIRST LETTER UPPERCASE SECTION
476                                strOp = strOp.substring( 0, 1 ).toUpperCase() + strOp.substring( 1 );
477                                op = createOperation( OperationDefines.PROPERTYISLIKE, cf[k], strOp );
478                                sb.append( op.toXML() );
479                            }
480                        }
481                    }
482                }
483                sb.append( "</ogc:Or>" );
484            }
485    
486            return sb.toString();
487        }
488    
489        /**
490         * Builds OGC Filterencoding fragment: for <code>CSWRequestmodel</code> field <b>topiccategory</b>.
491         *
492         * @return Returns the fragment for topiccategory. May be null, if no topiccategory is specified.
493         */
494        private String handleTopiccategory() {
495    
496            String rpcVal = null;
497            if ( struct.getMember( RPC_TOPICCATEGORY ) != null ) {
498                rpcVal = (String) struct.getMember( RPC_TOPICCATEGORY ).getValue();
499            }
500    
501            if ( rpcVal != null && !rpcVal.startsWith( "..." ) && rpcVal.length() > 0 ) {
502                String cf_props = requestElementsProps.getProperty( Constants.CONF_TOPICCATEGORY );
503                String[] cf = cf_props.split( ";" );
504    
505                Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], rpcVal );
506                rpcVal = op1.toXML().toString();
507            } else {
508                rpcVal = null;
509            }
510    
511            return rpcVal;
512        }
513    
514        /**
515         * Build OGC Filterencoding fragment: Split <code>CSWRequestmodel</code> field <b>keywords</b> to one Comparison
516         * Operation for each keyword.
517         *
518         * @return Returns the fragment for keywords. May be empty, if no keywords are specified.
519         */
520        private String handleKeywords() {
521    
522            StringBuffer sb = new StringBuffer( 1000 );
523            String[] keywords = null;
524            if ( struct.getMember( RPC_KEYWORDS ) != null ) {
525                String s = (String) struct.getMember( RPC_KEYWORDS ).getValue();
526                keywords = StringTools.toArray( s, ",;", true );
527            }
528    
529            if ( ( keywords != null ) && ( keywords.length > 0 ) ) {
530                String cf_props = requestElementsProps.getProperty( Constants.CONF_KEYWORDS );
531                String[] cf = cf_props.split( ";" );
532    
533                sb = new StringBuffer( 1000 );
534                int i = 0;
535    
536                for ( i = 0; i < keywords.length; i++ ) {
537                    if ( keywords[i].trim().length() > 0 ) {
538                        Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], keywords[i] );
539                        sb.append( op1.toXML() );
540                    }
541                }
542    
543                if ( i > 1 ) {
544                    sb.insert( 0, "<ogc:Or>" );
545                    sb.append( "</ogc:Or>" );
546                }
547            }
548    
549            return sb.toString();
550        }
551    
552        /**
553         * Build OGC Filterencoding fragment: use <code>dateFrom</code> and <code>dateTo</code> to create Comparison
554         * Operations.
555         *
556         * @return Returns the fragment for dates specified in the <code>RPCStruct</code>. May be null, if no dates are
557         *         specified.
558         */
559        private String handleDate() {
560    
561            String s = null;
562    
563            if ( struct.getMember( Constants.RPC_DATEFROM ) == null && struct.getMember( Constants.RPC_DATETO ) == null ) {
564                return s;
565            }
566    
567            // RPC_DATEFROM
568            String fromYear = null;
569            String fromMonth = null;
570            String fromDay = null;
571    
572            if ( struct.getMember( Constants.RPC_DATEFROM ) != null ) {
573                RPCStruct st = (RPCStruct) struct.getMember( Constants.RPC_DATEFROM ).getValue();
574                if ( st.getMember( Constants.RPC_YEAR ) != null ) {
575                    fromYear = st.getMember( Constants.RPC_YEAR ).getValue().toString();
576                }
577                if ( st.getMember( Constants.RPC_MONTH ) != null ) {
578                    fromMonth = st.getMember( Constants.RPC_MONTH ).getValue().toString();
579                }
580                if ( st.getMember( Constants.RPC_DAY ) != null ) {
581                    fromDay = st.getMember( Constants.RPC_DAY ).getValue().toString();
582                }
583            }
584    
585            if ( fromYear == null ) {
586                fromYear = "0000";
587            }
588            if ( fromMonth == null ) {
589                fromMonth = "1";
590            }
591            if ( Integer.parseInt( fromMonth ) < 10 ) {
592                fromMonth = "0" + Integer.parseInt( fromMonth );
593            }
594            if ( fromDay == null ) {
595                fromDay = "1";
596            }
597            if ( Integer.parseInt( fromDay ) < 10 ) {
598                fromDay = "0" + Integer.parseInt( fromDay );
599            }
600            String dateFrom = fromYear + "-" + fromMonth + "-" + fromDay;
601    
602            // RPC_DATETO
603            String toYear = null;
604            String toMonth = null;
605            String toDay = null;
606    
607            if ( struct.getMember( Constants.RPC_DATETO ) != null ) {
608                RPCStruct st = (RPCStruct) struct.getMember( Constants.RPC_DATETO ).getValue();
609                if ( st.getMember( Constants.RPC_YEAR ) != null ) {
610                    toYear = st.getMember( Constants.RPC_YEAR ).getValue().toString();
611                }
612                if ( st.getMember( Constants.RPC_MONTH ) != null ) {
613                    toMonth = st.getMember( Constants.RPC_MONTH ).getValue().toString();
614                }
615                if ( st.getMember( Constants.RPC_DAY ) != null ) {
616                    toDay = st.getMember( Constants.RPC_DAY ).getValue().toString();
617                }
618            }
619    
620            if ( toYear == null ) {
621                toYear = "9999";
622            }
623            if ( toMonth == null ) {
624                toMonth = "12";
625            }
626            if ( Integer.parseInt( toMonth ) < 10 ) {
627                toMonth = "0" + Integer.parseInt( toMonth );
628            }
629            if ( toDay == null ) {
630                toDay = "31";
631            }
632            if ( Integer.parseInt( toDay ) < 10 ) {
633                toDay = "0" + Integer.parseInt( toDay );
634            }
635            String dateTo = toYear + "-" + toMonth + "-" + toDay;
636    
637            String date_props = requestElementsProps.getProperty( Constants.CONF_DATE );
638            String[] conf_date = date_props.split( ";" );
639    
640            if ( ( toYear != null ) && ( toYear.length() > 0 ) ) {
641                StringBuffer sb = new StringBuffer( "<ogc:And>" );
642    
643                Operation op1 = null;
644                op1 = createOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO, conf_date[0], dateFrom );
645                sb.append( op1.toXML() );
646                op1 = createOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO, conf_date[0], dateTo );
647                sb.append( op1.toXML() );
648    
649                sb.append( "</ogc:And>" );
650                s = sb.toString();
651            }
652    
653            return s;
654        }
655    
656        /**
657         * Build OGC Filterencoding fragment: use <code>CSWRequestmodel</code> field <b>geographicBox</b> to create
658         * Comparison Operation.
659         *
660         * @return Returns the fragment for the geographic bounding box. May be empty, if no bounding box is specified.
661         * @throws CatalogClientException
662         * @throws UnknownCRSException
663         */
664        private String handleBbox()
665                                throws CatalogClientException, UnknownCRSException {
666    
667            StringBuffer sb = new StringBuffer( 1000 );
668            if ( struct.getMember( Constants.RPC_BBOX ) != null ) {
669                RPCStruct bboxStruct = (RPCStruct) struct.getMember( Constants.RPC_BBOX ).getValue();
670    
671                Double minx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINX ).getValue();
672                Double miny = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINY ).getValue();
673                Double maxx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXX ).getValue();
674                Double maxy = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXY ).getValue();
675    
676                // FIXME check if srs is correct
677                CoordinateSystem srs = CRSFactory.create( config.getSrs() );
678                Envelope bbox = GeometryFactory.createEnvelope( minx.doubleValue(), miny.doubleValue(), maxx.doubleValue(),
679                                                                maxy.doubleValue(), srs );
680                try {
681                    // transform request boundingbox to EPSG:4326 because a ISO 19115
682                    // compliant catalog must store the bbox of an entry like this
683                    GeoTransformer geoTransformer = new GeoTransformer( "EPSG:4326" );
684                    bbox = geoTransformer.transform( bbox, config.getSrs() );
685    
686                } catch ( Exception e ) {
687                    throw new CatalogClientException( e.toString() );
688                }
689    
690                Geometry boxGeom = null;
691                try {
692                    boxGeom = GeometryFactory.createSurface( bbox, srs );
693                } catch ( GeometryException e ) {
694                    throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_CREATE_SURFACE",
695                                                                           e.getMessage() ) );
696                }
697    
698                String property = requestElementsProps.getProperty( Constants.CONF_GEOGRAPHICBOX );
699                String[] re = property.split( ";" );
700    
701                if ( boxGeom != null ) {
702                    Operation op1 = createOperation( OperationDefines.BBOX, re[0], boxGeom );
703                    sb.append( op1.toXML() );
704                }
705            }
706    
707            return sb.toString();
708        }
709    
710        // /**
711        // * @param bbox The bounding box to be used as filter condition.
712        // * @return Returns the GML bounding box snippet.
713        // */
714        // private String createGMLBox( Envelope bbox ) {
715        // StringBuffer sb = new StringBuffer( 1000 );
716        //
717        // sb.append( "<gml:Box xmlns:gml=\"http://www.opengis.net/gml\" >" );
718        // sb.append( "<gml:coord><gml:X>" );
719        // sb.append( "" + bbox.getMin().getX() );
720        // sb.append( "</gml:X><gml:Y>" );
721        // sb.append( "" + bbox.getMin().getY() );
722        // sb.append( "</gml:Y></gml:coord><gml:coord><gml:X>" );
723        // sb.append( "" + bbox.getMax().getX() );
724        // sb.append( "</gml:X><gml:Y>" );
725        // sb.append( "" + bbox.getMax().getY() );
726        // sb.append( "</gml:Y></gml:coord></gml:Box>" );
727        //
728        // return sb.toString();
729        // }
730    
731        /**
732         * @param opId
733         * @param property
734         * @param value
735         * @return Returns the operation to create.
736         */
737        private Operation createOperation( int opId, String property, Object value ) {
738    
739            Operation op = null;
740    
741            switch ( opId ) {
742            case OperationDefines.PROPERTYISEQUALTO:
743                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
744                                                  new PropertyName( new QualifiedName( property ) ),
745                                                  new Literal( (String) value ) );
746                break;
747            case OperationDefines.PROPERTYISLIKE:
748    
749                char wildCard = WILDCARD;
750                char singleChar = '?';
751                char escapeChar = '/';
752                String lit = wildCard + (String) value + wildCard;
753                op = new PropertyIsLikeOperation( new PropertyName( new QualifiedName( property ) ), new Literal( lit ),
754                                                  wildCard, singleChar, escapeChar );
755                break;
756            case OperationDefines.PROPERTYISLESSTHANOREQUALTO:
757                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO,
758                                                  new PropertyName( new QualifiedName( property ) ),
759                                                  new Literal( (String) value ) );
760                break;
761            case OperationDefines.PROPERTYISGREATERTHANOREQUALTO:
762                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
763                                                  new PropertyName( new QualifiedName( property ) ),
764                                                  new Literal( (String) value ) );
765                break;
766            case OperationDefines.BBOX:
767                op = new SpatialOperation( OperationDefines.BBOX, new PropertyName( new QualifiedName( property ) ),
768                                           (Geometry) value );
769                break;
770            case OperationDefines.PROPERTYISNULL:
771                op = new PropertyIsNullOperation( new PropertyName( new QualifiedName( property ) ) );
772                break;
773            default:
774                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
775                                                  new PropertyName( new QualifiedName( property ) ),
776                                                  new Literal( (String) value ) );
777            }
778    
779            return op;
780        }
781    
782    }