001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/standard/wfs/control/WFSClientListener.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.wfs.control;
038    
039    import java.io.BufferedReader;
040    import java.io.File;
041    import java.io.FileReader;
042    import java.io.IOException;
043    import java.io.InputStream;
044    import java.io.InputStreamReader;
045    import java.net.URL;
046    
047    import javax.servlet.http.HttpServletRequest;
048    import javax.servlet.http.HttpSession;
049    
050    import org.apache.commons.httpclient.HttpClient;
051    import org.apache.commons.httpclient.methods.PostMethod;
052    import org.apache.commons.httpclient.methods.StringRequestEntity;
053    import org.deegree.enterprise.WebUtils;
054    import org.deegree.enterprise.control.AbstractListener;
055    import org.deegree.enterprise.control.FormEvent;
056    import org.deegree.enterprise.control.RPCMember;
057    import org.deegree.enterprise.control.RPCParameter;
058    import org.deegree.enterprise.control.RPCStruct;
059    import org.deegree.enterprise.control.RPCWebEvent;
060    import org.deegree.framework.log.ILogger;
061    import org.deegree.framework.log.LoggerFactory;
062    import org.deegree.framework.util.CharsetUtils;
063    import org.deegree.framework.util.StringTools;
064    import org.deegree.framework.xml.XMLFragment;
065    import org.deegree.model.feature.FeatureCollection;
066    import org.deegree.model.feature.GMLFeatureAdapter;
067    import org.deegree.model.feature.GMLFeatureCollectionDocument;
068    import org.deegree.portal.context.AbstractFrontend;
069    import org.deegree.portal.context.GeneralExtension;
070    import org.deegree.portal.context.Module;
071    import org.deegree.portal.context.ViewContext;
072    import org.deegree.portal.standard.wfs.WFSClientException;
073    
074    /**
075     * The WFSClientListener 1. receives an RPC request, 2. builds a request to a WFS service using the values given in the
076     * RPC request, 3. sends the request to the specified WFS, 4. receives the result from the WFS and 5. forwards the
077     * result to the WFSClient.
078     *
079     * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
080     * @author last edited by: $Author: mschneider $
081     *
082     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
083     */
084    public class WFSClientListener extends AbstractListener {
085    
086        private static final ILogger LOG = LoggerFactory.getLogger( WFSClientListener.class );
087    
088        protected static final String INIT_TARGETSRS = "TARGETSRS";
089    
090        protected static final String INIT_XSLT = "XSLT";
091    
092        /*
093         * (non-Javadoc)
094         *
095         * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
096         */
097        @Override
098        public void actionPerformed( FormEvent event ) {
099    
100            RPCWebEvent rpcEvent = (RPCWebEvent) event;
101    
102            try {
103                validateRequest( rpcEvent );
104            } catch ( Exception e ) {
105                LOG.logError( e.getMessage(), e );
106                gotoErrorPage( "Invalid rpc request: \n" + e.getMessage() );
107    
108                return;
109            }
110    
111            try {
112                doGetFeature( rpcEvent );
113            } catch ( Exception e ) {
114                LOG.logError( e.getMessage(), e );
115                gotoErrorPage( "doGetFeature not successful: \n" + e.getMessage() );
116    
117                return;
118            }
119    
120        }
121    
122        /**
123         * TODO check validation: are all elements checked? which elements are mandatory? ...?
124         *
125         * @param rpcEvent
126         * @throws WFSClientException
127         */
128        private void validateRequest( RPCWebEvent rpcEvent )
129                                throws WFSClientException {
130    
131            RPCParameter[] params = rpcEvent.getRPCMethodCall().getParameters();
132            if ( params.length != 1 ) {
133    
134                throw new WFSClientException( "Request/Method Call must contain one parameter, not: " + params.length );
135            }
136    
137            RPCStruct rpcStruct = (RPCStruct) params[0].getValue();
138    
139            if ( rpcStruct.getMember( "MODULE" ) == null ) {
140    
141                throw new WFSClientException( "Request does not contain mandatory element MODULE." );
142            }
143    
144            String tmp = (String) rpcStruct.getMember( "MODULE" ).getValue();
145            if ( tmp == null || tmp.length() < 1 ) {
146    
147                throw new WFSClientException( "Mandatory element MODULE must be set." );
148            }
149            try {
150                if ( rpcStruct.getMember( "FEATURETYPES" ) != null ) {
151                    tmp = (String) rpcStruct.getMember( "FEATURETYPES" ).getValue();
152                    // LOG.logDebug( "FEATURETYPES: " + tmp );
153                }
154                if ( rpcStruct.getMember( "QUERYTEMPLATE" ) != null ) {
155                    tmp = (String) rpcStruct.getMember( "QUERYTEMPLATE" ).getValue();
156                    // LOG.logDebug( "QUERYTEMPLATE: " + tmp );
157                }
158                if ( rpcStruct.getMember( "FILTER" ) != null ) {
159                    tmp = (String) rpcStruct.getMember( "FILTER" ).getValue();
160                    // LOG.logDebug( "FILTER: " + tmp );
161                }
162                if ( rpcStruct.getMember( "FILTERPROPERTIES" ) != null ) {
163                    tmp = (String) rpcStruct.getMember( "FILTERPROPERTIES" ).getValue();
164                    // LOG.logDebug( "FILTERPROPERTIES: " + tmp );
165                }
166                if ( rpcStruct.getMember( "RESULTFORMAT" ) != null ) {
167                    tmp = (String) rpcStruct.getMember( "RESULTFORMAT" ).getValue();
168                    // LOG.logDebug( "RESULTFORMAT: " + tmp );
169                }
170                if ( rpcStruct.getMember( "XMLNS" ) != null ) {
171                    tmp = (String) rpcStruct.getMember( "XMLNS" ).getValue();
172                    // LOG.logDebug( "XMLNS: " + tmp );
173                }
174                if ( rpcStruct.getMember( "NORMALIZE" ) != null ) {
175                    Boolean shouldNormalize = (Boolean) rpcStruct.getMember( "NORMALIZE" ).getValue();
176                    LOG.logDebug( "NORMALIZE: " + shouldNormalize );
177                }
178                if ( rpcStruct.getMember( "LOCALE" ) != null ) {
179                    tmp = (String) rpcStruct.getMember( "LOCALE" ).getValue();
180                    // LOG.logDebug( "LOCALE: " + tmp );
181                }
182                if ( rpcStruct.getMember( "SESSIONID" ) != null ) {
183                    tmp = (String) rpcStruct.getMember( "SESSIONID" ).getValue();
184                    // LOG.logDebug( "SESSIONID: " + tmp );
185                }
186            } catch ( Exception e ) {
187                LOG.logError( e.getMessage(), e );
188    
189                throw new WFSClientException( "Member of rpc request must not be null or empty: ", e );
190            }
191    
192        }
193    
194        /**
195         *
196         * @param rpcEvent
197         * @throws WFSClientException
198         */
199        protected void doGetFeature( RPCWebEvent rpcEvent )
200                                throws WFSClientException {
201    
202            RPCParameter[] params = rpcEvent.getRPCMethodCall().getParameters();
203            RPCStruct rpcStruct = (RPCStruct) params[0].getValue();
204    
205            // xml namespaces
206            String tmp = null;
207            RPCMember rpcMember = rpcStruct.getMember( "XMLNS" );
208            String[] xmlns = null;
209            if ( rpcMember != null ) {
210                tmp = (String) rpcMember.getValue();
211            }
212            if ( tmp == null ) {
213                xmlns = new String[0];
214            } else {
215                xmlns = StringTools.toArray( tmp, ",", true );
216            }
217    
218            // NORMALIZATION
219            // check if the query string needs to be normalized
220            Boolean getsNormalized = false;
221            rpcMember = rpcStruct.getMember( "NORMALIZE" );
222            if ( rpcMember != null ) {
223                getsNormalized = (Boolean) rpcMember.getValue();
224            }
225            // set locale for normalization
226            String locale = null;
227            if ( getsNormalized ) {
228                rpcMember = rpcStruct.getMember( "LOCALE" );
229                if ( rpcMember != null ) {
230                    locale = (String) rpcMember.getValue();
231                } else {
232                    locale = "default";
233                }
234            }
235    
236            // CREATE QUERY
237            // featuretypes to query
238            rpcMember = rpcStruct.getMember( "FEATURETYPES" );
239            tmp = (String) rpcMember.getValue();
240            String[] featureTypes = StringTools.toArray( tmp, ",", true );
241    
242            String moduleName = (String) rpcStruct.getMember( "MODULE" ).getValue();
243            String query = null;
244    
245            // use template or filter to build query
246            if ( rpcStruct.getMember( "QUERYTEMPLATE" ) != null ) {
247                String queryTemplate = (String) rpcStruct.getMember( "QUERYTEMPLATE" ).getValue();
248                RPCMember filterProperties = rpcStruct.getMember( "FILTERPROPERTIES" );
249                RPCMember sessionId = rpcStruct.getMember( "SESSIONID" );
250                try {
251                    query = createQueryFromTemplate( queryTemplate, moduleName, filterProperties, sessionId,
252                                                     getsNormalized, locale );
253                } catch ( Exception e ) {
254                    LOG.logError( e.getMessage(), e );
255    
256                    throw new WFSClientException( "Could not create query from template: " + e.getMessage() );
257                }
258                getRequest().setAttribute( "QUERYTEMPLATE", queryTemplate );
259    
260            } else if ( rpcStruct.getMember( "FILTER" ) != null ) {
261                // TODO this is not implemented yet
262                String filter = (String) rpcStruct.getMember( "FILTER" ).getValue();
263                query = createQueryFromFilter( featureTypes, xmlns, filter, getsNormalized, locale );
264            } else {
265                // TODO reactivate this option
266                // String filter = createFilterFromProperties();
267                // query = createQueryFromFilter( featureTypes, xmlns, filter, getsNormalized );
268                throw new WFSClientException( "could not create query" );
269            }
270    
271            // PERFORM QUERY
272            // LOG.logDebug( "\n***** QUERY *****\n" + query + "\n" );
273            XMLFragment response = performQuery( query, moduleName );
274            // LOG.logDebug( "\n***** RESPONSE *****\n" + response.getAsString() + "\n" );
275    
276            FeatureCollection fc = null;
277            try {
278                GMLFeatureCollectionDocument doc = new GMLFeatureCollectionDocument();
279                doc.setRootElement( response.getRootElement() );
280                fc = doc.parse();
281            } catch ( Exception e ) {
282                // DOMPrinter.printNode( response.getRootElement(), " " );
283                LOG.logError( e.getMessage(), e );
284    
285                throw new WFSClientException( "Could not build FeatureCollection from xml Document: " + e.getMessage() );
286            }
287            // TODO replace initParam
288            // if ( getInitParam( INIT_TARGETSRS ) != null ) {
289            // try {
290            // // TODO comment in again when needed
291            // fc = transformGeometries( fc );
292            // } catch ( Exception e ) {
293            // LOG.logError( e.getMessage(), e );
294            //
295            // throw new WFSClientException( "Could not transform geometries in FeatureCollection." );
296            // }
297            // }
298    
299            String resultFormat = null;
300            rpcMember = rpcStruct.getMember( "RESULTFORMAT" );
301            if ( rpcMember != null ) {
302                resultFormat = (String) rpcMember.getValue();
303            }
304            if ( !"XML".equals( resultFormat ) && !"FEATURECOLLECTION".equals( resultFormat ) ) {
305                throw new WFSClientException( "resultFormat" );
306            }
307    
308            // WRITE FEATURE RESULTS BACK TO CLIENT
309            try {
310                writeGetFeatureResult( fc, resultFormat );
311            } catch ( Exception e ) {
312                LOG.logError( e.getMessage(), e );
313    
314                throw new WFSClientException( "Could not write getFeatureResult: " + e.getMessage() );
315            }
316    
317        }
318    
319        /**
320         * Creates a WFS GetFeature query from a named template and a set of KVP-encoded properties.
321         *
322         * @param queryTemplate
323         * @param moduleName
324         * @param filterProperties
325         * @param sessionId
326         *            the users session id. may be null.
327         * @param getsNormalized
328         *            if true, the filter string gets normalized
329         * @param locale
330         *            the locale language defining the normalization rules to choose, e.g. "de"
331         * @return Returns the WFS GetFeature query as String.
332         * @throws WFSClientException
333         */
334        private String createQueryFromTemplate( String queryTemplate, String moduleName, RPCMember filterProperties,
335                                                RPCMember sessionId, Boolean getsNormalized, String locale )
336                                throws WFSClientException {
337    
338            HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
339            ViewContext vc = (ViewContext) session.getAttribute( org.deegree.portal.Constants.CURRENTMAPCONTEXT );
340    
341            GeneralExtension ge = vc.getGeneral().getExtension();
342            AbstractFrontend fe = (AbstractFrontend) ge.getFrontend();
343            Module module = null;
344            Module[] mods = fe.getModulesByName( moduleName );
345            if ( mods.length > 0 ) {
346                module = mods[0];
347            } else {
348                LOG.logError( "no module with the name" + moduleName + "could be found." );
349    
350                throw new WFSClientException( "The current map context does not contain the module:" + moduleName );
351            }
352    
353            queryTemplate = (String) module.getParameter().getParameter( queryTemplate ).getValue();
354            if ( queryTemplate.startsWith( "'" ) && queryTemplate.endsWith( "'" ) ) {
355                // strip ' from front and end of string
356                queryTemplate = queryTemplate.substring( 1, queryTemplate.length() - 1 );
357            }
358    
359            if ( !( new File( queryTemplate ).isAbsolute() ) ) {
360                queryTemplate = getHomePath() + queryTemplate;
361                LOG.logDebug( "The template file now has an absolute path: " + queryTemplate );
362            }
363            StringBuffer template = new StringBuffer( 10000 );
364            try {
365                BufferedReader br = new BufferedReader( new FileReader( queryTemplate ) );
366                String line = null;
367                while ( ( line = br.readLine() ) != null ) {
368                    template.append( line );
369                }
370                br.close();
371            } catch ( IOException e ) {
372                LOG.logError( e.getMessage(), e );
373    
374                throw new WFSClientException( "could not read query template: " + queryTemplate );
375            }
376            String query = template.toString();
377    
378            // SUBSTITUTE FILTER PROPERTIES
379            String tmp = null;
380            if ( filterProperties != null ) {
381                tmp = (String) filterProperties.getValue(); // tmp={myKey=searchStringXXX}{key2=value2}
382            }
383    
384            if ( tmp != null ) {
385                String[] properties = StringTools.extractStrings( tmp, "{", "}" );
386    
387                for ( int i = 0; i < properties.length; i++ ) {
388                    if ( properties[i].startsWith( "{" ) ) {
389                        properties[i] = properties[i].substring( 1, properties[i].length() );
390                    }
391                    if ( properties[i].endsWith( "}" ) ) {
392                        properties[i] = properties[i].substring( 0, properties[i].length() - 1 );
393                    }
394    
395                    String[] kvp = StringTools.toArray( properties[i], "=", false );
396                    // FIXME instead of using "%" as wildcard: read the wildcard character from the
397                    // template!
398                    kvp[1] = StringTools.replace( kvp[1], "XXX", "%", true );
399    
400                    if ( getsNormalized ) {
401                        try {
402                            kvp[1] = StringTools.normalizeString( kvp[1], locale );
403                        } catch ( Exception e ) {
404                            LOG.logError( "the search string of the filter property could not be normalized", e );
405                            throw new WFSClientException( e.getMessage(), e );
406                        }
407                    }
408                    query = StringTools.replace( query, '$' + kvp[0], kvp[1], true );
409                }
410            }
411    
412            // SUBSTITUTE SESSION_ID
413            tmp = null;
414            if ( sessionId != null ) {
415                tmp = (String) sessionId.getValue();
416            }
417            query = StringTools.replace( query, "$SESSION_ID", tmp, true );
418    
419            return query;
420        }
421    
422        /**
423         * Creates a WFS GetFeature query from a OGC filter expression sent from a client.
424         *
425         * TODO: implement support for getNormalized
426         *
427         * @param featureTypes
428         * @param xmlns
429         * @param filter
430         * @param getsNormalized
431         *            if true, the filter string gets normalized
432         * @param locale
433         *            the locale language defining the normalization rules to choose, e.g. "de"
434         * @return Returns the WFS GetFeature query as String.
435         */
436        private String createQueryFromFilter( String[] featureTypes, String[] xmlns, String filter, Boolean getsNormalized,
437                                              String locale ) {
438    
439            // TODO handle SESSIONID if it is part of the rpc request
440    
441            // normalize filter if needed
442            if ( getsNormalized ) {
443                // FIXME remove try-catch.
444                // TODO Proper implementation of method doNormalizeFilter().
445                try {
446                    filter = doNormalizeFilter( filter, locale );
447                } catch ( Exception e ) {
448                    LOG.logError( "Could not normalize filter.", e );
449                }
450            }
451    
452            StringBuffer query = new StringBuffer( 20000 );
453            String format = "text/xml; subtype=gml/3.1.1";
454            String resultType = "results";
455    
456            // TODO get values for parameters from rpc Request
457            // if ( parameter.get( "OUTPUTFORMAT" ) != null ) {
458            // format = (String) parameter.get( "OUTPUTFORMAT" );
459            // }
460            // if ( parameter.get( "RESULTTYPE" ) != null ) {
461            // resultType = (String) parameter.get( "RESULTTYPE" );
462            // }
463    
464            query.append( "<wfs:GetFeature outputFormat='" ).append( format );
465            query.append( " resultType='" ).append( resultType ).append( "' " );
466    
467            for ( int i = 0; i < xmlns.length; i++ ) {
468                String[] tmp = StringTools.toArray( xmlns[i], "=", false );
469                query.append( "xmlns:" ).append( tmp[0] ).append( "='" );
470                query.append( tmp[1] ).append( "' " );
471            }
472            query.append( "xmlns:wfs='http://www.opengis.net/wfs' " );
473            query.append( "xmlns:ogc='http://www.opengis.net/ogc' " );
474            query.append( "xmlns:gml='http://www.opengis.net/gml' " );
475            query.append( ">" );
476    
477            query.append( "<wfs:Query " );
478            for ( int i = 0; i < featureTypes.length; i++ ) {
479                query.append( "typeName='" ).append( featureTypes[i] );
480                if ( i < featureTypes.length - 1 ) {
481                    query.append( "," );
482                }
483            }
484            query.append( "'>" );
485            query.append( filter );
486            query.append( "</wfs:Query></wfs:GetFeature>" );
487    
488            return query.toString();
489        }
490    
491        // /**
492        // * creates an OGC FE filter from a set of KVP-encode properties and logical operations
493        // *
494        // * @return
495        // */
496        // private String createFilterFromProperties() {
497        // // TODO normalization
498        // // TODO handle SESSIONID if it is part of the rpc request
499        //
500        // String tmp = (String) parameter.get( "FILTERPROPERTIES" );
501        // if ( tmp != null ) {
502        // String[] properties = StringExtend.extractArray( tmp, "{", "}" );
503        // String logOp = (String) parameter.get( "LOGICALOPERATOR" );
504        // StringBuffer filter = new StringBuffer( 10000 );
505        // filter.append( "<ogc:Filter>" );
506        // if ( properties.length > 1 ) {
507        // filter.append( "<ogc:" ).append( logOp ).append( '>' );
508        // }
509        // for ( int i = 0; i < properties.length; i++ ) {
510        // String[] prop = StringExtend.extractArray( tmp, "[", "]" );
511        // if ( "!=".equals( prop[1] ) || "NOT LIKE".equals( prop[1] ) ) {
512        // filter.append( "<ogc:Not>" );
513        // }
514        // if ( "=".equals( prop[1] ) || "!=".equals( prop[1] ) ) {
515        // filter.append( "<ogc:PropertyIsEqualTo>" );
516        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
517        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
518        // filter.append( "</ogc:PropertyIsEqualTo>" );
519        // } else if ( ">=".equals( prop[1] ) ) {
520        // filter.append( "<ogc:PropertyIsGreaterThanOrEqualTo>" );
521        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
522        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
523        // filter.append( "</ogc:PropertyIsGreaterThanOrEqualTo>" );
524        // } else if ( ">".equals( prop[1] ) ) {
525        // filter.append( "<ogc:PropertyIsGreaterThan>" );
526        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
527        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
528        // filter.append( "</ogc:PropertyIsGreaterThan>" );
529        // } else if ( "<=".equals( prop[1] ) ) {
530        // filter.append( "<ogc:PropertyIsLessThanOrEqualTo>" );
531        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
532        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
533        // filter.append( "</ogc:PropertyIsLessThanOrEqualTo>" );
534        // } else if ( "<".equals( prop[1] ) ) {
535        // filter.append( "<ogc:PropertyIsLessThan>" );
536        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
537        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
538        // filter.append( "</ogc:PropertyIsLessThan>" );
539        // } else if ( "LIKE".equals( prop[1] ) || "NOT LIKE".equals( prop[1] ) ) {
540        // filter.append( "<ogc:PropertyIsLike wildCard='%' singleChar='#' escape='!'>" );
541        // filter.append( "<ogc:PropertyName>" ).append( prop[0] ).append( "</ogc:PropertyName>" );
542        // filter.append( "<ogc:Literal>" ).append( prop[2] ).append( "</ogc:Literal>" );
543        // filter.append( "</ogc:PropertyIsLike>" );
544        // }
545        // if ( "!=".equals( prop[1] ) || "NOT LIKE".equals( prop[1] ) ) {
546        // filter.append( "</ogc:Not>" );
547        // }
548        // }
549        // if ( properties.length > 1 ) {
550        // filter.append( "</ogc:" ).append( logOp ).append( '>' );
551        // }
552        // filter.append( "</ogc:Filter>" );
553        // return filter.toString();
554        // }
555        // return "";
556        // }
557    
558        /**
559         * Replace the filter string with a normalized version.
560         *
561         * @param filter
562         * @param locale
563         *            the locale language defining the normalization rules to choose, e.g. "de"
564         * @return the query with a normalized filter if query cannot be transformed to XMLFragment
565         */
566        private String doNormalizeFilter( String filter, String locale ) {
567    
568            throw new UnsupportedOperationException( "this method is not fully implemented yet" );
569    
570            //
571            //
572            // XMLFragment xmlFilter = new XMLFragment();
573            // try {
574            // xmlFilter.load( new StringReader( filter ),
575            // "http://www.deegree.org/portal/standard/WFSClientListener" );
576            // xmlFilter.prettyPrint( System.out );
577            // } catch ( Exception e ) {
578            // LOG.logError( e.getMessage() );
579            // throw new WFSClientException( "Could not transform filter into XMLFragment", e );
580            // }
581            //
582            // //FIXME normalization of filter using the passed locale !
583            //
584            //
585            // return xmlFilter.getAsString();
586        }
587    
588        /**
589         * Performs a GetFeature query against a WFS.
590         *
591         * The WFS address is defined in the module configuration: The default WFS is given with Parameter Name = WFS. If a
592         * different WFS is to be used for a special querytemplate, this is defined by specifying ParameterName =
593         * WFS:querytemplate
594         *
595         * @param query
596         * @param moduleName
597         * @return Returns the response to a WFS GetFeature request as xml Document.
598         * @throws WFSClientException
599         */
600        private XMLFragment performQuery( String query, String moduleName )
601                                throws WFSClientException {
602    
603            HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
604            ViewContext vc = (ViewContext) session.getAttribute( org.deegree.portal.Constants.CURRENTMAPCONTEXT );
605    
606            // WFS to contact
607            GeneralExtension ge = vc.getGeneral().getExtension();
608            AbstractFrontend fe = (AbstractFrontend) ge.getFrontend();
609            Module module = null;
610            Module[] mods = fe.getModulesByName( moduleName );
611            if ( mods.length > 0 ) {
612                module = mods[0];
613            } else {
614                LOG.logError( "no module with the name" + moduleName + "could be found." );
615    
616                throw new WFSClientException( "The current map context does not contain the module:" + moduleName );
617            }
618    
619            // get WFS address for template of current featuretype OR, if not available, the default WFS
620            String wfsAddress = null;
621            String queryTemplate = (String) getRequest().getAttribute( "QUERYTEMPLATE" );
622            if ( module.getParameter().getParameter( "WFS:" + queryTemplate ) != null ) {
623                wfsAddress = (String) module.getParameter().getParameter( "WFS:" + queryTemplate ).getValue();
624            } else {
625                wfsAddress = (String) module.getParameter().getParameter( "WFS" ).getValue();
626            }
627            if ( wfsAddress == null ) {
628    
629                throw new WFSClientException( "WFS is not known by the portal" );
630            }
631            if ( wfsAddress.startsWith( "'" ) && wfsAddress.endsWith( "'" ) ) {
632                // strip ' from front and end of string
633                wfsAddress = wfsAddress.substring( 1, wfsAddress.length() - 1 );
634            }
635    
636            InputStream is = null;
637            try {
638                StringRequestEntity re = new StringRequestEntity( query, "text/xml", CharsetUtils.getSystemCharset() );
639                PostMethod post = new PostMethod( wfsAddress );
640                post.setRequestEntity( re );
641                post.setRequestHeader( "Content-type", "text/xml;charset=" + CharsetUtils.getSystemCharset() );
642    
643                HttpClient client = new HttpClient();
644                client = WebUtils.enableProxyUsage( client, new URL( wfsAddress ) );
645                client.executeMethod( post );
646                is = post.getResponseBodyAsStream();
647            } catch ( IOException e ) {
648                LOG.logError( e.getMessage(), e );
649    
650                throw new WFSClientException( "could not perform query against the WFS." );
651            }
652    
653            XMLFragment xmlFrag = new XMLFragment();
654            try {
655                InputStreamReader isr = new InputStreamReader( is, CharsetUtils.getSystemCharset() );
656                xmlFrag.load( isr, wfsAddress );
657            } catch ( Exception e ) {
658                LOG.logError( e.getMessage(), e );
659    
660                throw new WFSClientException( "could not load xmlFragment. \n" + e.getMessage(), e );
661            }
662            return xmlFrag;
663        }
664    
665        /**
666         * writes the result into the forwarded request object
667         *
668         * @param fc
669         * @param resultFormat
670         *            the format of the result in the servlet request. Can be either 'XML' or 'FEATURECOLLECTION'.
671         * @throws WFSClientException
672         *             if the feature collection could not be exported to GML.
673         * @throws RuntimeException
674         *             if the resultFormat is not supported.
675         */
676    
677        private void writeGetFeatureResult( FeatureCollection fc, String resultFormat )
678                                throws WFSClientException {
679    
680            if ( "XML".equals( resultFormat ) ) {
681                try {
682                    GMLFeatureCollectionDocument gmlFcDoc = new GMLFeatureAdapter().export( fc );
683                    getRequest().setAttribute( "RESULT", gmlFcDoc );
684                } catch ( Exception e ) {
685                    LOG.logError( e.getMessage(), e );
686    
687                    throw new WFSClientException( "could not export feature collection as GML", e );
688                }
689            } else if ( "FEATURECOLLECTION".equals( resultFormat ) ) {
690                getRequest().setAttribute( "RESULT", fc );
691            } else {
692                throw new RuntimeException( "'" + resultFormat + "' is not a supported format." );
693            }
694    
695        }
696    
697    }