Reputation: 266
I currently have a file monitor, which reads an XML file and updates database tables base on the contents. When a file is read it is validated against a specific schema to ensure the contents are correct.
The result of the validation effects the destination of the file to move.
If the schema is successful, there are no issues when moving the file to the processed directory, however, when the schema fails I am unable to rename the file itself.
However, when I debug and explore the file paths to ensure the file is being moved to the right location, it often allows me to rename the file which makes me think this is a timing issue.
File Monitor Class :
// Get a directory listing;
FilterFiles filterFiles = new FilterFiles();
String inbox = GlobalVars.getConfiguration().getInboundInbox();
String [] dir = new File(inbox).list(filterFiles);
// Wait 500 ms before obtaining files (Avoid the ResourceBusy error);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// Log errors
logger.info("Interrupted Exception " + e.getMessage());
new LogStackTrace(logger, e);
e.printStackTrace();
}
// Iterate through directory;
for ( int a=0; a < dir.length; a++ ) {
// Derive the full file path i.e. folder + path name;
String fullFilePath = GetAbsoloutePath.getFullAbsoluteFilePath(inbox, dir[a]);
logger.info("==========================================================");
logger.info("");
logger.info("Found File : " + fullFilePath);
logger.info("==========================================================");
// Does the file exist & can we read the file at this time;
File file = new File(fullFilePath);
if (file.exists() && file.canRead()) {
// Process the file;
StringBuffer renamedFile = new StringBuffer();
// Rename the file to indicate InProgess;
String fileName = file.getAbsolutePath();
String fileNameInProgress = fileName.trim() + ".InProgress";
// Delete the file if exists where we are moving the file to;
File deleteFile = new File(fileNameInProgress);
if (deleteFile.delete()) logger.info("Existing file deleted: " + fileNameInProgress);
// Ensure file is renamed so we can see it is in progress
if (!file.renameTo(new File(fileNameInProgress)) ) {
// Logging
logger.error("Failed to renamed file :" + fileName + " to " + fileNameInProgress);
break;
}else{
logger.info("Renamed file to : " + fileNameInProgress);
// Pass back name of renamed file;
renamedFile.append(fileNameInProgress);
File renamedFileRef = new File(renamedFile.toString());
// Path to move - could be errors or processed
String pathToMove = "";
// Parse XMobject
ParseInboundXML par = new ParseInboundXML();
// check if parse was succesful
if(par.parseXML(renamedFileRef, con)){
// Path to move XML file
pathToMove = GlobalVars.getConfiguration().getInboundProcessed()+ "\\" + file.getName();
//Logging
logger.info("File parsed and tables updated successfully");
logger.info("Moving file to : " + pathToMove);
}else{
pathToMove = GlobalVars.getConfiguration().getInboundErrors()+ "\\" + file.getName();
//Logging
logger.error("Errors when parsing file and updating tables");
logger.error("Moving file to : " + pathToMove);
}
// Help with garbage collection
par = null;
// New file
File newPath = new File(pathToMove);
// Need to check if this already exists in processed- if so we must override the existing file
// Otherwise the move will not be processed and the same docuemnt will be continously processed
if(newPath.exists())
newPath.delete();
After the above code has been executed, this block of code is executed and this is where the rename fails:
// Rename path so it is placed in processed folder
if(renamedFileRef.renameTo(newPath)){
//Logging
logger.info("File processed successfully");
}else{
// Logging
logger.error("Unable process file");
}
Within the code you may notice the call to :
// Parse XMobject
ParseInboundXML par = new ParseInboundXML();
// check if parse was succesful
if(par.parseXML(renamedFileRef, con)){
This method is where the validation occurs and the parsing of the XML document and returns a true or false value depending on the outcome.
The area in which it fails is at the start of the method :
// Find schema path
String schemaPath = GlobalVars.getConfiguration().getInboundSchemaLocation();
String schemaFileName = "WMS_" + file.getAbsoluteFile().toString().split("#")[2] + ".xsd";
// Schema location
String schemaLocation = schemaPath + "\\" + schemaFileName;
// Create schema factory
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// Schema file
Source schemaFile = new StreamSource(new File(schemaLocation));
// Apply schema and validate XML
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
Source xmlFile = new StreamSource(file);
validator.validate(xmlFile);
I think the issue may lie around
Source xmlFile = new StreamSource(file);
as this is the file we try to rename, and i think if it fails validation, its possible that this may be keeping the file open and would explain why there are no issues when it passes validation.
EDIT
This is the catch clause for a failed validation:
catch (SAXException e) {
// Write Error Record
CreateErrorMessages.createIW702Message(record.getTrno701TransactionNumber(), IntegrationConstants.SAX_ERROR, "SAX Error", e.toString(), con);
// Logging
logger.info("SAX Exception " + e.getMessage());
// Log stack trace
new LogStackTrace(logger, e);
// Prints to stack trace
e.printStackTrace();
return false;
}
Upvotes: 1
Views: 1109
Reputation: 13858
If you want to later rename the file, it has to be closed first. Apparently, your code does not do that.
Closing StreamSource and Moving files after failed validation (Java) suggest to not pass in a File
but instead a FileInputStream
that you can then close at the end yourself (or use try-with-resource)
try(InputStream in = new FileInputStream (file)) {
Source xmlFile = new StreamSource(fr);
validator.validate(xmlFile);
}
Upvotes: 1