It occured to me later on, that I think this interface would be better if it were focused on describing an Archive, rather than trying to describe two processes (ie describing the noun rather than all the verbs). The fall out from this, is that you don't have a member for an unpack directory, since that is only relevent to the unpacking process. and I think it makes the interface I went to mock this up and came up with a couple other issues with the interface.

1) Adding an entry or a file to an archive, you need to be able to set the entry name, otherwise you can run into problems with getting just the right relative path in the archive for the files. 2) It is pretty common to want to recursively add directories, we should provide this in the archive API

I've attached my mock-up so folks can see if they think these thoughts make sense. I tried to borrow design and parameter conventions from some of the commons-io methods I use alot.

   --Will


will pugh wrote:

Overall, I like the interfaces, but I've got a few issues:

0) Update is mentioned in the Javadoc at the beginning of Archiver, but is not implemented.

1) You often change method names based on the parameter types, e.g. Archiver.addFile + Archiver.addFileName, setUnpackDestinationName + setUnpackDestinationFile, etc. It seems more conventional and less chaotic to give all the methods the same name, and have them only differ based on parameter. Examples of this style are constructors for java.utils.zip.ZipFile, java.io.FileInputStream, java.io.FileOutputStream, org.apache.commons.io.IOUtils.IOUtils.copy, org.apache.commons.io.FileUtils.isFileNewer, etc

2) You can only add files to an archive, this makes it more difficult to add generated entries into an archive. You need to actually write them to disk before including them in an archive

3) UnpackDestination + Destination should be the same property (on the both the interface as well as underlying implementation), or you should split packing and unpacking into two different interfaces (or force folks to pass a path to pack + unpack, instead of setting properties on the object).

4) None of your interfaces deal with the case of what to do if the destination file is already there. Choices are either defining it in the interface, or adding a property defining what to do. I would suggest the latter, and would suggest that for Archiver this method should take a FileFilter (since the unpack behaviour can be non-trivial) and should default to FalseFileFilter.INSTANCE. For the Compresser interface a simple boolean is probably sufficient. e.g.

   Archiver.setOverwriteFilter(TrueFileFilter.INSTANCE)
   Compresser.setOverwrite(true);

5) In AbstractCompressor, I don't understand why you have a copy method and don't just use IOUtils.copy() 6) In AbstractCompressor, I don't understand why you try to create your own temp name, rather than just letting File.createTempFile do it's thing.

   --Will

C. Grobmeier wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello all,

here is a new draft for the compress interface:

* http://grobmeier.de/commons-compress-draft-5.zip

I have improved a lot of things, based on the comments of Sandy (thanks
for that).

This draft is not perfect, as you can see in the todo list. But imho we
have a quite good base for future work, everything compiles and works
and is documented. So i would like to propose that someone is comitting
this, except you have reasons not to do this.
If you agree with me, i will open a bugzilla issue and add the link to
the code.

- - Chris.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEVKMikv8rKBUE/T4RAlxxAKCMYzova2roWDA/skRyoDvFcErE2gCfTjFw
bT2VrGdR8Byt+VjsRo7Cyhw=
=1GRF
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

package org.apache.commons.compress;

import java.io.*;
import java.util.Iterator;

/**
 * Archiver is an interface that defines a generic achive file.  This interface
 * allows a caller to inspect the entries in an archive, create new ones, add 
entries to existing ones
 * or to expand an archive.
 *
 *
 * @author christian.grobmeier
 */
public interface MyArchiver {

    /**
     * If pack is called with this as the <i>overwrite</i> parameter, the method
     * will fail if the ArchiveFile exists.
     */
    public static final int FAIL_ON_EXISTANCE = 0;

    /**
     * If pack is called with this as the <i>overwrite</i> parameter, the method
     * will overwrite ArchiveFile.  The new archive will only contain the 
entries
     * added via <i>addEntry</i>.
     */
    public static final int OVERWRITE_ON_EXISTANCE = 1;

    /**
     * If pack is called with this as the <i>overwrite</i> parameter, the method
     * will add the new entries added via <i>addEntry</i> to the ArchiveFile.
     */
    public static final int APPEND_ON_EXISTANCE = 2;


    /**
     * Adds a file to the internal filelist
     * for a possible pack-operation
     *
     * @param name the name for this entry in the archive
     * @param file the file who's contents will be put in the archive
     */
    public void addEntry(String name, File file);

    /**
     * Adds a file to the internal filelist
     *
     * @param name the name for this entry in the archive.  In the case that 
recurs is true, all the
     * child names will be generated using <i>name</i> as the base.
     * @param file the file to add to the archive
     * @param recurse whether to recurse into the children of file, in the case 
that file is a direcotry
     */
    public void addEntry(String name, File file, boolean recurse);

    /**
     * Adds a file to the internal filelist
     *
     * @param name the name for this entry in the archive.  In the case that 
recurs is true, all the
     * child names will be generated using <i>name</i> as the base.
     * @param fileFilter filter for which children should be included
     * @param fileFilter filter for which directory children should be recursed 
into
     */
    public void addEntry(String name, File file, FileFilter fileFilter, 
FileFilter dirFilter);


    /**
     * Adds a new entry to the archiver, where the contents come in from
     * an input stream rather than having to come in from a file.
     *
     * @param name the name for this entry in the archive
     * @param contents the InputStream that contains the contents to put in the 
archive
     */
    public void addEntry(String name, InputStream contents);

  
    /**
     * Iterates through the files in the archive.  This will include
     * any entries added through the addEntry apis.
     *
     * @return an interater that will contain objects of type ArchiveEntry
     */
    public Iterator getArchiveEntries();

    /**
     * Returns the file that backs this archive.
     * @return the file
     */
    public File getArchiveFile();


    /**
     * Sets the file that will back this archive.
     * @param file the file that will back this archive
     */
    public void setArchiveFile(File file);

    /**
     * Unpacks a file to the provided directory
     *
     * @param destination the directory to unpack the archive to.  This 
parameter must refer to a directory
     * @throws org.apache.commons.compress.UnpackException if an unpack error 
occures
     * @throws java.lang.IllegalArgumentException if destination is a file 
instead of a directory
     * @throws java.io.FileNotFoundException if the destination does not exist
     */
    public void unpack(File destination) throws IOException;

    /**
     * Unpacks a file to the provided directory.  This method also provides a 
parameter to
     * define overwrite sematics.  It allows you to set a FileFilter to define 
when to overwrite existing
     * files or not. The filter should return:
     *          true when it should overwrite a file,
     *          false if the file should not be overwritten,
     *          or it throw an exception if this
     *
     * If you want to always ignore files that already exist, you can use 
org.apache.commons.io.filefilter.FalseFileFilter.INSTANCE
     * If you want to always overwrite files that already exist, you can use 
org.apache.commons.io.filefilter.TrueFileFilter.INSTANCE
     * If you want to always throw an error when a file already exists, you can 
use org.apache.commons.compress.ErrorFileFilter.INSTANCE
     *
     * @param destination the directory to unpack the archive to.  This 
parameter must refer to a directory
     * @param overwriteFilter a file filter that gets called when a file 
already exists on the filesystem.
     * @throws org.apache.commons.compress.UnpackException if an unpack error 
occures
     * @throws java.lang.IllegalArgumentException if destination is a file 
instead of a directory
     * @throws java.io.FileNotFoundException if the destination does not exist
     */
    public void unpack(File destination, FileFilter overwriteFilter) throws 
IOException;


    /**
     * Writes all the entries to the archive file
     * If there is already file that exists with that name, we will overwrite 
it.
     *
     * @throws org.apache.commons.compress.PackException if there is no 
destination file or files to be packed
     */
    public void pack() throws PackException;


    /**
     * Writes all the entries to the archive file
     * If there is already file that exists with that name, we will overwrite 
it.
     *
     * @param overrideOptions this provides the option for what to do incase a 
the ArchiveFile already exists
     * @throws org.apache.commons.compress.PackException if there is no 
destination file or files to be packed
     */
    public void pack(int overrideOptions) throws PackException;


    //UNDONE(willpugh) -- This should be it's own top level class, but is 
nested currently for
    // demonstration purposes
    static public interface ArchiveEntry {
        String getName();
        InputStream getConents();
    }

    //UNDONE(willpugh) -- This should be it's own top level class, but is 
nested currently for
    // demonstration purposes
    static public class FileOverwriteError extends RuntimeException {
        private File    file;

        public FileOverwriteError(File file) {
            this.setFile(file);
        }


        public File getFile() {
            return file;
        }

        public void setFile(File file) {
            this.file = file;
        }
    }

    //UNDONE(willpugh) -- This should be it's own top level class, but is 
nested currently for
    // demonstration purposes.  This will be 
org.apache.commons.compress.ErrorFileFilter
    static public class ErrorFileFilter implements FileFilter {
        public static final FileFilter INSTANCE = new ErrorFileFilter();

        public boolean accept(File file) {
            throw new FileOverwriteError(file);
        }
    }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to