Re: [vfs] proposal: FileUtils
Hello! Sorry for being late, but I have had an appointment day with one of our customers. public abstract class Backup implements IOOperation { protected Backup(final FuPolicy policy) { And two implementations: public class NoBackup extends Backup { public class SimpleBackup extends Backup { The only thing I do not understand is why you need the policy if you extend the Backup. The derived classes are the policy. Else you should do somethink like NoBackupPolicy and SimpleBackupPolicy which will be passed to Backup. But I think extending Backup (to implement different policies) is good enough and then you could drop the policy, no? Ciao, Mario - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
What do you think, if the commands do not chain the next command, but if they create a Undo-Command which will be put on a stack and - in case of an exception can be processed to rollback all commands. I havent though about it in every detail, but if it is possible it is easier to handle - and in the case of a file-manager one could provide a undo function. In pseudo code: UndoStack tx = new UndoStack(); try { Backup(tx, ...) Copy(tx, ...) Move(tx, ...) } catch (Exception) { tx.rollback(); - process undo-stack } But again - [transaction] already do something like this. I think I have some time today evening to check this out. Ciao, Mario - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Mario Ivankovits wrote: In pseudo code: UndoStack tx = new UndoStack(); try { Backup(tx, ...) Copy(tx, ...) Move(tx, ...) } catch (Exception) { tx.rollback(); - process undo-stack } This looks ok. I still prefer each command to handle it's own cleanup (try/catch/finally in part existing for this purpose), but there's nothing wrong with the concept. I'm curious what you find out about Commons Transactions. When I looked it over, it seemd to me designed with primitives for us to use to make our own transactions. I missed any ready-to-use code for this purpose. I wonder how much overlap there is with java.util.concurrent in the new JDK 5. Cheers, --binkley - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Hello! I'm curious what you find out about Commons Transactions. When I looked it over, it seemd to me designed with primitives for us to use to make our own transactions. I missed any ready-to-use code for this purpose. I wonder how much overlap there is with java.util.concurrent in the new JDK 5. On their homepage they state they have done this for a java.io.File implementation. JDK5: Dont forget, our target is jdk1.3 (even if I use 1.5 since it is out) You cant imagine how fast the first user shouted after I used (by mistake) a jdk 1.4 method. --- Mario - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Mario Ivankovits wrote: JDK5: Dont forget, our target is jdk1.3 (even if I use 1.5 since it is out) You cant imagine how fast the first user shouted after I used (by mistake) a jdk 1.4 method. JDK 1.3!? I had no earthly idea. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
B. K. Oxley (binkley) wrote: I'm curious what you find out about Commons Transactions. When I looked it over, it seemd to me designed with primitives for us to use to make our own transactions. I missed any ready-to-use code for this purpose. After 2 hours of copy/paste their FileResourceManager to use vfs.FileObject only I am able to do such thing: // init phase String tx1 = tx1; VFSResourceManager rsm = new VFSResourceManager( VFS.getManager(), /home/im/tmp/tx/store, // = root filesystem where the real stuff should happen on commit /home/im/tmp/tx/work, // = work filesystem - could be different to store above new PrintWriterLogger(new PrintWriter(System.err), VFS, true), true ); rsm.start(); // start transaction rsm.startTransaction(tx1); // create file1 rsm.createResource(tx1, dir1/file1.txt); // create file2 rsm.createResource(tx1, dir2/file1.txt); // write into file1 OutputStream os = rsm.writeResource(tx1, dir1/file1.txt); os.write(test.getBytes()); os.close(); // delete file2 rsm.deleteResource(tx1, dir2/file1.txt); rsm.deleteResource(tx1, dir2); // = dir2 has been created by the above createResource - now we have to remove it here manually. // commit transaction rsm.commitTransaction(tx1); Now - whats missing in this example? right there is no move or rename operation. Summary: *) implement rename *) implement something like listResource(tx) where we could get a list of all files in an directory - including/excluding those created/deleted within the transation. Both need some more investigation to see how this could happen. After experimenting a little bit it is fantastic to see who it prevents two simultan transactions to create the same file - in fact it isnt prevent - the second transaction just waits until the first has finished and then the second gains the lock. So we get in-process locking for free. The above code is just a start, but think of a file-object where the transactional logic is encapsulated and one can do whatever he wants - it will only be represented on the filesystem if commit() has been called. FileObject foRootTransactional = VFS.getManager().beginTransaction(foRoot) for (child .. foRootTransactional.getChildren()) { child.delete(); } VFS.getManager().commitTransaction(foRootTransactional); And maybe if your RamFS comes to reality we could use it as work-space e.g. if we know we handle only small transactions. I am looking forward to read what you think about it. If you would like to experiment a little bit follow the instructions at http://l3x.net/imwiki/Wiki.jsp?page=VfsStuff --- Mario - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Continuing the command pattern, I rejiggered the Save command to use a Backup command rather than hard-coding the backup policy: public class Save implements IOOperation { private final Backup backup; private final InputStream newContents; private final FuFile original; public Save(final Backup backup, final InputStream newContents, final FuFile original) { if (null == backup) throw new NullPointerException(); if (null == newContents) throw new NullPointerException(); if (null == original) throw new NullPointerException(); this.backup = backup; this.newContents = newContents; this.original = original; } public void execute() throws IOException { backup.prepare(original, new Write(newContents, original)).execute(); } } Notice the prepare method which is an example of delayed initialization. Since Backup needs a next operation, but Save both needs a Backup and creates the next operation (a Write command), I cannot both create an immutable Backup and create an immutable Save at the same time. And looking at Backup: public abstract class Backup implements IOOperation { protected final FuPolicy policy; private FuFile original; private IOOperation next; protected Backup(final FuPolicy policy) { if (null == policy) throw new NullPointerException(); this.policy = policy; } protected FuFile getOriginal() { return original; } protected IOOperation getNext() { return next; } public Backup prepare(final FuFile original, final IOOperation next) { if (null == original) throw new NullPointerException(); if (null == next) throw new NullPointerException(); this.original = original; this.next = next; return this; } } And two implementations: public class NoBackup extends Backup { public NoBackup(final FuPolicy policy) { super(policy); } public void execute() throws IOException { final FuFile original = getOriginal(); new Delete(original, policy.createScratch(original), getNext()).execute(); } } public class SimpleBackup extends Backup { public SimpleBackup(final FuPolicy policy) { super(policy); } public void execute() throws IOException { final FuFile original = getOriginal(); final FuFile backup = policy.createBackup(original); new Delete(backup, policy.createScratch(backup), new Move(original, backup, getNext())).execute(); } } The second implementation, SimpleBackup, implements the policy hard-coded previously in Save. I still use the FuPolicy object to decide how to make a temporary and a backup file. I think that creating a backup should be merged into the Backup object instead, but I haven't decided what the best way to do that is. The problem scenario is an Emacs-scheme multiple backup (e.g., foo.txt, foo.txt.~1~, foo.txt.~2~, etc.). There the policy for naming backups and the backup command are very intimate, and really belong in the same object. Cheers, --binkley - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Mario Ivankovits wrote: Where do you think to implement this FileOperation interface? I miss the source fileobject -a s I said, I dont want to implement the interface in the FileObject and thus thought about something like this: DefaultFileOperations.get().copy(FileObject src, FileObject dest); I was going to pass the src in on construction of the operation object, but why? Using src as part of the parameter list seems just as good. void save(final OutputStream newContents, final FileObject dest, final boolean overwrite) throws FileSystemException; I have a strong distaste for using flags to control behavior in public methods. I find that it often leads to bugs when the flags are wrong, and it makes understanding the code more difficult. That is why I prefer explicitly named methods: void save(final OutputStream newContents, final FileObject dest) throws FileSystemException; void saveAndOverwrite(final OutputStream newContents, final FileObject dest) throws FileSystemException; How strong is your preference? If overwrite=false and the destination exists the methods should use backup() to create a backup of the destination file As an alternative, I took someone's suggestion of a policy object when I started coding a default implementation of the FileOperation interface, and let the policy object figure these things out. Another thing we could discuss is the usage of save(InputStream, ...). I renamed it to copy(InputStream, ...). I think if you do have an InputStream you would like to copy its output to another file - in opposite to save(OutputStream ...) where you do have the content of the file in memory (a bufferedImage, ) and would like to save it. I like save() because it describes the operation most closely from the point of view of the caller (Hey, save this file with these new contents!). The reason I used InputStream everywhere was for genericness (is that a word?). I pictured usage like this: // copy(src, dst) in your snippet operations.save(src, otherFile.getInputStream()); operations.save(src, new ByteArrayInputStream(blobInMemory.toArray()); This sort of negotiation over interface is painful remotely. I'd rather do it with my programming pairmate while writing unit tests. :-) Cheers, --binkley - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Hello! void save(final OutputStream newContents, final FileObject dest) throws FileSystemException; void saveAndOverwrite(final OutputStream newContents, final FileObject dest) throws FileSystemException; How strong is your preference? Doesnt lead such a design to have tons of saveAnd methods. And the code within those objects is highly redundant, isnt it? However, I will let this decision on you. I never tried this style, maybe it become accepted. If overwrite=false and the destination exists the methods should use backup() to create a backup of the destination file As an alternative, I took someone's suggestion of a policy object when I started coding a default implementation of the FileOperation interface, and let the policy object figure these things out. ;-) Wasnt it me? I wanted you to use a BackupPolicy. And yes - I think this is the cleanest solution. I just thought you didnt want to go this way now as I missed it in your latest proposal. If you already took this way it is even better. I like save() because it describes the operation most closely from the point of view of the caller (Hey, save this file with these new contents!). The reason I used InputStream everywhere was for genericness (is that a word?). I pictured usage like this: You ask me? A non native speaker. However, it sounds cool ;-)) // copy(src, dst) in your snippet operations.save(src, otherFile.getInputStream()); operations.save(src, new ByteArrayInputStream(blobInMemory.toArray()); Didnt you mean? operations.save(otherFile.getInputStream(), dest); operations.save(new ByteArrayInputStream(blobInMemory.toArray()), dest); But every Filesystem call it copy and even if you use a file-manager there is a menu-entry called copy. save or save As only exists if you do have the content of the file open in an editor - and then, from the point of development - it is easier if the save method took an outputStream. --- Mario smime.p7s Description: S/MIME Cryptographic Signature
Re: [vfs] proposal: FileUtils
I looked over the problem again and think I'd prefer a command object approach: public interface OperationE extends Exception { void execute() throws E; } And: public interface IOOperation extends OperationIOException { } (Excess abstraction, I know. I had a hard time resisting the coolness of generic exceptions.) And some operations: public class Move implements IOOperation { private final FuFile original, newLocation; private final IOOperation next; public Move(final FuFile original, final FuFile newLocation, final IOOperation next) { if (null == original) throw new NullPointerException(); if (null == newLocation) throw new NullPointerException(); if (null == next) throw new NullPointerException(); this.original = original; this.newLocation = newLocation; this.next = next; } public void execute() throws IOException { original.moveTo(newLocation); try { next.execute(); } catch (final IOException e) { newLocation.moveTo(original); throw e; } } } And to make a Save operation: public class Save implements IOOperation { private final FuPolicy policy; private final InputStream newContents; private final FuFile original; public Save(final FuPolicy policy, final InputStream newContents, final FuFile original) { if (null == policy) throw new NullPointerException(); if (null == newContents) throw new NullPointerException(); if (null == original) throw new NullPointerException(); this.policy = policy; this.newContents = newContents; this.original = original; } public void execute() throws IOException { final FuFile backup = policy.createBackup(original); new Delete(backup, policy.createScratch(backup), new Move(original, backup, new Write(newContents, original))).execute(); } } Isn't that nifty? :-) I get to use the policy object without interfering with FuFile (my dummy file object just for proof of concept); I can create complex operations by composing simpler operations as building blocks. In fact, perhaps I should pull new Delete(...), new Move(...) and new Write(...) out into fields of Save so that someone could replace them with subclassed instances via IoC. How does that suit you? Cheers, --binkley - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
How is this for an interface for file operations? public interface FileOperation { void save(final InputStream newContents) throws FileSystemException; void saveAndBackup(final InputStream newContents) throws FileSystemException; void copyTo(final FileName newLocation) throws FileSystemException; void copyToAndOverwrite(final FileName newLocation) throws FileSystemException; void moveTo(final FileName newLocation) throws FileSystemException; void moveToAndOverwrite(final FileName newLocation) throws FileSystemException; } I think this covers 80%+ of use cases. This is your classic cut/copy/paste operations with a file manager and the usual file-saving operation of an editor. Cheers, --binkley - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Hello! How is this for an interface for file operations? Where do you think to implement this FileOperation interface? I miss the source fileobject -a s I said, I dont want to implement the interface in the FileObject and thus thought about something like this: DefaultFileOperations.get().copy(FileObject src, FileObject dest); or - if you use your own (derived) implementation: FileOperations fops = new MyFileOperations(); // this has to be done only once for the whole application fops.copy(FileObject src, FileObject dest); public interface FileOperation { void save(final OutputStream newContents, final FileObject dest, final boolean overwrite) throws FileSystemException; void copy(final InputStream src, final FileObject dest, final boolean overwrite) throws FileSystemException; void copy(final FileObject src, final FileObject dest, final boolean overwrite) throws FileSystemException; void move(final FileObject src, final FileObject dest, final boolean overwrite) throws FileSystemException; void backup(final FileObject file) throws FileSystemException; } If overwrite=false and the destination exists the methods should use backup() to create a backup of the destination file Another thing we could discuss is the usage of save(InputStream, ...). I renamed it to copy(InputStream, ...). I think if you do have an InputStream you would like to copy its output to another file - in opposite to save(OutputStream ...) where you do have the content of the file in memory (a bufferedImage, ) and would like to save it. In this case the save(OutputStream ...) should write the content to a temporary file and later use move() to put it on its right place. What do you think about this? Ciao, Mario - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Hi Brian! Sorry for the long delay. I was in an delivery period and therefore out of time. After the next week I should have more time again. I am not sure we should implement a poor-man's transaction if we could have more ([transaction] ) for free. Hmmm, I would like to have a depper look on this, remind, if [transaction] fits our needs, we might have locking too. Please let us delay this decision for a while, before we do the hard work I would like to see myself that [transaction] is really overkill. Thanks! --- Mario smime.p7s Description: S/MIME Cryptographic Signature
Re: [vfs] proposal: FileUtils
Damn good work! I think we should introduce a FileUtils class, I dont want to bloat the FileObject with utility functions. About transactionality :- care should be taken to not reimplement something like [transaction], they already implemented such a beast using java.io.File. Maybe we can adopt it. So my FileUtils would look like this: public class FileUtils { void copy(InputStream is, FileObject fo) throws FuException; void copy(FileObject input, FileObject new) throws FuException; void copy(FileObject fo, OutputStream out) throws FuException; void copy(InputStream is, FileObject fo, BackupStrategy bs) throws FuException; void copy(FileObject input, FileObject new, BackupStrategy bs) throws FuException; void move(FileObject old, FileObject new) throws FuException; void move(FileObject old, FileObject new, BackupStrategy bs) throws FuException; void append(FileObject input, FileObject new) throws FuException; void append(InputStream is, FileObject new) throws FuException; void append(FileObject input, FileObject new, BackupStrategy bs) throws FuException; void append(InputStream is, FileObject new, BackupStrategy bs) throws FuException; void delete(FileObject fo) throws FuException; } public interface BackupStrategy { /** * Takes the fileObject and moves it away. * returns the new file or null if the file has been deleted. (e.g. file overwrite) */ FileObject createBackup(FileObject fileObject) throws FuException; } Thanks! --- Mario PS: isnt throw (IOException) new IOException().initCause(e); what you searched? - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [vfs] proposal: FileUtils
Mario Ivankovits wrote: About transactionality :- care should be taken to not reimplement something like [transaction], they already implemented such a beast using java.io.File. Maybe we can adopt it. I'll have to look at it, but it looked like overkill for what I had in mind. I've been toying with closure-like operations to take care of this, so that saving from an input stream with a backup looks like: FuFile newContent = new FuFile(newContentStream); new Move(backup, backup.createTemporary(), new Move(original, backup, new Move(newContent, original, Noop))) The bulk of Move is: public void eval() throws FuException { try { original.moveTo(newLocation); nextMoveClosure.eval(); } catch (FuException e) { newLocation.moveTo(original); throw e; } } This means that you try to rename the original, call the next operation and if that fails, undo the rename. It's a poor-man's transaction. If you look at the nesting of my first code snippet, it behaves like this: 1. Write the content to a temporary. 2. Move the backup to a temporary to recover the backup if other operations fail. 3. Move the original to the backup to recover the original if other operations fail. 4. Move the content temporary to the original. The only complication I didn't mention is that my actual code takes care of deleting the various temporaries when things fail or they don't. Another way to view this is that I took: try { doTryWork(); } catch (e) { doCatchWork(); throw e; } finally { doFinallyWork(); } And made each of the do work methods a closure object with an eval() method to invoke them. Cheers, Brian - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]