Author: ozeigermann
Date: Thu Jul 12 05:39:49 2007
New Revision: 555614

URL: http://svn.apache.org/viewvc?view=rev&rev=555614
Log:
Next chaotic step to initial version.
- Contains much work_in_progress code in the locking package
- util now contains working code for FileHelpers and FileSequence (cleaned from 
1.x logging / exception crap)

Added:
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/BookKeepingLockManager.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericBookKeepingLockManager.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLock.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockImpl.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockManager.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpCondition.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpLock.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpMultiLevelLock.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileHelper.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileSequence.java
Modified:
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/ComboInputStreamMulticaster.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/InputStreamMulticaster.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java
    
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java

Modified: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/ComboInputStreamMulticaster.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/ComboInputStreamMulticaster.java?view=diff&rev=555614&r1=555613&r2=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/ComboInputStreamMulticaster.java
 (original)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/ComboInputStreamMulticaster.java
 Thu Jul 12 05:39:49 2007
@@ -16,6 +16,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+// TODO: Add two dedicated locks for close/open resp. spawn
 public class ComboInputStreamMulticaster implements InputStreamMulticaster {
 
     private int memoryBufferSize = 8192;
@@ -30,6 +31,7 @@
 
     protected boolean isOpen = false;
 
+    @Override
     public synchronized void close() {
         if (!isOpen) {
             throw new IllegalStateException("You can not close: Stream 
multicaster is not open!");
@@ -37,6 +39,7 @@
         isOpen = false;
     }
 
+    @Override
     public synchronized void open(InputStream backingInputStream) throws 
IOException {
         if (isOpen) {
             throw new IllegalStateException(
@@ -75,6 +78,7 @@
         isOpen = true;
     }
 
+    @Override
     public synchronized InputStream spawn() throws IOException {
         if (!isOpen) {
             throw new IllegalStateException(

Modified: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/InputStreamMulticaster.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/InputStreamMulticaster.java?view=diff&rev=555614&r1=555613&r2=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/InputStreamMulticaster.java
 (original)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/InputStreamMulticaster.java
 Thu Jul 12 05:39:49 2007
@@ -1,9 +1,12 @@
 package org.apache.commons.transaction.file;
+
 import java.io.IOException;
 import java.io.InputStream;
 
 public interface InputStreamMulticaster {
     void open(InputStream backingInputStream) throws IOException;
+
     InputStream spawn() throws IOException;
+
     void close() throws IOException;
 }

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/BookKeepingLockManager.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/BookKeepingLockManager.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/BookKeepingLockManager.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/BookKeepingLockManager.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,11 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.Set;
+
+public interface BookKeepingLockManager<K, L> extends LockManager<K, L> {
+    public Set<L> getAllLocksForCurrentThread();
+    
+    // TODO: We need a means for a global timeout or at least
+    // something to demarcate transaction boundaries
+
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericBookKeepingLockManager.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericBookKeepingLockManager.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericBookKeepingLockManager.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericBookKeepingLockManager.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,15 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class GenericBookKeepingLockManager<K, L> extends GenericLockManager<K, 
L> implements BookKeepingLockManager<K, L>{
+    
+    protected final ConcurrentHashMap<K, L> globalOwners = new 
ConcurrentHashMap<K, L>();
+
+    public Set<L> getAllLocksForCurrentThread() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}

Modified: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java?view=diff&rev=555614&r1=555613&r2=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java
 (original)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java
 Thu Jul 12 05:39:49 2007
@@ -4,7 +4,7 @@
 
 public class GenericLockManager<K, L> implements LockManager<K, L> {
     
-    private final ConcurrentHashMap<K, L> globalLocks = new 
ConcurrentHashMap<K, L>();
+    protected final ConcurrentHashMap<K, L> globalLocks = new 
ConcurrentHashMap<K, L>();
 
     @Override
     public L getLock(K key) {

Modified: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java?view=diff&rev=555614&r1=555613&r2=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java
 (original)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java
 Thu Jul 12 05:39:49 2007
@@ -1,10 +1,10 @@
 package org.apache.commons.transaction.locking;
 
+
 public interface LockManager<K, L> {
     public L getLock(K key);
 
     public L createLockIfAbsent(K key, L lock);
 
     public L removeLock(K key);
-
 }

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLock.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLock.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLock.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLock.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,7 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.concurrent.locks.Lock;
+
+public interface MultiLevelLock {
+    Lock getLock(int level);
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockImpl.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockImpl.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockImpl.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockImpl.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,73 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.LockSupport;
+
+public class MultiLevelLockImpl implements MultiLevelLock {
+
+    private int maxLevel;
+    private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();
+
+    public MultiLevelLockImpl(int maxLevel) {
+        if (maxLevel < 1)
+            throw new IllegalArgumentException("The maximum lock level must be 
at least 1 ("
+                    + maxLevel + " was specified)");
+
+        this.maxLevel = maxLevel;
+    }
+
+    // for getter / setter injection
+    public MultiLevelLockImpl() {
+    }
+
+    public Lock getLock(int level) {
+        if (level > maxLevel)
+            throw new IllegalArgumentException("The requested lock level (" + 
level
+                    + ") is higher than the maximum lock level (" + maxLevel + 
")");
+
+    }
+
+    private class InternalMLLock implements Lock {
+
+        public void lock() {
+            LockSupport.park();
+        }
+
+        public void lockInterruptibly() throws InterruptedException {
+            // TODO Auto-generated method stub
+
+        }
+
+        public Condition newCondition() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public boolean tryLock() {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        public boolean tryLock(long time, TimeUnit unit) throws 
InterruptedException {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        public void unlock() {
+            LockSupport.unpark(thread)();
+        }
+    }
+
+    public int getMaxLevel() {
+        return maxLevel;
+    }
+
+    public void setMaxLevel(int maxLevel) {
+        this.maxLevel = maxLevel;
+    }
+
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockManager.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockManager.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockManager.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/MultiLevelLockManager.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,5 @@
+package org.apache.commons.transaction.locking;
+
+
+public class MultiLevelLockManager extends GenericLockManager<Object, 
MultiLevelLock> implements LockManager<Object, MultiLevelLock> {
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpCondition.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpCondition.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpCondition.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpCondition.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,51 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+
+public class NoOpCondition implements Condition {
+
+    @Override
+    public void await() throws InterruptedException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public boolean await(long time, TimeUnit unit) throws InterruptedException 
{
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public long awaitNanos(long nanosTimeout) throws InterruptedException {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public void awaitUninterruptibly() {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public boolean awaitUntil(Date deadline) throws InterruptedException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public void signal() {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void signalAll() {
+        // TODO Auto-generated method stub
+
+    }
+
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpLock.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpLock.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpLock.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpLock.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,40 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+public class NoOpLock implements Lock {
+
+    private final transient NoOpCondition internalCondition = new 
NoOpCondition();
+
+    @Override
+    public void lock() {
+    }
+
+    @Override
+    public void lockInterruptibly() throws InterruptedException {
+        if (Thread.currentThread().isInterrupted())
+            throw new InterruptedException();
+    }
+
+    @Override
+    public Condition newCondition() {
+        return internalCondition;
+    }
+
+    @Override
+    public boolean tryLock() {
+        return true;
+    }
+
+    @Override
+    public boolean tryLock(long time, TimeUnit unit) throws 
InterruptedException {
+        return true;
+    }
+
+    @Override
+    public void unlock() {
+    }
+
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpMultiLevelLock.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpMultiLevelLock.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpMultiLevelLock.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/NoOpMultiLevelLock.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,13 @@
+package org.apache.commons.transaction.locking;
+
+import java.util.concurrent.locks.Lock;
+
+public class NoOpMultiLevelLock implements MultiLevelLock {
+    private final transient NoOpLock internalLock = new NoOpLock();
+
+    
+    public Lock getLock(int level) {
+        return internalLock;
+    }
+
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileHelper.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileHelper.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileHelper.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileHelper.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.transaction.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Helper methods for file manipulation. 
+ * All methods are <em>thread safe</em>.
+ * 
+ * @version $Id: FileHelper.java 493628 2007-01-07 01:42:48Z joerg $
+ */
+public final class FileHelper {
+
+    private static int BUF_SIZE = 50000;
+    private static byte[] BUF = new byte[BUF_SIZE];
+
+    /**
+     * Deletes a file specified by a path.
+     *  
+     * @param path path of file to be deleted
+     * @return <code>true</code> if file has been deleted, <code>false</code> 
otherwise
+     */
+    public static boolean deleteFile(String path) {
+        File file = new File(path);
+        return file.delete();
+    }
+
+    /**
+     * Checks if a file specified by a path exits.
+     *  
+     * @param path path of file to be checked
+     * @return <code>true</code> if file exists, <code>false</code> otherwise
+     */
+    public static boolean fileExists(String path) {
+        File file = new File(path);
+        return file.exists();
+    }
+
+    /**
+     * Creates a file specified by a path. All necessary directories will be 
created.
+     * 
+     * @param path path of file to be created
+     * @return <code>true</code> if file has been created, <code>false</code> 
if the file already exists
+     * @throws  IOException
+     *          If an I/O error occurred
+     */
+    public static boolean createFile(String path) throws IOException {
+        File file = new File(path);
+        if (file.isDirectory()) {
+            return file.mkdirs();
+        } else {
+            File dir = file.getParentFile();
+            // do not check if this worked, as it may also return false, when 
all neccessary dirs are present
+            dir.mkdirs();
+            return file.createNewFile();
+        }
+    }
+
+    /**
+     * Removes a file. If the specified file is a directory all contained 
files will
+     * be removed recursively as well. 
+     * 
+     * @param toRemove file to be removed
+     */
+    public static void removeRec(File toRemove) {
+        if (toRemove.isDirectory()) {
+            File fileList[] = toRemove.listFiles();
+            for (int a = 0; a < fileList.length; a++) {
+                removeRec(fileList[a]);
+            }
+        }
+        toRemove.delete();
+    }
+
+    /**
+     * Moves one directory or file to another. Existing files will be replaced.
+     * 
+     * @param source file to move from
+     * @param target file to move to
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     */
+    public static void moveRec(File source, File target) throws IOException {
+        byte[] sharedBuffer = new byte[BUF_SIZE];
+        moveRec(source, target, sharedBuffer);
+    }
+
+    static void moveRec(File source, File target, byte[] sharedBuffer) throws 
IOException {
+        if (source.isDirectory()) {
+            if (!target.exists()) {
+                target.mkdirs();
+            }
+            if (target.isDirectory()) {
+
+                File[] files = source.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    File file = files[i];
+                    File targetFile = new File(target, file.getName());
+                    if (file.isFile()) {
+                        if (targetFile.exists()) {
+                            targetFile.delete();
+                        }
+                        if (!file.renameTo(targetFile)) {
+                            copy(file, targetFile, sharedBuffer);
+                            file.delete();
+                        }
+                    } else {
+                        if (!targetFile.exists()) {
+                            if (!targetFile.mkdirs()) {
+                                throw new IOException("Could not create target 
directory: "
+                                        + targetFile);
+                            }
+                        }
+                        moveRec(file, targetFile);
+                    }
+                }
+                source.delete();
+            }
+        } else {
+            if (!target.isDirectory()) {
+                copy(source, target, sharedBuffer);
+                source.delete();
+            }
+        }
+    }
+
+    /**
+     * Copies one directory or file to another. Existing files will be 
replaced.
+     * 
+     * @param source directory or file to copy from
+     * @param target directory or file to copy to
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     */
+    public static void copyRec(File source, File target) throws IOException {
+        byte[] sharedBuffer = new byte[BUF_SIZE];
+        copyRec(source, target, sharedBuffer);
+    }
+
+    static void copyRec(File source, File target, byte[] sharedBuffer) throws 
IOException {
+        if (source.isDirectory()) {
+            if (!target.exists()) {
+                target.mkdirs();
+            }
+            if (target.isDirectory()) {
+
+                File[] files = source.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    File file = files[i];
+                    File targetFile = new File(target, file.getName());
+                    if (file.isFile()) {
+                        if (targetFile.exists()) {
+                            targetFile.delete();
+                        }
+                        copy(file, targetFile, sharedBuffer);
+                    } else {
+                        targetFile.mkdirs();
+                        copyRec(file, targetFile);
+                    }
+                }
+            }
+        } else {
+            if (!target.isDirectory()) {
+                if (!target.exists()) {
+                    File dir = target.getParentFile();
+                    if(!dir.exists() && !dir.mkdirs()) {
+                        throw new IOException("Could not create target 
directory: " + dir);
+                    }
+                    if (!target.createNewFile()) {
+                        throw new IOException("Could not create target file: " 
+ target);
+                    }
+                }
+                copy(source, target, sharedBuffer);
+            }
+        }
+    }
+
+    /**
+     * Copies one file to another using [EMAIL PROTECTED] #copy(InputStream, 
OutputStream)}.
+     * 
+     * @param input
+     *            source file
+     * @param output
+     *            destination file
+     * @return the number of bytes copied
+     * @throws IOException
+     *             if an I/O error occurs (may result in partially done work)
+     * @see #copy(InputStream, OutputStream)
+     */
+    public static long copy(File input, File output) throws IOException {
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(input);
+            return copy(in, output);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Copies one file to another using the supplied buffer.
+     * 
+     * @param input source file
+     * @param output destination file
+     * @param copyBuffer buffer used for copying
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     * @see #copy(InputStream, OutputStream)
+     */
+    public static long copy(File input, File output, byte[] copyBuffer) throws 
IOException {
+        FileInputStream in = null;
+        FileOutputStream out = null;
+        try {
+            in = new FileInputStream(input);
+            out = new FileOutputStream(output);
+            return copy(in, out, copyBuffer);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                }
+            }
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Copies an <code>InputStream</code> to a file using [EMAIL PROTECTED] 
#copy(InputStream, OutputStream)}.
+     * 
+     * @param in stream to copy from 
+     * @param outputFile file to copy to
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     * @see #copy(InputStream, OutputStream)
+     */
+    public static long copy(InputStream in, File outputFile) throws 
IOException {
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(outputFile);
+            return copy(in, out);
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Copies an <code>InputStream</code> to an <code>OutputStream</code> 
using a local internal buffer for performance.
+     * Compared to [EMAIL PROTECTED] #globalBufferCopy(InputStream, 
OutputStream)} this method allows for better
+     * concurrency, but each time it is called generates a buffer which will 
be garbage.
+     * 
+     * @param in stream to copy from 
+     * @param out stream to copy to
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     * @see #globalBufferCopy(InputStream, OutputStream)
+     */
+    public static long copy(InputStream in, OutputStream out) throws 
IOException {
+        // we need a buffer of our own, so no one else interferes
+        byte[] buf = new byte[BUF_SIZE];
+        return copy(in, out, buf);
+    }
+
+    /**
+     * Copies an <code>InputStream</code> to an <code>OutputStream</code> 
using a global internal buffer for performance.
+     * Compared to [EMAIL PROTECTED] #copy(InputStream, OutputStream)} this 
method generated no garbage,
+     * but decreases concurrency.
+     * 
+     * @param in stream to copy from 
+     * @param out stream to copy to
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     * @see #copy(InputStream, OutputStream)
+     */
+    public static long globalBufferCopy(InputStream in, OutputStream out) 
throws IOException {
+        synchronized (BUF) {
+            return copy(in, out, BUF);
+        }
+    }
+
+    /**
+     * Copies an <code>InputStream</code> to an <code>OutputStream</code> 
using the specified buffer. 
+     * 
+     * @param in stream to copy from 
+     * @param out stream to copy to
+     * @param copyBuffer buffer used for copying
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs (may result in partially 
done work)  
+     * @see #globalBufferCopy(InputStream, OutputStream)
+     * @see #copy(InputStream, OutputStream)
+     */
+    public static long copy(InputStream in, OutputStream out, byte[] 
copyBuffer) throws IOException {
+        long bytesCopied = 0;
+        int read = -1;
+
+        while ((read = in.read(copyBuffer, 0, copyBuffer.length)) != -1) {
+            out.write(copyBuffer, 0, read);
+            bytesCopied += read;
+        }
+        return bytesCopied;
+    }
+}

Added: 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileSequence.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileSequence.java?view=auto&rev=555614
==============================================================================
--- 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileSequence.java
 (added)
+++ 
jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/util/FileSequence.java
 Thu Jul 12 05:39:49 2007
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.transaction.util;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.transaction.util.FileHelper;
+
+/**
+ * Fail-Safe sequence store implementation using the file system. Works by
+ * versioning values of sequences and throwing away all versions, but the
+ * current and the previous one.
+ * 
+ * @version $Id: FileSequence.java 493628 2007-01-07 01:42:48Z joerg $
+ */
+public class FileSequence {
+
+    private Log logger = LogFactory.getLog(getClass());
+
+    protected final String storeDir;
+
+    /**
+     * Creates a new resouce manager operation on the specified directories.
+     * 
+     * @param storeDir
+     *            directory where sequence information is stored
+     * @param logger
+     *            logger used for warnings only
+     */
+    public FileSequence(String storeDir) {
+        this.storeDir = storeDir;
+        File file = new File(storeDir);
+        file.mkdirs();
+        if (!file.exists()) {
+            throw new IllegalStateException("Can not create working directory 
" + storeDir);
+        }
+    }
+
+    /**
+     * Checks if the sequence already exists.
+     * 
+     * @param sequenceName
+     *            the name of the sequence you want to check
+     * @return <code>true</code> if the sequence already exists,
+     *         <code>false</code> otherwise
+     */
+    public synchronized boolean exists(String sequenceName) {
+        String pathI = getPathI(sequenceName);
+        String pathII = getPathII(sequenceName);
+
+        return (FileHelper.fileExists(pathI) || FileHelper.fileExists(pathII));
+    }
+
+    /**
+     * Creates a sequence if it does not already exist.
+     * 
+     * @param sequenceName
+     *            the name of the sequence you want to create
+     * @return <code>true</code> if the sequence has been created,
+     *         <code>false</code> if it already existed
+     */
+    public synchronized boolean create(String sequenceName, long initialValue) 
{
+        if (exists(sequenceName))
+            return false;
+        write(sequenceName, initialValue);
+        return true;
+    }
+
+    /**
+     * Deletes a sequence if it exists.
+     * 
+     * @param sequenceName
+     *            the name of the sequence you want to delete
+     * @return <code>true</code> if the sequence has been deleted,
+     *         <code>false</code> if not
+     */
+    public synchronized boolean delete(String sequenceName) {
+        if (!exists(sequenceName))
+            return false;
+        String pathI = getPathI(sequenceName);
+        String pathII = getPathII(sequenceName);
+
+        // XXX be careful no to use shortcut eval with || might not delete
+        // second file
+        boolean res1 = FileHelper.deleteFile(pathI);
+        boolean res2 = FileHelper.deleteFile(pathII);
+
+        return (res1 || res2);
+    }
+
+    /**
+     * Gets the next value of the sequence.
+     * 
+     * @param sequenceName
+     *            the name of the sequence you want the next value for
+     * @param increment
+     *            the increment for the sequence, i.e. how much to add to the
+     *            sequence with this call
+     * @return the next value of the sequence <em>not yet incremented</em>,
+     *         i.e. the increment is recorded internally, but not returned with
+     *         the next call to this method
+     * @throws ResourceManagerException
+     *             if anything goes wrong while accessing the sequence
+     */
+    public synchronized long nextSequenceValueBottom(String sequenceName, long 
increment) {
+        if (!exists(sequenceName)) {
+            throw new IllegalStateException("Sequence " + sequenceName + " 
does not exist");
+        }
+        if (increment <= 0) {
+            throw new IllegalArgumentException("Increment must be greater than 
0, was " + increment);
+        }
+        long value = read(sequenceName);
+        long newValue = value + increment;
+        write(sequenceName, newValue);
+        return value;
+    }
+
+    protected long read(String sequenceName) {
+        String pathI = getPathI(sequenceName);
+        String pathII = getPathII(sequenceName);
+
+        long returnValue = -1;
+
+        long valueI = -1;
+        if (FileHelper.fileExists(pathI)) {
+            try {
+                valueI = readFromPath(pathI);
+            } catch (NumberFormatException e) {
+                throw new Error("Fatal internal error: Backup sequence value 
corrupted");
+            } catch (FileNotFoundException e) {
+                throw new Error("Fatal internal error: Backup sequence 
vanished");
+            } catch (IOException e) {
+                throw new Error("Fatal internal error: Backup sequence value 
corrupted");
+            }
+        }
+
+        long valueII = -1;
+        if (FileHelper.fileExists(pathII)) {
+            try {
+                valueII = readFromPath(pathII);
+                if (valueII > valueI) {
+                    returnValue = valueII;
+                } else {
+                    // if it is smaller than previous this *must* be an error 
as
+                    // we constantly increment
+                    logger
+                            .warn("Latest sequence value smaller than 
previous, reverting to previous");
+                    FileHelper.deleteFile(pathII);
+                    returnValue = valueI;
+                }
+            } catch (NumberFormatException e) {
+                logger.warn("Latest sequence value corrupted, reverting to 
previous");
+                FileHelper.deleteFile(pathII);
+                returnValue = valueI;
+            } catch (FileNotFoundException e) {
+                logger.warn("Can not find latest sequence value, reverting to 
previous");
+                FileHelper.deleteFile(pathII);
+                returnValue = valueI;
+            } catch (IOException e) {
+                logger.warn("Can not read latest sequence value, reverting to 
previous");
+                FileHelper.deleteFile(pathII);
+                returnValue = valueI;
+            }
+        } else {
+            logger.warn("Can not read latest sequence value, reverting to 
previous");
+            returnValue = valueI;
+        }
+
+        if (returnValue != -1) {
+            return returnValue;
+        } else {
+            throw new Error("Fatal internal error: Could not compute valid 
sequence value");
+        }
+    }
+
+    protected void write(String sequenceName, long value) {
+        String pathII = getPathII(sequenceName);
+
+        File f2 = new File(pathII);
+        // by contract when this method is called an f2 exists it must be valid
+        if (f2.exists()) {
+            // move previous value to backup position
+            String pathI = getPathI(sequenceName);
+            File f1 = new File(pathI);
+            f1.delete();
+            if (!f2.renameTo(f1)) {
+                throw new Error("Fatal internal error: Can not create backup 
value at" + pathI);
+            }
+        }
+        try {
+            if (!f2.createNewFile()) {
+                throw new Error("Fatal internal error: Can not create new 
value at" + pathII);
+            }
+        } catch (IOException e) {
+            throw new Error("Fatal internal error: Can not create new value 
at" + pathII, e);
+        }
+        writeToPath(pathII, value);
+    }
+
+    protected String getPathI(String sequenceName) {
+        return storeDir + "/" + sequenceName + "_1.seq";
+    }
+
+    protected String getPathII(String sequenceName) {
+        return storeDir + "/" + sequenceName + "_2.seq";
+    }
+
+    protected long readFromPath(String path) throws NumberFormatException, 
FileNotFoundException,
+            IOException {
+        File file = new File(path);
+        BufferedReader reader = null;
+        try {
+            InputStream is = new FileInputStream(file);
+
+            // we do not care for encoding as we only have numbers
+            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+            String valueString = reader.readLine();
+            long value = Long.parseLong(valueString);
+            return value;
+        } catch (UnsupportedEncodingException e) {
+            throw new Error("Fatal internal error, encoding UTF-8 unknown");
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                }
+
+            }
+        }
+    }
+
+    protected void writeToPath(String path, long value) {
+        File file = new File(path);
+        BufferedWriter writer = null;
+        try {
+            OutputStream os = new FileOutputStream(file);
+            writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
+            String valueString = Long.toString(value);
+            writer.write(valueString);
+            writer.write('\n');
+        } catch (FileNotFoundException e) {
+            throw new Error("Fatal internal error: Can not find sequence at " 
+ path);
+        } catch (IOException e) {
+            throw new Error("Fatal internal error: Can not write to sequence 
at " + path);
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                }
+
+            }
+        }
+    }
+}



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

Reply via email to