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]