Question

I am using TrueZip in my application to add files/folders to a template zip then move the zip to a location specified by the user. When I run the application from Netbeans or run the .jar from command prompt everything works as I want. If the user names the zip "test" two files will be created where directed, the test.zip and a tmp file called "test.zip.{random-number}.tmp", and when the application is closed the tmp file is removed.

Now when I deploy my application to the web server with Java Web Start and run it the two files get created again, but when the application closes the tmp file isn't removed and when trying to open the created zip I get the message, "The archive is either in unknown format or damaged".

I can't figure out why it would work fine from netbeans or the .jar, but not through web start.

Code calling the class that is creating the zip:

JFileChooser chooser = new JFileChooser();
    chooser.setAcceptAllFileFilterUsed(false);
    chooser.addChoosableFileFilter(new FileFilter() { 
        @Override
        public boolean accept(File file) {
            if (file.isDirectory()) {
                return true;
            }
            if(file.getName().toLowerCase().endsWith(".zip")) {
                return true;
            }
            return false;
        }
        @Override
        public String getDescription() {
            return "*.zip";
        }
    });

    int rVal = chooser.showSaveDialog(this);

    if (rVal == JFileChooser.APPROVE_OPTION) {
        try {
            //Get savepath and ensure it ends with .zip extension
            String savePath = chooser.getSelectedFile().getCanonicalPath();
            if (!savePath.endsWith(".zip")) {
                savePath = savePath.concat(".zip");
            }

            PackageBuilder build = new PackageBuilder(groups, calibData);
            build.buildZip(savePath);
        } catch (IOException ex) {
            System.out.println(ex);
        }

    }

PackageBuilder class:

package apkinstallingaromacreator;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;

public class PackageBuilder {

    private File workingArchive;
    private AromaConfigBuilder aromaBuilder;
    private UpdaterScriptBuilder updaterBuilder;
    private ApkGroup[] groups;

    public PackageBuilder(ApkGroup[] groups, String calibData) {
        workingArchive = new File(System.getProperty("java.io.tmpdir"), "aromabuild.zip");
        aromaBuilder = new AromaConfigBuilder(groups, calibData);
        updaterBuilder = new UpdaterScriptBuilder(groups);
        this.groups = groups;

        //Get template.zip from jar package and move it to system tmp directory
        URL templateUrl = getClass().getResource("resources/template.zip");
        try {
            FileUtils.copyURLToFile(templateUrl, workingArchive);
        } catch (IOException ex) {
            System.out.println("Failed to copy template zip from resources");
            Logger.getLogger(PackageBuilder.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void importApkFiles() {
        //For each Apk in each ApkGroup add Apk file to zip in system tmp directory
        //If Apk doesn't list a file, create an empty directory for adding manually
        for (int x = 0; x < groups.length; x++) {
            Apk[] apks = groups[x].getApkArray();
            for (int y = 0; y < apks.length; y++) {
                if (apks[y].getApkFileLocation().isEmpty()) {
                    TFile dir = new TFile(workingArchive, "data/" + apks[y].getApkName());
                    dir.mkdir();
                }
                else {
                    TFile src = new TFile(apks[y].getApkFileLocation());
                    TFile dst = new TFile(workingArchive, "data/" + apks[y].getApkName() + 
                            "/" + apks[y].getApkName() + ".apk");
                    try {
                        src.cp_rp(dst);
                    } catch (IOException ex) {
                        Logger.getLogger(PackageBuilder.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            } 
        }
    }

    public void buildZip(String savePath) {
        //populate aroma-config file within template.zip
        File aroma = new TFile(workingArchive, "META-INF/com/google/android/aroma-config");
        try {
            Writer aromaWriter = new TFileWriter(aroma);
            aromaWriter.write(aromaBuilder.buildConfig());
            aromaWriter.close();
        } catch (IOException ex) {
            Logger.getLogger(PackageBuilder.class.getName()).log(Level.SEVERE, null, ex);
        }

        //Populate updater-script file within template.zip
        File updater = new TFile(workingArchive, "META-INF/com/google/android/updater-script");
        try {
            Writer updaterWriter = new TFileWriter(updater);
            updaterWriter.write(updaterBuilder.buildConfig());
            updaterWriter.close();
        } catch (IOException ex) {
            Logger.getLogger(PackageBuilder.class.getName()).log(Level.SEVERE, null, ex);
        }

        importApkFiles();

        //Copy the zip from system tmp directory to user specified location
        TFile src = new TFile(workingArchive);
        TFile dst = new TFile(savePath);

        try {
           src.cp_rp(dst);
        } catch (IOException ex) {
            Logger.getLogger(PackageBuilder.class.getName()).log(Level.SEVERE, null, ex);
        }   
    }
}
Was it helpful?

Solution

Apparently the shutdown hook isn't run to commit your changes to any archive files. Just add a call to TVFS.umount() wherever appropriate, e.g. in a finally-block in buildZip. Make sure to call it only once when you are done with the archive file, not for every change because this would result in quadratic run time.

Things to improve:

  • Make workingArchive a TFile rather than just a File to improve performance.
  • Remove the call to dir.mkdir() in importApkFiles(). Within archive files, it isn't required and results in a superfluous archive entry.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top