Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Validator locks file on failure - what am I doing wrong?

I am trying to validate an XML file against a schema in Java and the problem is that if the validation of the file fails, then the file becomes locked until the application terminates. If the input file was valid then the file does not become locked and everything is fine.

I'm using the javax.xml.validation.Validator and validate() method. This seems simple enough and is fine when validation passes. I can only assume that I am missing something in my error handling, but the API for Validator does not seem to supply anything that would be useful. Can anyone shed light on what I am doing wrong here?

I've simplified all of this into a stand-alone class below. If you run this then at the point when the Scanner starts, check the input file and you can see that it is now locked. I can supply an input and structure file if you require it.

Thanks,

Phil


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.URI;
import java.util.Scanner;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class ValidationTest {

    public static void validate(URI xmlLocation, URI schemaLocation) throws Exception {

        SchemaFactory schemaFactory = SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" );

        Source schemaSource = new StreamSource(schemaLocation.toString());
        Schema schema = schemaFactory.newSchema(schemaSource);

        Validator schemaValidator = schema.newValidator();

        StreamSource source = new StreamSource(xmlLocation.getPath());
        schemaValidator.validate( source );
    }


    public static void main(String[] args) throws Exception {
        File srcFile = new File("c:/aaa/MySrc-Broken.xml");
        File schema = new File("c:/aaa/MyStructureDefinition.xsd");

        try {
            ValidationTest.validate(srcFile.toURI(), schema.toURI());
        } catch(Exception e) {
            System.err.println(e);
        }

        // Use a Scanner to pause the thread, so that I can 
        // go and check the file's permissions.
        Scanner scan = new Scanner(System.in);
        scan.nextLine();
    }
}


Update:

I have a bit of a hack which provides a (bad) solution. I add a custom errorHandler to the schemaValidator. This errorHandler just stores any errors in a member variable. This means that the validator will always succeed and thus release all of the locks on the input file. However I then have to check the error handler to see if there were any errors and then throw an error if there were. This isn't great but does get me round this problem.

like image 487
Phil Avatar asked Nov 17 '11 16:11

Phil


2 Answers

Note that StreamSource instances are not allowed. (http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/Validator.html)

URL xmlFileURL = xmlFileToCheck.toURI().toURL();
InputStream inputStream = xmlFileURL.openStream();
InputSource is = new InputSource(inputStream);
SAXSource saxSource = new SAXSource(is);

xmlValidator.validate(saxSource);

inputStream.close(); // this is probably important...
like image 166
S.Zolta Avatar answered Nov 01 '22 13:11

S.Zolta


catch the exception raised in your validate() call, close the StreamSource object linked to your file in order to release the file resources, and then throw the exception up to your calling method.

edit: you may need to retrieve the InputStream explicitly in order to close the underlying file handle - it seems StreamSource doesn't define an explicit way to close the underlying stream. Check whether you get an InputStream object returned by source.getInputStream() - if so, closing this should release any underlying handles to your file.

like image 27
mcfinnigan Avatar answered Nov 01 '22 15:11

mcfinnigan