I'm working on swing application that relies on an embedded H2 database. Because I don't want to bundle the database with the app(the db is frequently updated and I want new users of the app to start with a recent copy), I've implemented a solution which downloads a compressed copy of the db the first time the application is started and extracts it. Since the extraction process might be slow I've added a ProgressMonitorInputStream to show to progress of the extraction process - unfortunately when the extraction starts, the progress dialog shows up but it's not updated at all. It seems like to events are getting through to the event dispatch thread. Here is the method:
public static String extractDbFromArchive(String pathToArchive) {
if (SwingUtilities.isEventDispatchThread()) {
System.out.println("Invoking on event dispatch thread");
}
// Get the current path, where the database will be extracted
String currentPath = System.getProperty("user.home") + File.separator + ".spellbook" + File.separator;
LOGGER.info("Current path: " + currentPath);
try {
//Open the archive
FileInputStream archiveFileStream = new FileInputStream(pathToArchive);
// Read two bytes from the stream before it used by CBZip2InputStream
for (int i = 0; i < 2; i++) {
archiveFileStream.read();
}
// Open the gzip file and open the output file
CBZip2InputStream bz2 = new CBZip2InputStream(new ProgressMonitorInputStream(
null,
"Decompressing " + pathToArchive,
archiveFileStream));
FileOutputStream out = new FileOutputStream(ARCHIVED_DB_NAME);
LOGGER.info("Decompressing the tar file...");
// Transfer bytes from the compressed file to the output file
byte[] buffer = new byte[1024];
int len;
while ((len = bz2.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
// Close the file and stream
bz2.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
try {
TarInputStream tarInputStream = null;
TarEntry tarEntry;
tarInputStream = new TarInputStream(new ProgressMonitorInputStream(
null,
"Extracting " + ARCHIVED_DB_NAME,
new FileInputStream(ARCHIVED_DB_NAME)));
tarEntry = tarInputStream.getNextEntry();
byte[] buf1 = new byte[1024];
LOGGER.info("Extracting tar file");
while (tarEntry != null) {
//For each entry to be extracted
String entryName = currentPath + tarEntry.getName();
entryName = entryName.replace('/', File.separatorChar);
entryName = entryName.replace('\\', File.separatorChar);
LOGGER.info("Extracting entry: " + entryName);
FileOutputStream fileOutputStream;
File newFile = new File(entryName);
if (tarEntry.isDirectory()) {
if (!newFile.mkdirs()) {
break;
}
tarEntry = tarInputStream.getNextEntry();
continue;
}
fileOutputStream = new FileOutputStream(entryName);
int n;
while ((n = tarInputStream.read(buf1, 0, 1024)) > -1) {
fileOutputStream.write(buf1, 0, n);
}
fileOutputStream.close();
tarEntry = tarInputStream.getNextEntry();
}
tarInputStream.close();
} catch (Exception e) {
}
currentPath += "db" + File.separator + DB_FILE_NAME;
if (!currentPath.isEmpty()) {
LOGGER.info("DB placed in : " + currentPath);
}
return currentPath;
}
This method gets invoked on the event dispatch thread (SwingUtilities.isEventDispatchThread() returns true) so the UI components should be updated. I haven't implemented this as an SwingWorker since I need to wait for the extraction anyways before I can proceed with the initialization of the program. This method get invoked before the main JFrame of the application is visible. I don't won't a solution based on SwingWorker + property changed listeners - I think that the ProgressMonitorInputStream is exactly what I need, but I guess I'm not doing something right. I'm using Sun JDK 1.6.18. Any help would be greatly appreciated.