View Javadoc

1   package org.musicontroller.core.jobs;
2   
3   import java.io.BufferedInputStream;
4   import java.io.File;
5   import java.io.InputStream;
6   import java.util.HashMap;
7   import java.util.Map;
8   
9   import org.apache.log4j.Logger;
10  import org.musicontroller.service.FileUtils;
11  import org.varienaja.util.FileOperations;
12  import org.varienaja.util.TolerantZipInputStream;
13  
14  /**
15   * The ImportJob is responsible for unpacking zip-files and placing unpacked
16   * files in the appropriate directories.
17   * 
18   * The ImportJob is run every few seconds. It scans for files in the
19   * upload-directory. If there are files present, the first will be unpacked
20   * into the unpack-directory.
21   * 
22   * @author Varienaja
23   */
24  public class ImportJob {
25  	private static final Logger log = Logger.getLogger(ImportJob.class);
26  	public static final String READY_FOR_INSPECTION = "readyforinspection";
27  	public static final String TRANSFERRING = "transferring";
28  
29  	private static Map<String,InputStream> _todo = new HashMap<String,InputStream>();
30  	
31  	/**
32  	 * Call this method to add an inputstream to the TODO-list
33  	 * @param in An InputStream
34  	 * @param name A name (filename without path) for the InputStream
35  	 */
36  	public static synchronized void addData(InputStream in, String name) {
37  		//TODO Throw Exception if filename or inputstream is null?
38  		_todo.put(name,in);
39  	}
40  	
41  	/* TODO Files are saved in directories which have a name starting with "mcbusy"
42  	 * When all processing is complete, this prefix is deleted from the name.
43  	 * This way, the processing-job can see which directories contain files
44  	 * fit for further processing.
45  	 */
46  	/**
47  	 * This method is to be executed periodically. It checks for the presence of
48  	 * new 'todos', and if there is something to do, the file is moved (non-zip) or
49  	 * unpacked (zip) to the Unpackdir ( @see FileUtils). This method should not 
50  	 * be run in parallel (avoid disk-thrashing unpacking many files at a time).
51  	 * 
52  	 * Unpacked files are unpacked into a 'working'-directory. (busyunzipping)
53  	 * When the job is done, this directory is renamed to 'readyforinspection'
54  	 * to signal other processes they can read from the directory now. As long
55  	 * as the directory is still named busyunzipping, files can be in an incomplete
56  	 * state and should not be read.
57  	 * @return true if there was something done, alse if there was nothing to do.
58  	 */
59  	public int execute() {
60  		if (log.isDebugEnabled()) {
61  			long total = Runtime.getRuntime().totalMemory();
62  			long max = Runtime.getRuntime().maxMemory();
63  			long free = Runtime.getRuntime().freeMemory();
64  			StringBuilder sb = new StringBuilder();
65  			sb.append("Memory usage: ");
66  			sb.append( (total - free) / 1048576);
67  			sb.append("M of ");
68  			sb.append(max / 1048576);
69  			sb.append("M.");
70  			
71  			log.debug(sb.toString());
72  		}
73  		int result = 0;
74  		if (_todo.size()>0) {
75  			try {
76  				String fileName = _todo.keySet().iterator().next();
77  				InputStream fis = _todo.get(fileName);
78  				_todo.remove(fileName);
79  				
80  				String uniqueDir = FileOperations.createUniqueFilename(
81  						FileUtils.getUnpackdir()+File.separator,TRANSFERRING);
82  				File targetdir = new File(uniqueDir);
83  				if (!targetdir.mkdirs()) {
84  					throw new Exception("Could not create directory: "+targetdir);
85  				}
86  				if (fileName.toLowerCase().endsWith(".zip")) {
87  					log.debug("Unpacking "+fileName+" to temporary review-storage.");
88  					TolerantZipInputStream zis = new TolerantZipInputStream(new BufferedInputStream(fis));
89  					result = FileOperations.extractToDirectory(zis, uniqueDir);
90  				} else {
91  					log.debug("Moving "+fileName+" to temporary review-storage.");
92  					FileOperations.streamToFile(fis, uniqueDir+File.separator+fileName);
93  					result = 1;
94  				}
95  				
96  				String renameddirname = FileOperations.createUniqueFilename(
97  						FileUtils.getUnpackdir()+File.separator,READY_FOR_INSPECTION);
98  				File renameddir = new File(renameddirname);
99  				if (!targetdir.renameTo(renameddir)) {
100 					throw new Exception("Could not rename directory: "+targetdir+" to: "+renameddir);
101 				}
102 				
103 				log.debug("Processing complete.");
104 			} catch (Exception e) {
105 				log.error("Error processing input: "+e);
106 			}
107 		}
108 		return result;
109 	}
110 	
111 }