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