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 }