001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wass/wss/operation/DoServiceHandler.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.ogcwebservices.wass.wss.operation;
038    
039    import java.io.ByteArrayInputStream;
040    import java.io.IOException;
041    import java.io.InputStream;
042    import java.io.UnsupportedEncodingException;
043    import java.net.MalformedURLException;
044    import java.net.URI;
045    import java.net.URL;
046    import java.net.URLDecoder;
047    import java.util.ArrayList;
048    import java.util.List;
049    
050    import org.apache.commons.httpclient.Header;
051    import org.apache.commons.httpclient.HttpClient;
052    import org.apache.commons.httpclient.HttpException;
053    import org.apache.commons.httpclient.HttpMethod;
054    import org.apache.commons.httpclient.methods.GetMethod;
055    import org.apache.commons.httpclient.methods.PostMethod;
056    import org.apache.commons.httpclient.methods.StringRequestEntity;
057    import org.apache.commons.httpclient.params.HttpClientParams;
058    import org.deegree.enterprise.WebUtils;
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.util.CharsetUtils;
062    import org.deegree.framework.xml.XMLParsingException;
063    import org.deegree.i18n.Messages;
064    import org.deegree.ogcwebservices.csw.capabilities.CatalogueCapabilities;
065    import org.deegree.ogcwebservices.csw.capabilities.CatalogueCapabilitiesDocument;
066    import org.deegree.ogcwebservices.getcapabilities.HTTP;
067    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
068    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilitiesDocument;
069    import org.deegree.ogcwebservices.getcapabilities.Operation;
070    import org.deegree.ogcwebservices.wass.exceptions.DoServiceException;
071    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilities;
072    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilitiesDocument;
073    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
074    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
075    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
076    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
077    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
078    import org.deegree.owscommon_new.DCP;
079    import org.xml.sax.SAXException;
080    
081    /**
082     * This base class will makes the connection to the requested service on the "hidden" machines.
083     * Every Subclass must implement the handleRequest method to check the credentials. A call to
084     * another service can only be made, if the requestAllowed values is true;
085     *
086     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
087     *
088     * @author last edited by: $Author: mschneider $
089     *
090     * @version 2.0, $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
091     *
092     * @since 2.0
093     */
094    
095    public abstract class DoServiceHandler {
096    
097        private ILogger LOG = LoggerFactory.getLogger( DoServiceHandler.class );
098    
099        private boolean requestAllowed = false;
100    
101        /**
102         * Each subclass must implement this method, appropriate to its needs. For example password
103         * handling.
104         *
105         * @param request
106         *            the request the client sent to the secured service
107         * @throws DoServiceException
108         *             if an error occured while processing the clients credentials.
109         */
110        public abstract void handleRequest( DoService request )
111                                throws DoServiceException;
112    
113        /**
114         * @return Returns the requestAllowed.
115         */
116        public boolean requestAllowed() {
117            return requestAllowed;
118        }
119    
120        /**
121         * @param isAllowed
122         *            The requestAllowed to set.
123         */
124        public void setRequestAllowed( boolean isAllowed ) {
125            this.requestAllowed = isAllowed;
126        }
127    
128        /**
129         * This method does the actual request to the secured service. It returns the response of the
130         * secured service as an inputstream. It also replace the GetCapabilities request - responses
131         * with the facadeurl given by the client.
132         *
133         * @param request
134         *            send by the client a DoService Request.
135         * @param securedService
136         *            the service for which this wss is proxying, must be put in the deegreeparams of
137         *            the configuration file.
138         * @param requestedCharset
139         *            this wss uses, also read from the deegreeparams in the configuration file.
140         * @param timeout
141         *            how long to wait for a response. Service dependable therefor also read from the
142         *            deegreeparams in the config file.
143         * @param securedServiceName
144         *            the name of the service for which we are proxying -> config.
145         * @return the http response of the secured service as an inputstream.
146         * @throws DoServiceException
147         *             if an error occurs wile sending the request or treating the response. see
148         *             org.deegree.ogcwebservices.csw.manager.CatalogueHarvester#getNextMetadataRecord
149         */
150        public DoServiceResponse sendRequest( DoService request, URL securedService, String requestedCharset, int timeout,
151                                              String securedServiceName )
152                                throws DoServiceException {
153            if ( requestAllowed ) {
154    
155                Header[] headers = null;
156                InputStream body = null;
157                Header[] footers = null;
158                String proxyRequest = null;
159                try {
160                    proxyRequest = URLDecoder.decode( request.getPayload(), CharsetUtils.getSystemCharset() );
161                } catch ( UnsupportedEncodingException e ) {
162                    LOG.logError( e.getMessage(), e );
163                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_INTERNAL", "WSS" ) );
164                }
165                LOG.logDebug( "encoded proxyrequest: " + request.getPayload() + "\ndecoded proxy: " + proxyRequest );
166                String dcp = request.getDcp();
167                HttpClient client = new HttpClient();
168                client = WebUtils.enableProxyUsage( client, securedService );
169                StringRequestEntity requestEntity = null;
170                HttpClientParams params = client.getParams();
171                params.setSoTimeout( timeout );
172                HttpMethod requestMethod = null;
173                try {
174                    String contentType = null;
175                    for ( RequestParameter param : request.getRequestParameters() ) {
176                        if ( param.getId().toLowerCase().trim().contains( "mime-type" ) )
177                            contentType = param.getParameter();
178                    }
179                    requestEntity = new StringRequestEntity( proxyRequest, contentType, requestedCharset );
180                } catch ( UnsupportedEncodingException e1 ) {
181                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_ENCODING_NOT_SUPPORTED", "WSS" ) );
182                }
183                if ( dcp.equalsIgnoreCase( "http_post" ) ) {
184    
185                    // the url to the service must be written in the deegreeparams in the configuration
186                    // xml
187                    requestMethod = new PostMethod( securedService.toExternalForm() );
188                    ( (PostMethod) requestMethod ).setRequestEntity( requestEntity );
189                } else if ( dcp.equalsIgnoreCase( "http_get" ) ) {
190                    requestMethod = new GetMethod( securedService.toExternalForm() );
191                    requestMethod.setQueryString( proxyRequest );
192                } else {
193                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_NOT_POST_OR_GET", "WSS" ) );
194                }
195                // getDataRequest
196                try {
197                    // make header parameters of the requestParameters.
198                    for ( RequestParameter param : request.getRequestParameters() ) {
199                        if ( !param.getId().toLowerCase().trim().contains( "mime-type" ) )// Contenttype
200                            requestMethod.addRequestHeader( param.getId(), param.getParameter() );
201                    }
202                    // Call the secured service
203                    client.executeMethod( requestMethod );
204                    headers = requestMethod.getResponseHeaders();
205                    footers = requestMethod.getResponseFooters();
206                    body = requestMethod.getResponseBodyAsStream();
207    
208                    if ( body == null )
209                        throw new DoServiceException( Messages.getMessage( "WASS_ERROR_GOT_NO_RESPONSE", "WSS" ) );
210                } catch ( HttpException e ) {
211                    LOG.logError( e.getMessage(), e );
212                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_EXCEPTION_IN_RESPONSE", "WSS" ) );
213                } catch ( IOException e ) {
214                    LOG.logError( e.getMessage(), e );
215                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_IN_TRANSPORT", "WSS" ) );
216                }
217                try {
218                    // Replace the given urls with the facadeurls if it is a GetCapabilities request
219                    if ( proxyRequest.trim().contains( "GetCapabilities" ) ) {
220                        Operation[] operations = null;
221                        OGCCapabilitiesDocument doc = null;
222                        /*
223                         * For now just check these service, others may be "secured" in the future.
224                         */
225                        if ( "WFS".equals( securedServiceName ) ) {
226                            doc = new WFSCapabilitiesDocument();
227                            doc.load( body, securedService.toExternalForm() );
228                            WFSCapabilities cap = (WFSCapabilities) doc.parseCapabilities();
229                            operations = cap.getOperationsMetadata().getOperations();
230                            replaceFacadeURL( operations, request.getFacadeURL() );
231                            doc = org.deegree.ogcwebservices.wfs.XMLFactory.export( cap );
232                        } else if ( ( "WMS" ).equals( securedServiceName ) ) {
233                            doc = new WMSCapabilitiesDocument();
234                            doc.load( body, securedService.toExternalForm() );
235                            doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
236                            WMSCapabilities cap = (WMSCapabilities) doc.parseCapabilities();
237                            org.deegree.owscommon_new.Operation[] ops = cap.getOperationMetadata().getOperations().toArray(
238                                                                                                                            new org.deegree.owscommon_new.Operation[0] );
239                            replaceFacadeURL( ops, request.getFacadeURL() );
240                            doc = org.deegree.ogcwebservices.wms.XMLFactory.export( cap );
241                        } else if ( ( "WCS" ).equals( securedServiceName ) ) {
242                            doc = new WCSCapabilitiesDocument();
243                            doc.load( body, securedService.toExternalForm() );
244                            WCSCapabilities cap = (WCSCapabilities) doc.parseCapabilities();
245                            operations = cap.getCapabilitiy().getOperations().getOperations();
246                            replaceFacadeURL( operations, request.getFacadeURL() );
247                            doc = org.deegree.ogcwebservices.wcs.XMLFactory.export( cap );
248                        } else if ( ( "CSW" ).equals( securedServiceName ) ) {
249                            doc = new CatalogueCapabilitiesDocument();
250                            doc.load( body, securedService.toExternalForm() );
251                            CatalogueCapabilities cap = (CatalogueCapabilities) doc.parseCapabilities();
252                            operations = cap.getOperationsMetadata().getOperations();
253                            replaceFacadeURL( operations, request.getFacadeURL() );
254                            doc = org.deegree.ogcwebservices.csw.XMLFactory_2_0_0.export( cap, null );
255                        }
256    
257                        body = new ByteArrayInputStream( doc.getAsString().getBytes() );
258                    }
259                } catch ( IOException e ) {
260                    LOG.logError( e.getMessage(), e );
261                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_READING_BODY", "WSS" ) );
262                } catch ( InvalidCapabilitiesException e ) {
263                    LOG.logError( e.getMessage(), e );
264                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_CAPABILITIES_RESPONSE", "WSS" ) );
265                } catch ( SAXException e ) {
266                    LOG.logError( e.getMessage(), e );
267                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_FACADE_URL", "WSS" ) );
268                } catch ( XMLParsingException e ) {
269                    LOG.logError( e.getMessage(), e );
270                    throw new DoServiceException( Messages.getMessage( "WASS_ERROR_READING_BODY", "WSS" ) );
271                }
272                return new DoServiceResponse( headers, body, footers );
273            }
274    
275            return null;
276        }
277    
278        private void replaceFacadeURL( Operation[] operations, URI facadeURI ) {
279    
280            if ( operations != null && facadeURI != null ) {
281                for ( int i = 0; i < operations.length; i++ ) {
282                    setNewOnlineResource( operations[i], facadeURI );
283                }
284            }
285        }
286    
287        private void replaceFacadeURL( org.deegree.owscommon_new.Operation[] operations, URI facadeURI ) {
288    
289            if ( operations != null && facadeURI != null ) {
290                for ( int i = 0; i < operations.length; i++ ) {
291                    setNewOnlineResource( operations[i], facadeURI );
292                }
293            }
294        }
295    
296        /**
297         * Resets all the url in the response body with the facade urls
298         *
299         * @param op
300         *            the operation which has the secured service url in it
301         * @param facadeURI
302         *            the url of this wss.
303         */
304        private void setNewOnlineResource( Operation op, URI facadeURI ) {
305    
306            if ( op.getDCPs() != null ) {
307                for ( int i = 0; i < op.getDCPs().length; i++ ) {
308                    HTTP http = (HTTP) op.getDCPs()[i].getProtocol();
309                    try {
310                        if ( http.getGetOnlineResources().length > 0 ) {
311                            URL urls[] = new URL[http.getGetOnlineResources().length];
312                            for ( int k = 0; k < http.getGetOnlineResources().length; ++k )
313                                urls[k] = facadeURI.toURL();
314    
315                            http.setGetOnlineResources( urls );
316                        }
317                        if ( http.getPostOnlineResources().length > 0 ) {
318                            URL urls[] = new URL[http.getPostOnlineResources().length];
319                            for ( int k = 0; k < http.getPostOnlineResources().length; ++k ) {
320                                urls[k] = facadeURI.toURL();
321                            }
322    
323                            http.setPostOnlineResources( urls );
324                        }
325                    } catch ( MalformedURLException e1 ) {
326                        e1.printStackTrace();
327                    }
328                }
329            }
330    
331        }
332    
333        private void setNewOnlineResource( org.deegree.owscommon_new.Operation op, URI facadeURI ) {
334    
335            if ( op.getDCP() != null ) {
336                for ( DCP dcp : op.getDCP() ) {
337                    // assuming HTTP here, SOAP won't work!
338                    org.deegree.owscommon_new.HTTP http = (org.deegree.owscommon_new.HTTP) dcp;
339                    try {
340                        if ( http.getGetOnlineResources().size() > 0 ) {
341                            List<URL> urls = http.getGetOnlineResources();
342                            List<URL> urlsnew = new ArrayList<URL>( urls.size() );
343                            for ( int i = 0; i < urls.size(); ++i ) {
344                                urlsnew.add( facadeURI.toURL() );
345                            }
346    
347                            http.setGetOnlineResources( urlsnew );
348                        }
349                        if ( http.getPostOnlineResources().size() > 0 ) {
350                            List<URL> urls = http.getPostOnlineResources();
351                            List<URL> urlsnew = new ArrayList<URL>( urls.size() );
352                            for ( int i = 0; i < urls.size(); ++i ) {
353                                urlsnew.add( facadeURI.toURL() );
354                            }
355    
356                            http.setPostOnlineResources( urls );
357                        }
358                    } catch ( MalformedURLException e1 ) {
359                        e1.printStackTrace();
360                    }
361                }
362            }
363    
364        }
365    }