Thursday, July 05, 2012

How To Dump File Structure To XML. Part 3 (Final Part)

In Part1 we learned how to operate with XSD schemas and design you XML-based DSL. Then in Part 2 we learned how to build the parser and apply the business logic to owr application. We made our application capable to store the file structure in XML file.

Now we need the oposite operation. We need to restore file structure from XML file. Remember that that's only a structure, not the content, so every file will not hold a byte of information, just a name (aka record in file system).

Validating XML file with XSD schema


So, check this snippet:

public class XMLToFS {

 public static void reproduce(String sourceFile) throws SAXException, IOException, JAXBException{
  JAXBContext context = JAXBContext.newInstance(XTFSFolderRoot.class);
  Unmarshaller reader = context.createUnmarshaller();
  File schemaFile = new File("conf/fstoxml.xsd");
  File sampleFile = new File(sourceFile);
  validateAgainstSchema(schemaFile, sampleFile);
  XTFSFolderRoot rootNode = (XTFSFolderRoot) reader.unmarshal(sampleFile);
  long startTime = System.currentTimeMillis();
  new FSCreator(rootNode).create();
  System.out.println("Finished in " + String.valueOf(System.currentTimeMillis() - startTime) + " milliseconds");
  
 }

 static void validateAgainstSchema(File schema, File targetXml) throws SAXException, IOException{
  SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  Schema referenceSchema = schemaFactory.newSchema(schema);
  Validator schemaValidator = referenceSchema.newValidator();
  schemaValidator.validate(new StreamSource(targetXml));
  System.out.println("Xml file conforms specified schema.");
 }
}

XML recursive going round

This is the main acting class to reproduce the file system from an XML file. It requires the schema designed in previous posts to parse the input content genereated by previousely described functionality. This snippet is also the example of how to validate xml file against xsd schema. As it is seen it's quite simple - just use the pattern.
After we have validated our input data, we should process the data to get the file structure. First we should create the root object from the data from file (aka unmarshall) - see line #9. Once we have the object we can pass it to the dedicated code to reporoduce the structure as the set of files on your hard drive. Such the functioality I incapsulated in FSCreator class. Here it is:


public class FSCreator {

 XTFSFolderRoot rootNode;
 
 public FSCreator(XTFSFolderRoot rootNode){
  this.rootNode = rootNode;
 }
 
 public void create() throws IOException{
  File rootFolder = new File(rootNode.getPath());
  if(!rootFolder.isDirectory()){
   boolean isSuccess = rootFolder.mkdir();
   if(!isSuccess){
    throw new IOException("Root folder failed to get created");
   }
  }
  reproduceFileFolderStructure(rootNode.getFolderOrFile(), rootFolder);
 }
 
 private void reproduceFileFolderStructure(List<XTFSFile> currentInput, File parent){
  for(XTFSFile item: currentInput){
   if(item instanceof XTFSFolder){
    System.out.println("Processing folder " + parent.getAbsolutePath() + "\\" + item.getName());
    File newParent = new File(parent, item.getName());
    newParent.mkdir();
    reproduceFileFolderStructure(((XTFSFolder) item).getFolderOrFile(), newParent);
   }else if(item instanceof XTFSFile){
    System.out.println("Processing file " + parent.getAbsolutePath() + "\\" + item.getName());
    try {
     new File(parent, item.getName()).createNewFile();
    } catch (IOException e) {
     System.out.println("Skipping due to IO error");
    }
   }else{
    throw new IllegalStateException("Unrecognized class of the object");
   }
  }
 }
 
}


As you can see it uses recursive function to walk through a tree and process every node depending on its type. Point the attention to lines #22, #27. We have to check which type exactly the node implements as we process files and folders in different way. It is also very important how you order type check (it's important to check if the object is of Folder type first).

The new and finalized application sources you can find here. It now has combined dump/reproduce features with single entry point. You also may download the built solution which is ready to use.