Nathan
Nathan

Reputation: 266

Unable to move file using renameTo()

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

Answers (1)

Jan
Jan

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

Related Questions