001 //$HeadURL: svn+ssh://mschneider@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $ 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.csw.iso_profile.ebrim; 038 039 import java.io.BufferedReader; 040 import java.io.ByteArrayOutputStream; 041 import java.io.IOException; 042 import java.io.InputStream; 043 import java.io.InputStreamReader; 044 import java.io.OutputStream; 045 import java.io.OutputStreamWriter; 046 import java.io.PrintWriter; 047 import java.io.UnsupportedEncodingException; 048 import java.net.MalformedURLException; 049 import java.net.URI; 050 import java.net.URISyntaxException; 051 import java.net.URL; 052 import java.security.InvalidParameterException; 053 import java.util.ArrayList; 054 import java.util.HashMap; 055 import java.util.List; 056 import java.util.Map; 057 import java.util.Set; 058 059 import javax.mail.MessagingException; 060 import javax.mail.internet.ContentDisposition; 061 import javax.mail.internet.MimeBodyPart; 062 import javax.mail.internet.MimeMultipart; 063 import javax.mail.internet.MimeUtility; 064 import javax.mail.util.ByteArrayDataSource; 065 import javax.servlet.Filter; 066 import javax.servlet.FilterChain; 067 import javax.servlet.FilterConfig; 068 import javax.servlet.ServletException; 069 import javax.servlet.ServletRequest; 070 import javax.servlet.ServletResponse; 071 import javax.servlet.http.HttpServletRequest; 072 import javax.servlet.http.HttpServletResponse; 073 074 import org.deegree.enterprise.servlet.ServletRequestWrapper; 075 import org.deegree.enterprise.servlet.ServletResponseWrapper; 076 import org.deegree.framework.log.ILogger; 077 import org.deegree.framework.log.LoggerFactory; 078 import org.deegree.framework.util.CharsetUtils; 079 import org.deegree.framework.util.IDGenerator; 080 import org.deegree.framework.util.WebappResourceResolver; 081 import org.deegree.framework.xml.InvalidConfigurationException; 082 import org.deegree.framework.xml.XMLException; 083 import org.deegree.framework.xml.XMLFragment; 084 import org.deegree.framework.xml.XMLTools; 085 import org.deegree.ogcbase.CommonNamespaces; 086 import org.deegree.ogcbase.ExceptionCode; 087 import org.deegree.ogcwebservices.OGCRequestFactory; 088 import org.deegree.ogcwebservices.OGCWebServiceException; 089 import org.deegree.ogcwebservices.OGCWebServiceRequest; 090 import org.deegree.ogcwebservices.csw.CSWExceptionCode; 091 import org.deegree.ogcwebservices.csw.CatalogueService; 092 import org.deegree.ogcwebservices.csw.configuration.CatalogueConfiguration; 093 import org.deegree.ogcwebservices.csw.manager.Insert; 094 import org.deegree.ogcwebservices.csw.manager.InsertResults; 095 import org.deegree.ogcwebservices.csw.manager.Manager; 096 import org.deegree.ogcwebservices.csw.manager.Operation; 097 import org.deegree.ogcwebservices.csw.manager.Transaction; 098 import org.deegree.ogcwebservices.csw.manager.TransactionResult; 099 import org.deegree.ogcwebservices.csw.manager.TransactionResultDocument; 100 import org.deegree.ogcwebservices.csw.manager.XMLFactory; 101 import org.deegree.security.GeneralSecurityException; 102 import org.deegree.security.drm.model.User; 103 import org.w3c.dom.CDATASection; 104 import org.w3c.dom.Document; 105 import org.w3c.dom.Element; 106 import org.w3c.dom.Node; 107 import org.xml.sax.SAXException; 108 109 /** 110 * The <code>CSWEbRIMFilter</code> class is able to handle an incoming csw/wrs ebrim Transaction. This extra filter is 111 * necessary because the insertion of an ebrim object is handled different then the original csw:Insert. 112 * <p> 113 * The first difference is the usage of the form/multipart header which allows for ExtrinsicObjects to be defined 114 * outside the message Body and thus must be handled seperatly. 115 * </p> 116 * <p> 117 * A second difference results after the insertion of an Object for every update and insertion leads to the extra 118 * insertion of an auditableEvent. The AuditableEvents result in an audit-trail (a version coontrol history ) for each 119 * inserted or updated app:RegistryObject. 120 * </p> 121 * 122 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 123 * 124 * @author last edited by: $Author: poth $ 125 * 126 * @version $Revision: 1.13 $, $Date: 2007-11-27 12:50:25 $ 127 * 128 */ 129 130 public class CSWEbRIMFilter implements Filter { 131 132 private static ILogger LOG = LoggerFactory.getLogger( CSWEbRIMFilter.class ); 133 134 private Manager transactionManager = null; 135 136 private URI appURI; 137 138 private OWSProxyHandler proxyHandler = null; 139 140 private CatalogueService cswService; 141 142 public void init( FilterConfig config ) 143 throws ServletException { 144 String configLocation = config.getInitParameter( "csw.config" ); 145 try { 146 URL configURL = WebappResourceResolver.resolveFileLocation( configLocation, config.getServletContext(), LOG ); 147 CatalogueConfiguration cswConfig = CatalogueConfiguration.createConfiguration( configURL ); 148 cswService = CatalogueService.create( cswConfig ); 149 transactionManager = cswService.getManager( "2.0.1" ); 150 if ( transactionManager.getWFService() == null ) { 151 LOG.logError( "CSW (Ebrim) Insert-Filter: The InserFilter has no access to the localWFS" ); 152 } 153 } catch ( MalformedURLException e ) { 154 LOG.logError( "Could not initiate CSWInsertfilter: " + e.getMessage() ); 155 } catch ( IOException e ) { 156 LOG.logError( "Could not initiate CSWInsertfilter: " + e.getMessage() ); 157 } catch ( SAXException e ) { 158 LOG.logError( "Could not initiate CSWInsertfilter: " + e.getMessage() ); 159 } catch ( InvalidConfigurationException e ) { 160 LOG.logError( "Could not initiate CSWInsertfilter: " + e.getMessage() ); 161 } catch ( OGCWebServiceException e ) { 162 LOG.logError( "Could not initiate CSWInsertfilter: " + e.getMessage() ); 163 } 164 if ( transactionManager != null ) { 165 try { 166 appURI = new URI( "http://www.deegree.org/app" ); 167 proxyHandler = new OWSProxyHandler( config ); 168 } catch ( URISyntaxException e ) { 169 // This never happens but whatever 170 } catch ( InvalidParameterException ipe ) { 171 LOG.logInfo( "CSW (Ebrim) Insert-Filter: couldn't create an OWSProxyHandler, so no user authentification available, because: " 172 + ipe.getMessage() ); 173 } 174 LOG.logInfo( "CSW (Ebrim) Insert Servlet Filter successfully initialized" ); 175 } else { 176 LOG.logInfo( "CSW (Ebrim) Insert Servlet Filter was not initialized" ); 177 } 178 } 179 180 public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) 181 throws IOException, ServletException { 182 if ( transactionManager == null ) { 183 LOG.logInfo( "CSW (Ebrim) Insert-Filter: Local Catalogue service is not instantiated, therefore the CSW-Insert filter can not be used" ); 184 sendException( response, new OGCWebServiceException( "The transactionManager is not configured " 185 + "so not accepting any requests.", 186 CSWExceptionCode.WRS_NOTIMPLEMENTED ) ); 187 // chain.doFilter( request, response ); 188 return; 189 } 190 response.setCharacterEncoding( "UTF-8" ); 191 // so no get request (or a get Request without parameters) 192 ServletRequestWrapper requestWrapper = null; 193 if ( request instanceof ServletRequestWrapper ) { 194 LOG.logDebug( "The incoming request is actually an org.deegree.enterprise.servlet.RequestWrapper, so not creating new instance." ); 195 requestWrapper = (ServletRequestWrapper) request; 196 } else { 197 requestWrapper = new ServletRequestWrapper( (HttpServletRequest) request ); 198 } 199 200 Map<String, String[]> parameters = requestWrapper.getParameterMap(); 201 ResponseObject responseObject = null; 202 try { 203 if ( parameters.size() != 0 ) { 204 responseObject = handleParameterizedRequest( parameters, requestWrapper ); 205 } else { 206 responseObject = handlePostedRequest( requestWrapper, response ); 207 } 208 } catch ( OGCWebServiceException e ) { 209 sendException( response, e ); 210 return; 211 } 212 if ( responseObject != null && responseObject.doResponseValidation() ) { 213 // Try the user authorization of the response 214 ServletResponseWrapper responseWrapper = new ServletResponseWrapper( (HttpServletResponse) response ); 215 responseWrapper.setCharacterEncoding( "UTF-8" ); 216 response.setContentType( "application/xml" ); 217 if ( responseObject.getOriginalRequest() instanceof Transaction ) { 218 try { 219 TransactionResult result = handleTransactions( (Transaction) responseObject.getOriginalRequest(), 220 responseObject.getUserName() ); 221 LOG.logDebug( "Creating xml representation of the csw-transaction " ); 222 TransactionResultDocument resultDoc = XMLFactory.export( result ); 223 // String prettyString = resultDoc.getAsPrettyString(); 224 if ( LOG.isDebug() ) { 225 LOG.logDebug( "The result of the csw-transaction was not null, it has following xml-structure: \n" 226 + resultDoc.getAsPrettyString() ); 227 } 228 PrintWriter writer = new PrintWriter( new OutputStreamWriter( responseWrapper.getOutputStream() ) ); 229 resultDoc.prettyPrint( writer ); 230 writer.flush(); 231 } catch ( OGCWebServiceException e ) { 232 sendException( response, e ); 233 return; 234 } catch ( Exception e ) { 235 sendException( response, 236 new OGCWebServiceException( 237 "Error while writing transaction response to the strea: " 238 + e.getLocalizedMessage(), 239 CSWExceptionCode.WRS_TRANSACTIONFAILED ) ); 240 return; 241 } 242 } else { 243 // Get a response which must be evaluated 244 chain.doFilter( requestWrapper, responseWrapper ); 245 } 246 if ( this.proxyHandler != null ) { 247 try { 248 authorizeResponse( responseObject.getUserName(), responseObject.getPassword(), 249 responseObject.getOriginalRequest(), responseWrapper ); 250 } catch ( OGCWebServiceException e ) { 251 sendException( response, e ); 252 return; 253 } 254 } 255 try { 256 afterResponseEvaluation( responseObject.getOriginalRequest(), responseWrapper ); 257 } catch ( OGCWebServiceException e ) { 258 sendException( response, e ); 259 return; 260 } 261 OutputStream os = responseWrapper.getOutputStream(); 262 String encoding = requestWrapper.getCharacterEncoding(); 263 if ( !"UTF-8".equals( encoding ) ) { 264 LOG.logDebug( "The request uses following character encoding: " + encoding + " setting to UTF-8." ); 265 encoding = "UTF-8"; 266 } 267 268 String responseString = ( (ServletResponseWrapper.ProxyServletOutputStream) os ).toString( encoding ); 269 if ( LOG.isDebug() ) { 270 LOG.logDebug( "got the string: " + responseString ); 271 } 272 os.close(); 273 PrintWriter writer = response.getWriter(); 274 writer.write( responseString ); 275 writer.flush(); 276 writer.close(); 277 // responseWrapper.flushBuffer(); 278 } else { 279 chain.doFilter( requestWrapper, response ); 280 } 281 } 282 283 /** 284 * This method is called after the CSWEbRIMFilter has successfully processed the incoming request, but did not 285 * actually write it to the Stream. THis method could be overwritten to do postprocessing the stream without 286 * actually having to register a new filter. 287 * 288 * @param originalRequest 289 * containing deegree java bean which is represents the request. 290 * @param responsewrapper 291 * which should be used. 292 */ 293 public void afterResponseEvaluation( OGCWebServiceRequest originalRequest, ServletResponseWrapper responsewrapper ) 294 throws OGCWebServiceException { 295 // This method is called after the CSWEbRIMFilter has successfully processed the incoming request, but did not 296 // write it to the Stream. 297 } 298 299 /** 300 * @param requestWrapper 301 * @param response 302 * @throws IOException 303 * if an exception occurred while getting the inputstream 304 */ 305 private ResponseObject handlePostedRequest( ServletRequestWrapper requestWrapper, ServletResponse response ) 306 throws OGCWebServiceException, IOException { 307 308 Transaction transaction = null; 309 BufferedReader reader = new BufferedReader( new InputStreamReader( requestWrapper.getInputStream() ) ); 310 String firstLine = reader.readLine(); 311 LOG.logDebug( "first line of request: " + firstLine ); 312 if ( firstLine == null ) { 313 LOG.logInfo( "CSW (Ebrim) Insert-Filter: no request characters found, not handling request" ); 314 // chain.doFilter( requestWrapper, response ); 315 throw new OGCWebServiceException( "no request characters found, not handling request", 316 CSWExceptionCode.WRS_INVALIDREQUEST ); 317 } 318 if ( LOG.isDebug() ) { 319 LOG.logDebug( "OUTPUTING as Strings" ); 320 LOG.logDebug( firstLine ); 321 try { 322 while ( reader.ready() ) { 323 LOG.logDebug( reader.readLine() ); 324 } 325 } catch ( IOException e ) { 326 // because of debug, just do anythin. 327 } 328 } 329 330 LOG.logDebug( "GetContentype(): " + requestWrapper.getContentType() ); 331 332 // These variables will be set according to the request properties 333 CSWSOAPHandler soapHandler = new CSWSOAPHandler(); 334 if ( requestWrapper.getContentType() != null 335 && requestWrapper.getContentType().contains( "multipart/form-data" ) ) { 336 // because we have some multiparts, the soap/owsproxy handling is done in the 337 // #handleMultiparts method 338 transaction = handleMultiparts( requestWrapper, soapHandler ); 339 if ( transaction == null ) { 340 LOG.logDebug( "Could not generate a Transaction object out of the multiparts, giving request to the chain" ); 341 throw new OGCWebServiceException( "Could not generate a Transaction object out of the multiparts", 342 CSWExceptionCode.WRS_INVALIDREQUEST ); 343 } 344 } else { 345 // Not a multipart, please continue 346 XMLFragment doc = null; 347 try { 348 doc = new XMLFragment( new InputStreamReader( requestWrapper.getInputStream() ), 349 "http://some_server.org" ); 350 } catch ( SAXException e ) { 351 LOG.logDebug( "couldn't create an xml Fragment of the incoming request, so not handling. " 352 + e.getMessage() ); 353 throw new OGCWebServiceException( "Couldn't create an xml Fragment of the incoming request", 354 CSWExceptionCode.WRS_INVALIDREQUEST ); 355 } catch ( IOException e ) { 356 throw new OGCWebServiceException( "Couldn't create an xml Fragment of the incoming request", 357 CSWExceptionCode.WRS_INVALIDREQUEST ); 358 } 359 Element rootElement = doc.getRootElement(); 360 String ns = rootElement.getNamespaceURI(); 361 if ( LOG.isDebug() ) { 362 LOG.logDebug( "Decoded request as xml:\n " + doc.getAsPrettyString() ); 363 } 364 365 if ( !CommonNamespaces.CSWNS.toASCIIString().equals( ns ) 366 && !CommonNamespaces.W3SOAP_ENVELOPE.toASCIIString().equals( ns ) ) { 367 LOG.logDebug( "The namespace of the root element (" + ns + ") is neither: " 368 + CommonNamespaces.W3SOAP_ENVELOPE + " nor: " + CommonNamespaces.CSWNS.toASCIIString() 369 + ", so not using the servlet filter " ); 370 throw new OGCWebServiceException( "Service not known", CSWExceptionCode.WRS_INVALIDREQUEST ); 371 } 372 373 soapHandler.setIncomingRequest( doc ); 374 doc = soapHandler.createCSWRequestFromSOAP(); 375 if ( doc == null ) { 376 LOG.logDebug( "The soap handler returned a null valued XMLFragment, cannot be!" ); 377 throw new OGCWebServiceException( "The body of your request could not be parsed.", 378 CSWExceptionCode.WRS_INVALIDREQUEST ); 379 } 380 rootElement = doc.getRootElement(); 381 if ( LOG.isDebug() ) { 382 LOG.logDebug( "The body of the soap request:\n" + doc.getAsPrettyString() ); 383 } 384 385 // reset the stream to handle the request without the soap 386 if ( soapHandler.isSOAPRequest() ) { 387 ByteArrayOutputStream bos = new ByteArrayOutputStream( 50000 ); 388 try { 389 OutputStreamWriter osw = new OutputStreamWriter( bos, CharsetUtils.getSystemCharset() ); 390 doc.write( osw ); 391 } catch ( UnsupportedEncodingException e ) { 392 throw new OGCWebServiceException( "The charset is not supported: " + e.getLocalizedMessage(), 393 CSWExceptionCode.WRS_NOTSUPPORTED ); 394 } 395 requestWrapper.setInputStreamAsByteArray( bos.toByteArray() ); 396 } 397 398 // checking the authorization of the user. 399 OGCWebServiceRequest owsProxyRequest = null; 400 if ( this.proxyHandler != null ) { 401 owsProxyRequest = proxyHandler.createOWSRequest( requestWrapper ); 402 authorizeRequest( soapHandler.getUserName(), soapHandler.getPassword(), owsProxyRequest, requestWrapper ); 403 } else { 404 LOG.logDebug( "The proxyHandler is not defined so no user Authentification." ); 405 throw new OGCWebServiceException( "The proxyHandler is not defined so not accepting any requests.", 406 CSWExceptionCode.WRS_NOTIMPLEMENTED ); 407 } 408 409 if ( !"Transaction".equals( rootElement.getLocalName() ) ) { 410 LOG.logDebug( "The localname of the root element is not: 'Transaction', so put request onto the chain. " ); 411 return new ResponseObject( soapHandler.getUserName(), soapHandler.getPassword(), true, owsProxyRequest ); 412 } 413 414 // create the transaction 415 transaction = Transaction.create( Long.toString( IDGenerator.getInstance().generateUniqueID() ), 416 rootElement ); 417 } 418 LOG.logDebug( "The request is a csw:Transaction parsed and handled by the CSWEbRIMFilter" ); 419 if ( transaction == null ) { 420 LOG.logDebug( "the transaction is null, this cannot be" ); 421 throw new OGCWebServiceException( "Failed to handle your transaction, please check your request.", 422 CSWExceptionCode.WRS_INVALIDREQUEST ); 423 } 424 return new ResponseObject( soapHandler.getUserName(), soapHandler.getPassword(), true, transaction ); 425 } 426 427 private ResponseObject handleParameterizedRequest( Map<String, String[]> parameters, 428 ServletRequestWrapper requestWrapper ) 429 throws OGCWebServiceException { 430 Map<String, String> params = new HashMap<String, String>(); 431 for ( String key : parameters.keySet() ) { 432 String[] tmp = parameters.get( key ); 433 for ( int i = 0; i < tmp.length; i++ ) { 434 tmp[i] = tmp[i].trim(); 435 LOG.logDebug( "for key: " + key + " found param: " + tmp[i] ); 436 } 437 // params.put( key.toUpperCase(), StringTools.arrayToString( tmp, ',' ) ); 438 if ( tmp.length > 0 ) { 439 params.put( key.toUpperCase(), tmp[0] ); 440 } 441 } 442 String service = params.get( "SERVICE" ); 443 if ( service == null ) { 444 // a profile of a service will be treated as a service 445 service = params.get( "PROFILE" ); 446 if ( service == null ) { 447 throw new OGCWebServiceException( "The SERVICE or PROFILE keyword isn't set.", 448 CSWExceptionCode.WRS_INVALIDREQUEST ); 449 } else if ( !( OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.equals( service ) || "CSW".equals( service ) ) ) { 450 LOG.logDebug( "The Service parameter of the request (" + service + ") is neither: " 451 + OGCRequestFactory.CSW_SERVICE_NAME_EBRIM + " nor: CSW" 452 + ", so not using the servlet filter " ); 453 throw new OGCWebServiceException( "Service not known: " + service, CSWExceptionCode.WRS_INVALIDREQUEST ); 454 } 455 } 456 457 OGCWebServiceRequest owsProxyRequest = null; 458 // put them to uppercase *sigh* 459 String userName = params.get( "USER" ); 460 String password = params.get( "PASSWORD" ); 461 LOG.logDebug( "Trying to get authentication for user: " + userName + " with password: " + password ); 462 if ( this.proxyHandler != null ) { 463 owsProxyRequest = proxyHandler.createOWSRequest( requestWrapper ); 464 authorizeRequest( userName, password, owsProxyRequest, requestWrapper ); 465 } else { 466 LOG.logDebug( "CSW (Ebrim) Insert-Filter: the proxyHandler is not defined so no user Authentification." ); 467 new OGCWebServiceException( "The proxyHandler is not defined so not accepting any requests.", 468 CSWExceptionCode.WRS_NOTIMPLEMENTED ); 469 } 470 return new ResponseObject( userName, password, true, owsProxyRequest ); 471 } 472 473 private void authorizeRequest( String userName, String password, OGCWebServiceRequest owsProxyRequest, 474 ServletRequestWrapper requestWrapper ) 475 throws OGCWebServiceException { 476 // checking the authorization of the user. 477 try { 478 User user = proxyHandler.authentificateFromUserPw( userName, password ); 479 proxyHandler.doRequestValidation( requestWrapper, user, owsProxyRequest ); 480 } catch ( GeneralSecurityException e ) { 481 LOG.logDebug( "User: " + userName + " with password: " + password 482 + " couldn't get authentification because: " + e.getMessage() ); 483 throw new OGCWebServiceException( e.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 484 } 485 } 486 487 private void authorizeResponse( String userName, String password, OGCWebServiceRequest owsProxyRequest, 488 ServletResponseWrapper responseWrapper ) 489 throws OGCWebServiceException { 490 // checking the authorization of the user. 491 if ( this.proxyHandler != null ) { 492 try { 493 User user = proxyHandler.authentificateFromUserPw( userName, password ); 494 proxyHandler.doResponseValidation( responseWrapper, user, owsProxyRequest ); 495 } catch ( GeneralSecurityException e ) { 496 LOG.logDebug( "User: " + userName + " with password: " + password 497 + " couldn't get authentification because: " + e.getMessage() ); 498 throw new OGCWebServiceException( e.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 499 } catch ( IOException e ) { 500 LOG.logDebug( "couldn't get an outputstream for the repsponse because: " + e.getMessage() ); 501 throw new OGCWebServiceException( e.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 502 } 503 } 504 } 505 506 public void destroy() { 507 // implements nottin. 508 } 509 510 /** 511 * Sends the passed <tt>OGCWebServiceException</tt> to the calling client and flushes/closes the writer. 512 * 513 * @param responseWriter 514 * to write the message of the exception to 515 * @param e 516 * the exception to 'send' e.g. write to the stream. 517 * @throws IOException 518 * if an error occurred while getting the writer of the response. 519 */ 520 private void sendException( ServletResponse response, OGCWebServiceException e ) 521 throws IOException { 522 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 523 Thread.dumpStack(); 524 } 525 if ( response instanceof ServletResponseWrapper ) { 526 ( (ServletResponseWrapper) response ).reset(); 527 } 528 response.setContentType( "application/xml" ); 529 PrintWriter writer = response.getWriter(); 530 LOG.logInfo( "CSW (Ebrim) Insert-Filter: Sending OGCWebServiceException to client with message: ." 531 + e.getMessage() ); 532 Document doc = XMLTools.create(); 533 534 XMLFragment frag = new XMLFragment( doc.createElementNS( CommonNamespaces.OWSNS.toASCIIString(), 535 "ows:ExceptionReport" ) ); 536 ExceptionCode code = e.getCode(); 537 String exceptionCode = CSWExceptionCode.WRS_INVALIDREQUEST.value; 538 if ( code != null && code.value != null ) { 539 exceptionCode = code.value; 540 } 541 Element soapFailed = XMLTools.appendElement( frag.getRootElement(), CommonNamespaces.WRS_EBRIMNS, exceptionCode ); 542 XMLTools.setNodeValue( soapFailed, e.getMessage() ); 543 writer.write( frag.getAsPrettyString() ); 544 writer.flush(); 545 writer.close(); 546 } 547 548 /** 549 * This method handles the operations in the given Transaction that is, it splits the Transaction into update/delete 550 * and insert operations. The update and delete operations are gathered as long as there are no insert operations. 551 * If an Insert opertation is encountered the pending delete/update operations are first send to the csw after which 552 * all records in the insert operation are sequently inserted into the registry, using the 553 * {@link InsertTransactionHandler}. Note this method guarantees the sequential processing of the operations in 554 * their defined order. 555 * 556 * @param transaction 557 * bean representation of the incoming request. 558 * @param username 559 * of the user which inserts the registryObjects. 560 * @throws OGCWebServiceException 561 * if an error occurred while hanlding an operations. 562 */ 563 private TransactionResult handleTransactions( Transaction transaction, String username ) 564 throws OGCWebServiceException { 565 List<Operation> ops = transaction.getOperations(); 566 // find all the ids which were referenced by the transaction. 567 List<Operation> pendingOps = new ArrayList<Operation>(); 568 List<Node> briefInsertedRecords = new ArrayList<Node>(); 569 // 0 = insert 570 // 1 = delete 571 // 2 = update 572 int[] resultValues = new int[3]; 573 for ( Operation op : ops ) { 574 if ( "Insert".equalsIgnoreCase( op.getName() ) ) { 575 // First do all transactions which were not insert(s) 576 if ( pendingOps.size() > 0 ) { 577 TransactionResult tr = sendPendingOperations( transaction, pendingOps ); 578 resultValues[0] += tr.getTotalInserted(); 579 resultValues[1] += tr.getTotalDeleted(); 580 resultValues[2] += tr.getTotalUpdated(); 581 } 582 // handle all records inside the insert operation, e.g. set the 583 // app:RegistryObject/app:status to invalid 584 // if the id of the object allready exists. 585 InsertTransactionHandler handler = new InsertTransactionHandler( transaction, (Insert) op, appURI, 586 username ); 587 briefInsertedRecords.addAll( handler.handleInsertTransaction( this.transactionManager, resultValues ) ); 588 589 } else { 590 pendingOps.add( op ); 591 } 592 } 593 if ( pendingOps.size() > 0 ) { 594 TransactionResult tr = sendPendingOperations( transaction, pendingOps ); 595 resultValues[0] += tr.getTotalInserted(); 596 resultValues[1] += tr.getTotalDeleted(); 597 resultValues[2] += tr.getTotalUpdated(); 598 } 599 LOG.logDebug( "Number of brief inserted records: " + briefInsertedRecords.size() ); 600 InsertResults iresults = new InsertResults( briefInsertedRecords ); 601 return new TransactionResult( transaction, resultValues[0], resultValues[1], resultValues[2], iresults ); 602 } 603 604 /** 605 * Sends all operations in the list to the csw. 606 * 607 * @param originalTransaction 608 * used to get the version, id and vendorspecific params from. 609 * @param pendingOps 610 * the list of delete and update operations. 611 * @return the Result of the csw. 612 * @throws OGCWebServiceException 613 */ 614 private TransactionResult sendPendingOperations( Transaction originalTransaction, List<Operation> pendingOps ) 615 throws OGCWebServiceException { 616 Transaction transaction = new Transaction( originalTransaction.getVersion(), originalTransaction.getId(), 617 originalTransaction.getVendorSpecificParameters(), pendingOps, false ); 618 619 return transactionManager.transaction( transaction ); 620 } 621 622 /** 623 * This method handles the multiparts of a ServletRequest. This method is called when the 624 * content-type:form/multipart header is set. Inside the multiparts different extrinsice object representations (as 625 * xml) may reside. They will be added inside the appropriate InsertOperation (found by the extrinsicObject's/@id) 626 * and inserted in the xml representation of the referenced (again while looking at the /@id attribute) 627 * extrinicObject. The definition of the extrinsicObject (e.g. inside the multipart) will be put inside the 628 * following xml-Element: 'deegreecsw:DescribedObject', at the end of the nodelist of the 'rim:ExtrinsicOjbects'. 629 * 630 * @param request 631 * the actual HttpServletRequest. 632 * @param soapHandler 633 * @return the Transaction Representation of the incoming request 634 * @throws OGCWebServiceException 635 * if an exception occurred while processing the mime parts. 636 */ 637 private Transaction handleMultiparts( HttpServletRequest request, CSWSOAPHandler soapHandler ) 638 throws OGCWebServiceException { 639 Transaction trans = null; 640 // StreamDataSource sds = new StreamDataSource( request ); 641 try { 642 ByteArrayDataSource bads = new ByteArrayDataSource( request.getInputStream(), "application/xml" ); 643 LOG.logInfo( "CSW (Ebrim) Insert-Filter: Setting the 'mail.mime.multipart.ignoremissingendboundary' System property to false." ); 644 System.setProperty( "mail.mime.multipart.ignoremissingendboundary", "false" ); 645 MimeMultipart multi = new MimeMultipart( bads ); 646 Map<String, Insert> insertOpContainingExtObj = new HashMap<String, Insert>(); 647 648 for ( int i = 0; i < multi.getCount(); i++ ) { 649 MimeBodyPart content = (MimeBodyPart) multi.getBodyPart( i ); 650 LOG.logDebug( "multipart (" + ( i + 1 ) + " of " + multi.getCount() + ") content id: " 651 + content.getContentID() ); 652 LOG.logDebug( "multipart (" + ( i + 1 ) + " of " + multi.getCount() + ") content type: " 653 + content.getContentType() ); 654 String contentType = content.getContentType(); 655 if ( !( contentType.contains( "application/xml" ) || contentType.contains( "text/xml" ) ) ) { 656 throw new OGCWebServiceException( 657 "Other than xml-encoded data can not be handled in the multiparts", 658 CSWExceptionCode.WRS_INVALIDREQUEST ); 659 } 660 String[] names = content.getHeader( "Content-Disposition" ); 661 String nameID = null; 662 if ( names != null ) { 663 for ( String name : names ) { 664 ContentDisposition cd = new ContentDisposition( name ); 665 String nm = cd.getParameter( "name" ); 666 if ( nm != null ) { 667 nameID = nm; 668 break; 669 } 670 } 671 } 672 673 if ( nameID == null ) { 674 nameID = content.getContentID(); 675 if ( nameID == null ) { 676 throw new OGCWebServiceException( "Exactly one 'name' parameter must be set in the header.", 677 CSWExceptionCode.WRS_INVALIDREQUEST ); 678 } 679 } 680 LOG.logDebug( "Working with multipart (" + ( i + 1 ) + " of " + multi.getCount() + ") content name:" 681 + nameID ); 682 LOG.logDebug( "multipart (" + ( i + 1 ) + " of " + multi.getCount() + ") lineCount: " 683 + content.getLineCount() ); 684 LOG.logDebug( "multipart (" + ( i + 1 ) + " of " + multi.getCount() + ") encoding: " 685 + content.getEncoding() ); 686 if ( "Transaction".equalsIgnoreCase( nameID ) ) { 687 InputStream contentIS = null; 688 if ( !"UTF-8".equalsIgnoreCase( content.getEncoding() ) ) { 689 contentIS = MimeUtility.decode( content.getInputStream(), content.getEncoding() ); 690 } else { 691 contentIS = content.getInputStream(); 692 } 693 694 // first get an xml fragment of the request and check if it is a soap. 695 XMLFragment doc = new XMLFragment( new InputStreamReader( contentIS ), XMLFragment.DEFAULT_URL ); 696 LOG.logDebug( "Decoded first multiPart:\n " + doc.getAsPrettyString() ); 697 soapHandler.setIncomingRequest( doc ); 698 699 doc = soapHandler.createCSWRequestFromSOAP(); 700 Element rootElement = doc.getRootElement(); 701 702 String ns = rootElement.getNamespaceURI(); 703 if ( !CommonNamespaces.CSWNS.toASCIIString().equals( ns ) 704 || !"Transaction".equals( rootElement.getLocalName() ) ) { 705 // create the transaction 706 LOG.logDebug( "The namespace of the root element (" + ns + ") is not" 707 + CommonNamespaces.CSWNS.toASCIIString() 708 + ", or the request isn't a Transaction so not creating a Transaction object. " ); 709 // set the first multipart to the multipart without the soap. 710 content.setContent( doc.getAsPrettyString(), "application/xml" ); 711 return null; 712 } 713 trans = Transaction.create( "0", rootElement ); 714 715 if ( this.proxyHandler != null ) { 716 ServletRequestWrapper wrapper = new ServletRequestWrapper( request ); 717 ByteArrayOutputStream bos = new ByteArrayOutputStream( 50000 ); 718 OutputStreamWriter osw = new OutputStreamWriter( bos, CharsetUtils.getSystemCharset() ); 719 doc.write( osw ); 720 wrapper.setInputStreamAsByteArray( bos.toByteArray() ); 721 authorizeRequest( soapHandler.getUserName(), soapHandler.getPassword(), trans, wrapper ); 722 } else { 723 LOG.logDebug( "the proxyHandler is not defined so no user Authentification." ); 724 } 725 726 List<Operation> ops = trans.getOperations(); 727 // find all the ids which were referenced by the transaction. 728 int countInserts = 0; 729 for ( Operation op : ops ) { 730 731 if ( "Insert".equalsIgnoreCase( op.getName() ) ) { 732 733 Map<String, Element> objects = ( (Insert) op ).getExtrinsicObjects(); 734 Set<String> keys = objects.keySet(); 735 LOG.logDebug( "This insert operation (" + ++countInserts 736 + ") contains the following keys: " + keys ); 737 // set the keys to the operations they were referenced in. 738 for ( String key : keys ) { 739 if ( insertOpContainingExtObj.containsKey( key ) ) { 740 throw new OGCWebServiceException( "The following key is not unique, " + key 741 + ", the transaction therefore failed.", 742 CSWExceptionCode.WRS_INVALIDREQUEST ); 743 } 744 insertOpContainingExtObj.put( key, (Insert) op ); 745 } 746 } 747 } 748 } else { 749 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 750 InputStream contentIS = null; 751 752 if ( !"UTF-8".equalsIgnoreCase( content.getEncoding() ) ) { 753 contentIS = MimeUtility.decode( content.getInputStream(), content.getEncoding() ); 754 } else { 755 contentIS = content.getInputStream(); 756 } 757 758 BufferedReader reader = new BufferedReader( new InputStreamReader( contentIS ) ); 759 String firstLine = reader.readLine(); 760 if ( !reader.ready() || firstLine == null ) { 761 LOG.logInfo( "CSW (Ebrim) Insert-Filter: no characters found in multipart, is this an error?" ); 762 } 763 LOG.logDebug( "first line of multipart: " + firstLine ); 764 } 765 LOG.logDebug( "found Keys: " + insertOpContainingExtObj.keySet() ); 766 if ( insertOpContainingExtObj.size() > 0 ) { 767 if ( insertOpContainingExtObj.containsKey( nameID ) ) { 768 LOG.logDebug( "found the key to insert (" + nameID 769 + ") trying to find associated multipart." ); 770 Insert insertOperation = insertOpContainingExtObj.remove( nameID ); 771 Map<String, Element> extrinsicObjects = insertOperation.getExtrinsicObjects(); 772 // find the extrinsicobject element and add the multipartmime type 773 // containing it's id. 774 if ( extrinsicObjects.containsKey( nameID ) ) { 775 List<Element> records = insertOperation.getRecords(); 776 Element extrinsicObject = extrinsicObjects.get( nameID ); 777 if ( records.contains( extrinsicObject ) ) { 778 int objectIndex = records.indexOf( extrinsicObject ); 779 LOG.logDebug( "removing extrinsicObject at index: " + objectIndex 780 + " from the records list" ); 781 records.remove( extrinsicObject ); 782 Element handledExtrinsicObject = addDescribedExtrinsicObject( content, 783 extrinsicObject ); 784 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 785 XMLFragment testFrag = new XMLFragment( handledExtrinsicObject ); 786 LOG.logDebug( "The extrinsicObject after the insertion of the multipart: " 787 + testFrag.getAsPrettyString() ); 788 } 789 records.add( objectIndex, handledExtrinsicObject ); 790 // records.add( handledExtrinsicObject ); 791 } else { 792 LOG.logDebug( "Following extrinsicObject was not found in the records list, this cannot be!: " 793 + extrinsicObject.toString() ); 794 } 795 } else { 796 LOG.logDebug( "The given id: " 797 + nameID 798 + " was not found in the list of extrinsicObjects in the given InsertOperation, this cannot be!" ); 799 } 800 } 801 } else { 802 throw new OGCWebServiceException( "Some mime multiparts remain, but there are no more " 803 + "referenced ids, something is wrong with the transaction", 804 CSWExceptionCode.WRS_INVALIDREQUEST ); 805 } 806 } 807 } 808 } catch ( IOException ioe ) { 809 throw new OGCWebServiceException( "Can't handle your insert request, because an IOException " 810 + "(with following message occured) while handling the mime multiparts:" 811 + ioe.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 812 } catch ( MessagingException me ) { 813 throw new OGCWebServiceException( "Can't handle your insert request, because a MessagingException " 814 + "(with following message occured) while handling the mime multiparts:" 815 + me.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 816 } catch ( XMLException xmle ) { 817 throw new OGCWebServiceException( "Can't handle your insert request, because an XMLException (with " 818 + "following message occured) while handling the mime multiparts:" 819 + xmle.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 820 } catch ( SAXException saxe ) { 821 throw new OGCWebServiceException( "Can't handle your insert request, because an SAXException (with " 822 + "following message) occured while handling the mime multiparts:" 823 + saxe.getMessage(), CSWExceptionCode.WRS_INVALIDREQUEST ); 824 } 825 // finished so lets give back the transaction as a result. 826 return trans; 827 } 828 829 /** 830 * Adds an deegreecsw:DescribedObject to the rim:EextrinsicObject, which will contain the xml encoded object given 831 * in the MimeBodyPart. 832 * 833 * @param content 834 * holding the described object 835 * @param extrinsicObject 836 * which will receive the deegreecsw:DescribedObject 837 * @return the modified extrinsicObject xml-Element. 838 * @throws OGCWebServiceException 839 * @throws MessagingException 840 */ 841 private Element addDescribedExtrinsicObject( MimeBodyPart content, Element extrinsicObject ) 842 throws OGCWebServiceException, MessagingException { 843 844 String contentType = content.getContentType(); 845 LOG.logDebug( "in the multipart, we found the contentType: " + contentType ); 846 if ( contentType == null || !( contentType.contains( "application/xml" ) || contentType.contains( "text/xml" ) ) ) { 847 throw new OGCWebServiceException( "Other than xml-encoded data can not be handled in the multiparts", 848 CSWExceptionCode.WRS_INVALIDREQUEST ); 849 } 850 try { 851 InputStream contentIS = null; 852 if ( !"UTF-8".equalsIgnoreCase( content.getEncoding() ) ) { 853 contentIS = MimeUtility.decode( content.getInputStream(), content.getEncoding() ); 854 } else { 855 contentIS = content.getInputStream(); 856 } 857 858 BufferedReader reader = new BufferedReader( new InputStreamReader( contentIS ) ); 859 String firstLine = reader.readLine(); 860 if ( !reader.ready() || firstLine == null ) { 861 LOG.logInfo( "CSW (Ebrim) Insert-Filter: no request characters found, not handling request" ); 862 } 863 StringBuffer sb = new StringBuffer(); 864 while ( firstLine != null ) { 865 sb.append( firstLine ); 866 firstLine = reader.readLine(); 867 } 868 String resultString = sb.toString(); 869 LOG.logDebug( "content of multipart: " + resultString ); 870 871 // first delete the old element of the records list. 872 // XMLFragment doc = new XMLFragment( new InputStreamReader( contentIS ), 873 // XMLFragment.DEFAULT_URL ); 874 Element describedObject = XMLTools.appendElement( extrinsicObject, CommonNamespaces.DEEGREECSW, 875 CommonNamespaces.DEEGREECSW_PREFIX + ":DescribedObject" ); 876 CDATASection dataSection = describedObject.getOwnerDocument().createCDATASection( resultString ); 877 LOG.logDebug( "content of multipart(after cdata encoding): " + dataSection.getWholeText() ); 878 describedObject.appendChild( dataSection ); 879 // Document ownerDoc = extrinsicObject.getOwnerDocument(); 880 // Node newInsertNode = ownerDoc.importNode( doc.getRootElement(), true ); 881 // describedObject.appendChild( newInsertNode ); 882 883 } catch ( IOException e ) { 884 throw new OGCWebServiceException( "An error occurred while processing a multipart, discarding", 885 CSWExceptionCode.WRS_INVALIDREQUEST ); 886 } 887 return extrinsicObject; 888 } 889 890 private class ResponseObject { 891 892 private final String userName; 893 894 private final String password; 895 896 private final boolean doResponseValidation; 897 898 private final OGCWebServiceRequest originalRequest; 899 900 ResponseObject( String userName, String password, boolean doResponseValidation, 901 OGCWebServiceRequest originalRequest ) { 902 this.userName = userName; 903 this.password = password; 904 this.doResponseValidation = doResponseValidation; 905 this.originalRequest = originalRequest; 906 } 907 908 /** 909 * @return the userName 910 */ 911 public final String getUserName() { 912 return userName; 913 } 914 915 /** 916 * @return the password 917 */ 918 public final String getPassword() { 919 return password; 920 } 921 922 /** 923 * @return the doResponseValidation 924 */ 925 public final boolean doResponseValidation() { 926 return doResponseValidation; 927 } 928 929 /** 930 * @return the originalRequest 931 */ 932 public final OGCWebServiceRequest getOriginalRequest() { 933 return originalRequest; 934 } 935 } 936 937 /** 938 * @return an instance of the catalogue service intiliazed in the init method. 939 */ 940 public CatalogueService getCatalogueService() { 941 return cswService; 942 } 943 }