001 //$HeadURL: svn+ssh://developername@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/files_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 package org.deegree.tools.metadata; 037 038 import java.io.BufferedReader; 039 040 import java.io.File; 041 import java.io.FileWriter; 042 import java.io.IOException; 043 import java.io.InputStream; 044 import java.io.PrintWriter; 045 import java.io.StringReader; 046 import java.net.MalformedURLException; 047 import java.text.MessageFormat; 048 import java.util.List; 049 import java.util.Properties; 050 import java.util.Random; 051 052 import javax.swing.text.AttributeSet; 053 import javax.swing.text.Element; 054 import javax.swing.text.ElementIterator; 055 import javax.swing.text.StyleConstants; 056 import javax.swing.text.html.HTML; 057 import javax.swing.text.html.HTMLDocument; 058 import javax.swing.text.html.HTMLEditorKit; 059 import javax.swing.text.html.parser.ParserDelegator; 060 061 import org.apache.commons.httpclient.HttpMethod; 062 import org.apache.http.HttpResponse; 063 import org.apache.http.client.HttpClient; 064 import org.apache.http.client.methods.HttpPost; 065 import org.apache.http.entity.mime.MultipartEntity; 066 import org.apache.http.entity.mime.content.FileBody; 067 import org.apache.http.impl.client.DefaultHttpClient; 068 import org.apache.http.message.BasicHttpResponse; 069 import org.deegree.framework.log.ILogger; 070 import org.deegree.framework.log.LoggerFactory; 071 import org.deegree.framework.util.BootLogger; 072 import org.deegree.framework.util.FileUtils; 073 import org.deegree.framework.util.HttpUtils; 074 import org.deegree.framework.util.StringTools; 075 import org.deegree.framework.xml.NamespaceContext; 076 import org.deegree.framework.xml.XMLFragment; 077 import org.deegree.framework.xml.XMLTools; 078 import org.deegree.ogcbase.CommonNamespaces; 079 import org.w3c.dom.Node; 080 import org.xml.sax.SAXException; 081 082 /** 083 * TODO add class documentation here 084 * 085 * @author <a href="mailto:name@deegree.org">Andreas Poth</a> 086 * @author last edited by: $Author: poth $ 087 * 088 * @version $Revision: 1.3 $, $Date: 2011-03-09 07:41:56 $ 089 */ 090 public class InspireValidator { 091 092 private static final ILogger LOG = LoggerFactory.getLogger( InspireValidator.class ); 093 094 private static NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 095 096 private String cswAddress; 097 098 private String outputFile; 099 100 private PrintWriter outputWriter; 101 102 private XMLFragment query; 103 104 /** 105 * 106 * @param cswAddress 107 * @param outputFile 108 * @throws SAXException 109 * @throws IOException 110 * @throws MalformedURLException 111 */ 112 public InspireValidator( String cswAddress, String outputFile ) throws MalformedURLException, IOException, 113 SAXException { 114 this.outputFile = outputFile; 115 this.cswAddress = cswAddress; 116 } 117 118 /** 119 * 120 * @param cswAddress 121 * @param query 122 * @param outputFile 123 */ 124 public InspireValidator( String cswAddress, XMLFragment query, String outputFile ) { 125 this.query = query; 126 } 127 128 /** 129 * reads a number of random records from a CSW and validates them against INSPIRE metadata validator 130 * 131 * @param mr 132 * number of records to be tested 133 */ 134 public void runRandomQuery( String mr ) { 135 int maxQueries = 50; 136 if ( mr != null ) { 137 maxQueries = Integer.parseInt( mr ); 138 LOG.logInfo( Messages.get( "m1", mr ) ); 139 } else { 140 LOG.logInfo( Messages.get( "m2", mr ) ); 141 } 142 try { 143 int max = getNumberOfAvailableRecords(); 144 if ( maxQueries > max ) { 145 maxQueries = max; 146 LOG.logInfo( Messages.get( "m3", max ) ); 147 } 148 // create base GetRecords request without constraint but with startPosition and maxRecords = 1 149 String s = Messages.get( "getRecordsWithoutFilter" ); 150 XMLFragment request = new XMLFragment( new StringReader( s ), XMLFragment.DEFAULT_URL ); 151 Random random = new Random(); 152 outputWriter = new PrintWriter( new File( outputFile ) ); 153 for ( int i = 0; i < maxQueries; i++ ) { 154 // set index of record to read 155 Node node = XMLTools.getNode( request.getRootElement(), Messages.get( "xPathStartPosition" ), nsc ); 156 node.setNodeValue( Integer.toString( random.nextInt( max ) + 1 ) ); 157 158 HttpMethod m = HttpUtils.performHttpPost( cswAddress, request, 60000, null, null, null ); 159 XMLFragment xml = new XMLFragment(); 160 xml.load( m.getResponseBodyAsStream(), cswAddress ); 161 List<org.w3c.dom.Element> list = XMLTools.getElements( xml.getRootElement(), 162 Messages.get( "xPathMetadata" ), nsc ); 163 System.out.println( Messages.get( "m4", i + 1, maxQueries ) ); 164 outputWriter.println( "---------------------------------------------------------------------" ); 165 String id = XMLTools.getNodeAsString( list.get( 0 ), Messages.get( "xPathIdentifier" ), nsc, "none" ); 166 outputWriter.println( Messages.get( "m5", id ) ); 167 validateINSPIRE( list.get( 0 ) ); 168 } 169 System.out.println(); 170 } catch ( Exception e ) { 171 LOG.logError( e ); 172 } finally { 173 if ( outputWriter != null ) { 174 outputWriter.flush(); 175 outputWriter.close(); 176 } 177 } 178 System.out.println( Messages.get( "m6", new File( outputFile ).getAbsolutePath() ) ); 179 } 180 181 /** 182 * @return 183 * @throws IOException 184 * @throws SAXException 185 */ 186 private int getNumberOfAvailableRecords() 187 throws Exception { 188 String s = Messages.get( "getRecordsHits" ); 189 XMLFragment xml = new XMLFragment( new StringReader( s ), XMLFragment.DEFAULT_URL ); 190 HttpMethod m = HttpUtils.performHttpPost( cswAddress, xml, 60000, null, null, null ); 191 XMLFragment result = new XMLFragment(); 192 result.load( m.getResponseBodyAsStream(), cswAddress ); 193 return XMLTools.getNodeAsInt( result.getRootElement(), Messages.get( "xPathNumberOfRecordsMatched" ), nsc, 0 ); 194 } 195 196 /** 197 * reads a records from a CSW defined by a GetRecord request and validates them against INSPIRE metadata validator 198 * 199 * @param queryFile 200 * reference to GetRecords request 201 */ 202 public void runDefinedQuery( String queryFile ) { 203 try { 204 query = new XMLFragment( new File( queryFile ) ); 205 HttpMethod m = HttpUtils.performHttpPost( cswAddress, query, 60000, null, null, null ); 206 XMLFragment xml = new XMLFragment(); 207 xml.load( m.getResponseBodyAsStream(), cswAddress ); 208 List<org.w3c.dom.Element> list = XMLTools.getElements( xml.getRootElement(), 209 Messages.get( "xPathMetadata" ), nsc ); 210 outputWriter = new PrintWriter( new File( outputFile ) ); 211 int cnt = 1; 212 for ( org.w3c.dom.Element element : list ) { 213 System.out.println( Messages.get( "m7", cnt, list.size() ) ); 214 outputWriter.println( "---------------------------------------------------------------------" ); 215 String id = XMLTools.getNodeAsString( element, Messages.get( "xPathIdentifier" ), nsc, "none" ); 216 outputWriter.println( Messages.get( "m8", id ) ); 217 validateINSPIRE( element ); 218 cnt++; 219 } 220 System.out.println(); 221 } catch ( Exception e ) { 222 LOG.logError( e ); 223 } finally { 224 if ( outputWriter != null ) { 225 outputWriter.flush(); 226 outputWriter.close(); 227 } 228 } 229 System.out.println( "report stored at: " + new File( outputFile ).getAbsolutePath() ); 230 } 231 232 /** 233 * 234 * @param fileName 235 * name of a file containing a metadata record to be validated 236 */ 237 public void runISOFile( String fileName ) { 238 try { 239 XMLFragment xml = new XMLFragment( new File( fileName ) ); 240 outputWriter = new PrintWriter( new File( outputFile ) ); 241 outputWriter.println( "---------------------------------------------------------------------" ); 242 outputWriter.println( Messages.get( "m9", fileName ) ); 243 validateINSPIRE( xml.getRootElement() ); 244 } catch ( Exception e ) { 245 LOG.logError( e ); 246 } finally { 247 if ( outputWriter != null ) { 248 outputWriter.flush(); 249 outputWriter.close(); 250 } 251 } 252 } 253 254 /** 255 * 256 * @param dirName 257 * name of the directory containing metadata records to be validated 258 */ 259 public void runISOFileDirectory( String dirName ) { 260 try { 261 File dir = new File( dirName ); 262 File[] files = dir.listFiles(); 263 outputWriter = new PrintWriter( new File( outputFile ) ); 264 outputWriter.println( Messages.get( "m10", dir.getAbsolutePath() ) ); 265 for ( File file : files ) { 266 XMLFragment xml = new XMLFragment( file ); 267 outputWriter.println( "---------------------------------------------------------------------" ); 268 outputWriter.println( Messages.get( "m11", file.getAbsolutePath() ) ); 269 System.out.println( Messages.get( "m11", file.getAbsolutePath() ) ); 270 validateINSPIRE( xml.getRootElement() ); 271 } 272 } catch ( Exception e ) { 273 LOG.logError( e ); 274 } finally { 275 if ( outputWriter != null ) { 276 outputWriter.flush(); 277 outputWriter.close(); 278 } 279 } 280 } 281 282 /** 283 * main method to validate a metadata record using INSPIRE metadata validator 284 * 285 * @param element 286 * @throws Exception 287 */ 288 private void validateINSPIRE( org.w3c.dom.Element element ) 289 throws Exception { 290 HttpClient httpclient = new DefaultHttpClient(); 291 292 HttpPost httpPost = new HttpPost( Messages.get( "validator" ) ); 293 // xml response: httpPost.addHeader("Accept", "application/xml"); 294 // html response 295 httpPost.addHeader( "Accept", "text/html" ); 296 XMLFragment xml = new XMLFragment( element ); 297 File tmp = new File( "tmp.xml" ); 298 tmp.deleteOnExit(); 299 xml.write( new FileWriter( tmp ) ); 300 FileBody dataFile = new FileBody( new File( "tmp.xml" ) ); 301 MultipartEntity reqEntity = new MultipartEntity(); 302 reqEntity.addPart( "dataFile", dataFile ); 303 httpPost.setEntity( reqEntity ); 304 305 HttpResponse response = httpclient.execute( httpPost ); 306 parseServiceResponse( response ); 307 308 } 309 310 /** 311 * parse INSPIRE metadata validator response and print out result onto the console 312 * 313 * @param response 314 * @throws IOException 315 * @throws IllegalStateException 316 */ 317 private void parseServiceResponse( HttpResponse response ) 318 throws Exception { 319 String s = FileUtils.readTextFile( ( (BasicHttpResponse) response ).getEntity().getContent() ).toString(); 320 if ( response.getStatusLine().getStatusCode() != 200 ) { 321 outputWriter.println( s ); 322 outputWriter.println(); 323 return; 324 } 325 s = "<html><head></head><body>" + s + "</body></html>"; 326 BufferedReader br = new BufferedReader( new StringReader( s ) ); 327 328 HTMLEditorKit htmlKit = new HTMLEditorKit(); 329 HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument(); 330 HTMLEditorKit.Parser parser = new ParserDelegator(); 331 HTMLEditorKit.ParserCallback callback = htmlDoc.getReader( 0 ); 332 parser.parse( br, callback, true ); 333 334 // Parse 335 ElementIterator iterator = new ElementIterator( htmlDoc ); 336 Element element; 337 while ( ( element = iterator.next() ) != null ) { 338 AttributeSet attributes = element.getAttributes(); 339 Object name = attributes.getAttribute( StyleConstants.NameAttribute ); 340 if ( ( name instanceof HTML.Tag ) && ( ( name == HTML.Tag.IMPLIED ) ) ) { 341 // Build up content text as it may be within multiple elements 342 StringBuffer text = new StringBuffer(); 343 int count = element.getElementCount(); 344 for ( int i = 0; i < count; i++ ) { 345 Element child = element.getElement( i ); 346 AttributeSet childAttributes = child.getAttributes(); 347 if ( childAttributes.getAttribute( StyleConstants.NameAttribute ) == HTML.Tag.CONTENT ) { 348 int startOffset = child.getStartOffset(); 349 int endOffset = child.getEndOffset(); 350 int length = endOffset - startOffset; 351 text.append( htmlDoc.getText( startOffset, length ) ); 352 } 353 } 354 outputWriter.println( text.toString() ); 355 } 356 } 357 outputWriter.println( "---------------------------------------------------------------------" ); 358 outputWriter.println(); 359 } 360 361 /** 362 * validate input parameter 363 * 364 * @param map 365 * @throws Exception 366 */ 367 private static void validate( Properties map ) 368 throws Exception { 369 // if ( map.get( "-cswAddress" ) == null ) { 370 // throw new Exception( "-cswAddress parameter must be set" ); 371 // } 372 if ( map.get( "-outFile" ) == null ) { 373 map.put( "-outFile", "validation_result.txt" ); 374 } 375 376 } 377 378 public static void main( String[] args ) 379 throws Exception { 380 Properties map = new Properties(); 381 for ( int i = 0; i < args.length; i += 2 ) { 382 map.put( args[i], args[i + 1] ); 383 } 384 try { 385 validate( map ); 386 } catch ( Exception e ) { 387 LOG.logError( "!!! E R R O R !!!", e ); 388 return; 389 } 390 LOG.logInfo( Messages.get( "m16" ) ); 391 StringTools.printMap( map, System.out ); 392 InspireValidator iv = new InspireValidator( map.getProperty( "-cswAddress" ), map.getProperty( "-outFile" ) ); 393 if ( map.get( "-queryFile" ) != null ) { 394 LOG.logInfo( Messages.get( "m12" ), map.get( "-queryFile" ) ); 395 iv.runDefinedQuery( map.getProperty( "-queryFile" ) ); 396 } else if ( map.get( "-isoFile" ) != null ) { 397 LOG.logInfo( Messages.get( "m13" ), map.get( "-isoFile" ) ); 398 iv.runISOFile( map.getProperty( "-isoFile" ) ); 399 } else if ( map.get( "-directory" ) != null ) { 400 LOG.logInfo( Messages.get( "m14" ), map.get( "-directory" ) ); 401 iv.runISOFileDirectory( map.getProperty( "-directory" ) ); 402 } else { 403 LOG.logInfo( Messages.get( "m15" ) ); 404 iv.runRandomQuery( map.getProperty( "-maxRecords" ) ); 405 } 406 } 407 408 /** 409 * 410 * TODO add class documentation here 411 * 412 * @author <a href="mailto:name@deegree.org">Andreas Poth</a> 413 * @author last edited by: $Author: poth $ 414 * 415 * @version $Revision: 1.3 $, $Date: 2011-03-09 07:41:56 $ 416 */ 417 private static class Messages { 418 419 private static Properties props = new Properties(); 420 421 /** 422 * Initialization done at class loading time. 423 */ 424 static { 425 try { 426 InputStream is = InspireValidator.class.getResourceAsStream( "InspireValidator.properties" ); 427 props.load( is ); 428 is.close(); 429 } catch ( IOException e ) { 430 BootLogger.logError( "Error while initializing " + Messages.class.getName() + " : " + e.getMessage(), e ); 431 } 432 } 433 434 static String get( String key, Object... args ) { 435 String s = (String) props.get( key ); 436 if ( s != null ) { 437 return MessageFormat.format( s, args ); 438 } 439 440 return "$Message with key: " + key + " not found$"; 441 } 442 } 443 444 }