Author: ozeigermann Date: Tue Aug 14 15:37:07 2007 New Revision: 565953 URL: http://svn.apache.org/viewvc?view=rev&rev=565953 Log: First working version of tx file resource manager driven by test.
Added: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/DefaultTransactionTest.java - copied, changed from r565874, commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java Removed: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/deadlock1.png commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/deadlock2.png commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/deadlock3.png commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/ComboInputStreamMulticasterTest.java Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java Tue Aug 14 15:37:07 2007 @@ -38,6 +38,10 @@ this.code = code; } + public TransactionException(Throwable cause) { + super(cause); + } + public TransactionException(Code code) { this.code = code; } Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java Tue Aug 14 15:37:07 2007 @@ -27,6 +27,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.TransactionException; import org.apache.commons.transaction.resource.ResourceException; import org.apache.commons.transaction.resource.ResourceManager; import org.apache.commons.transaction.resource.StreamableResource; @@ -39,7 +40,13 @@ protected String rootPath; public FileResourceManager(String rootPath) { - this.rootPath = rootPath; + try { + File file = new File(rootPath); + file.mkdirs(); + this.rootPath = file.getCanonicalPath(); + } catch (IOException e) { + throw new TransactionException(e); + } } public FileResourceManager.FileResource getResource(String path) throws ResourceException { Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java Tue Aug 14 15:37:07 2007 @@ -14,10 +14,9 @@ public class MemoryUndoManager implements FileResourceUndoManager { private Log logger = LogFactory.getLog(getClass()); - + protected ThreadLocal<List<UndoRecord>> localRecords = new ThreadLocal<List<UndoRecord>>(); - private final File logDirectory; public MemoryUndoManager(String logDir) throws IOException { @@ -38,6 +37,10 @@ } public void forgetRecord() { + List<UndoRecord> records = new ArrayList<UndoRecord>(localRecords.get()); + for (UndoRecord record : records) { + record.cleanUp(); + } localRecords.set(null); } @@ -91,6 +94,12 @@ } protected void save() { + storeRecord(this); + } + + public void cleanUp() { + if (updatedFile != null) + updatedFile.delete(); } public void undo() { @@ -103,11 +112,11 @@ break; case UPDATED_CONTENT: try { - FileHelper.move(updatedFile, file); - } catch (IOException e) { - // FIXME: This really is fatal: How to signal? - logger.fatal("Can not undo content update", e); - } + FileHelper.move(updatedFile, file); + } catch (IOException e) { + // FIXME: This really is fatal: How to signal? + logger.fatal("Can not undo content update", e); + } break; } Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java Tue Aug 14 15:37:07 2007 @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -45,8 +46,6 @@ private Log logger = LogFactory.getLog(getClass()); - protected String rootPath; - protected FileResourceManager wrapped; protected FileResourceUndoManager undoManager; @@ -55,7 +54,6 @@ public TxFileResourceManager(String name, String rootPath) { super(name); - this.rootPath = rootPath; wrapped = new FileResourceManager(rootPath); } @@ -71,7 +69,7 @@ @Override public void setLm(LockManager<Object, Object> lm) { super.setLm(lm); - hlm = new HierarchicalRWLockManager(rootPath, lm); + hlm = new HierarchicalRWLockManager(getRootPath(), lm); } public class FileTxContext extends AbstractTxContext implements @@ -100,6 +98,12 @@ } @Override + public void start(long timeout, TimeUnit unit) { + getUndoManager().startRecord(); + super.start(timeout, unit); + } + + @Override public String getRootPath() { return TxFileResourceManager.this.getRootPath(); } @@ -329,12 +333,12 @@ } public void readLock() { - getHLM().lockInHierarchy(getName(), getPath(), false); + getHLM().lockInHierarchy(TxFileResourceManager.this.getName(), getPath(), false); super.readLock(); } public void writeLock() { - getHLM().lockInHierarchy(getName(), getPath(), true); + getHLM().lockInHierarchy(TxFileResourceManager.this.getName(), getPath(), true); super.writeLock(); } } @@ -356,7 +360,7 @@ } public String getRootPath() { - return rootPath; + return wrapped.getRootPath(); } protected FileResourceUndoManager getUndoManager() { Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java Tue Aug 14 15:37:07 2007 @@ -33,7 +33,11 @@ throws LockException { // strip off root path // TODO misses sane checks - String relativePath = path.substring(path.indexOf(rootPath)); + if (!path.startsWith(rootPath)) { + throw new LockException("Could not lock a path (" + path + + ") that is not under the rootPath (" + rootPath + ")"); + } + String relativePath = path.substring(rootPath.length()); // this is the root path we want to lock if (relativePath.length() == 0) { @@ -44,12 +48,13 @@ // always read lock root lock(managedResource, "/", false); - String[] segments = relativePath.split("/"); + String[] segments = relativePath.split("\\\\"); StringBuffer currentPath = new StringBuffer(relativePath.length()); // for root path currentPath.append('/'); - for (int i = 0; i < segments.length; i++) { + // skip first segment which is just empty + for (int i = 1; i < segments.length; i++) { String segment = segments[i]; currentPath.append(segment).append('/'); Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java Tue Aug 14 15:37:07 2007 @@ -34,23 +34,23 @@ * Thread has been interrupted while waiting for lock. */ INTERRUPTED, - + /** * Maximum wait time for a lock has been exceeded. */ TIMED_OUT, - + /** * Locking request canceled because of deadlock. */ WOULD_DEADLOCK, - + /** - * A conflict between two optimistic transactions occured. + * A conflict between two optimistic transactions occurred. * */ CONFLICT, - + /** * A commit was tried, but did not succeed. * @@ -61,6 +61,15 @@ protected Object resourceId; protected Code code; + + public LockException(String message, Object resourceId) { + super(message); + this.resourceId = resourceId; + } + + public LockException(String message) { + super(message); + } public LockException(String message, Code code, Object resourceId) { super(message); Copied: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/DefaultTransactionTest.java (from r565874, commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java) URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/DefaultTransactionTest.java?view=diff&rev=565953&p1=commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java&r1=565874&p2=commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/DefaultTransactionTest.java&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/DefaultTransactionTest.java Tue Aug 14 15:37:07 2007 @@ -26,14 +26,14 @@ import org.apache.commons.transaction.memory.TxMap; import org.junit.Test; -public class TransactionImplTest { +public class DefaultTransactionTest { public static junit.framework.Test suite() { - return new JUnit4TestAdapter(TransactionImplTest.class); + return new JUnit4TestAdapter(DefaultTransactionTest.class); } @Test public void basic() { - LockManager lm = new RWLockManager<String, String>(); + LockManager<Object, Object> lm = new RWLockManager<Object, Object>(); Transaction t = new DefaultTransaction(lm); TxMap<String, Object> txMap1 = new PessimisticTxMap<String, Object>("TxMap1"); t.enlistResourceManager(txMap1); @@ -52,6 +52,6 @@ } public static void main(String[] args) { - new TransactionImplTest().basic(); + new DefaultTransactionTest().basic(); } } Modified: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java?view=diff&rev=565953&r1=565952&r2=565953 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java Tue Aug 14 15:37:07 2007 @@ -16,11 +16,16 @@ */ package org.apache.commons.transaction.file; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.concurrent.TimeUnit; import junit.framework.JUnit4TestAdapter; +import static junit.framework.Assert.fail; import org.apache.commons.transaction.file.FileResourceManager.FileResource; import org.apache.commons.transaction.locking.LockManager; @@ -28,10 +33,143 @@ import org.junit.Test; public class TxFileResourceManagerTest { + + private static final String ENCODING = "ISO-8859-15"; + public static junit.framework.Test suite() { return new JUnit4TestAdapter(TxFileResourceManagerTest.class); } + private static final void createFiles(String[] filePaths) { + createFiles(filePaths, null, null); + } + + private static final void createFiles(String[] filePaths, String dirPath) { + createFiles(filePaths, null, dirPath); + } + + private static final void createFiles(String[] filePaths, String[] contents) { + createFiles(filePaths, contents, null); + } + + private static final void createFiles(String[] filePaths, String[] contents, String dirPath) { + for (int i = 0; i < filePaths.length; i++) { + String filePath = filePaths[i]; + File file; + if (dirPath != null) { + file = new File(new File(dirPath), filePath); + } else { + file = new File(filePath); + } + file.getParentFile().mkdirs(); + try { + file.delete(); + file.createNewFile(); + String content = null; + if (contents != null && contents.length > i) { + content = contents[i]; + } + if (content != null) { + FileOutputStream stream = new FileOutputStream(file); + stream.write(contents[i].getBytes(ENCODING)); + stream.close(); + } + } catch (IOException e) { + } + } + } + + private static final void checkIsEmpty(String dirPath) { + checkExactlyContains(dirPath, null); + } + private static final void checkExactlyContains(String dirPath, String[] fileNames) { + checkExactlyContains(dirPath, fileNames, null); + } + + private static final void checkExactlyContains(String dirPath, String[] fileNames, + String[] contents) { + File dir = new File(dirPath); + + if (dir.isDirectory()) { + File[] files = dir.listFiles(); + if (fileNames == null) { + if (files.length != 0) { + fail(dirPath + " must be empty"); + } else { + return; + } + } + + if (files.length != fileNames.length) { + fail(dirPath + " contains " + files.length + " instead of " + fileNames.length + + " files"); + } + + for (int i = 0; i < fileNames.length; i++) { + String fileName = fileNames[i]; + boolean match = false; + File file = null; + for (int j = 0; j < files.length; j++) { + file = files[j]; + if (file.getName().equals(fileName)) { + match = true; + break; + } + } + if (!match) { + fail(dirPath + " does not contain required " + fileName); + } + + String content = null; + if (contents != null && i < contents.length) { + content = contents[i]; + } + if (content != null && !compare(file, content)) { + fail("Contents of " + fileName + " in " + dirPath + + " does not contain required content '" + content + "'"); + } + } + + } else { + fail(dirPath + " is not directoy"); + } + } + + private static boolean compare(FileInputStream stream, byte[] bytes) { + int read; + int count = 0; + try { + while ((read = stream.read()) != -1) { + if (bytes[count++] != read) { + return false; + } + } + } catch (IOException e) { + return false; + } + return true; + } + + private static boolean compare(File file, String content) { + FileInputStream stream = null; + try { + byte[] bytes = content.getBytes(ENCODING); + stream = new FileInputStream(file); + return compare(stream, bytes); + } catch (Throwable t) { + return false; + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + + + @Test public void basic() { TxFileResourceManager manager = new TxFileResourceManager("TxFileManager", "d:/tmp/content"); @@ -43,12 +181,15 @@ manager.setUndoManager(um); manager.startTransaction(60, TimeUnit.SECONDS); FileResource file = manager.getResource("d:/tmp/content/aha"); - file.createAsFile(); - OutputStream os = file.writeStream(false); + if (!file.exists()) { + file.createAsFile(); + } + OutputStream os = file.writeStream(true); PrintStream ps = new PrintStream(os); - ps.print("Huhu"); + ps.println("Huhu"); manager.commitTransaction(); } catch (Throwable throwable) { + System.err.println(throwable); manager.rollbackTransaction(); }