Author: ozeigermann Date: Mon Jul 23 13:54:15 2007 New Revision: 558857 URL: http://svn.apache.org/viewvc?view=rev&rev=558857 Log: First step to (yet non-working) pessimistic tx file manager having undo log
Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java Removed: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/DefaultPathManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/PathManager.java Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java?view=auto&rev=558857 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java Mon Jul 23 13:54:15 2007 @@ -0,0 +1,204 @@ +/* + * 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.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.resource.ResourceException; +import org.apache.commons.transaction.resource.ResourceManager; +import org.apache.commons.transaction.resource.StreamableResource; +import org.apache.commons.transaction.util.FileHelper; + +public class FileResourceManager implements ResourceManager<StreamableResource> { + + private Log logger = LogFactory.getLog(getClass()); + + protected String rootPath; + + public FileResourceManager(String rootPath) { + this.rootPath = rootPath; + } + + public StreamableResource getResource(String path) throws ResourceException { + return new FileResource(path); + } + + public String getRootPath() { + return rootPath; + } + + protected static class FileResource implements StreamableResource { + + protected File file; + + public FileResource(String path) { + this.file = new File(path); + } + + public FileResource(File file) { + this.file = file; + } + + public void createAsDirectory() throws ResourceException { + if (!file.mkdirs()) { + throw new ResourceException("Could not create directory"); + } + + } + + public void createAsFile() throws ResourceException { + try { + if (!file.createNewFile()) { + throw new ResourceException("Could not create file"); + } + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public void delete() throws ResourceException { + if (!file.delete()) + throw new ResourceException("Could not create file"); + + } + + public boolean exists() { + return file.exists(); + } + + public List<StreamableResource> getChildren() throws ResourceException { + List<StreamableResource> result = new ArrayList<StreamableResource>(); + File[] files = file.listFiles(); + for (File file : files) { + result.add(new FileResource(file)); + } + return result; + } + + public StreamableResource getParent() throws ResourceException { + // FIXME: Is reasonable, but would require refernce to enclosing class + /* + if (getPath().equals(getRootPath())) + return null; + */ + File parent = file.getParentFile(); + return new FileResource(parent); + } + + public String getPath() throws ResourceException { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public boolean isDirectory() { + return file.isDirectory(); + } + + public boolean isFile() { + return file.isFile(); + } + + public void move(String destinationpath) throws ResourceException { + File destination = new File(destinationpath); + try { + FileHelper.moveUsingNIO(file, destination); + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public void copy(String destinationpath) throws ResourceException { + File destination = new File(destinationpath); + try { + FileHelper.copyUsingNIO(file, destination); + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public InputStream readStream() throws ResourceException { + try { + FileInputStream is = new FileInputStream(file); + return is; + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public OutputStream writeStream(boolean append) throws ResourceException { + try { + FileOutputStream os = new FileOutputStream(file); + return os; + } catch (IOException e) { + throw new ResourceException(e); + } + } + + public void removeProperty(String name) { + throw new UnsupportedOperationException("You can not remove properties from files!"); + } + + public void setProperty(String name, Object newValue) { + throw new UnsupportedOperationException("You can not set properties on files!"); + } + + public Object getProperty(String name) { + if (name.equals("lastModified")) { + return file.lastModified(); + } + if (name.equals("length")) { + return file.length(); + } + return null; + } + + // XXX no op, only way to lock is using FileChannel#lock() and + // FileChannel#tryLock() + public boolean tryReadLock() { + return true; + } + + // XXX no op, only way to lock is using FileChannel#lock() and + // FileChannel#tryLock() + public boolean tryWriteLock() { + return true; + } + + // XXX no op, only way to lock is using FileChannel#lock() and + // FileChannel#tryLock() + public void readLock() { + } + + // XXX no op, only way to lock is using FileChannel#lock() and + // FileChannel#tryLock() + public void writeLock() { + } + + } +} Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java?view=auto&rev=558857 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java Mon Jul 23 13:54:15 2007 @@ -0,0 +1,31 @@ +package org.apache.commons.transaction.file; + +import java.io.File; + +public interface FileResourceUndoManager { + + public enum Code { + CREATED_DIRECTORY, CREATED_FILE, DELETED_DIRECTORY, MOVED, COPIED, CONTENT_CHANGED, PROPERTY_CHANGED + } + + public void startRecord(); + + public void undoRecord(); + + public void forgetRecord(); + + public void recordCopy(File from, File to); + + public void recordCreateAsDirectory(File directory); + + public void recordCreateAsFile(File file); + + public void recordDelete(File file); + + public void recordMove(File from, File to); + + public void recordChangeProperty(File file, String name, Object oldValue); + + public void recordChangeContent(File file); + +} Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java?view=auto&rev=558857 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java Mon Jul 23 13:54:15 2007 @@ -0,0 +1,136 @@ +package org.apache.commons.transaction.file; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.FileHelper; + +// TODO: memory version to be serialized to XML using JAXB +public class MemoryUndoManager implements FileResourceUndoManager { + + private Log logger = LogFactory.getLog(getClass()); + protected ThreadLocal<List<UndoRecord>> localRecords = new ThreadLocal<List<UndoRecord>>(); + + + public void recordChangeContent(File file) { + UndoRecord record = new UndoRecord(); + record.code = Code.CONTENT_CHANGED; + record.file = file; + try { + record.oldConent = new ByteArrayInputStream(FileHelper.readInto(file)); + } catch (IOException e) { + logger.fatal("Could not store changed content for "+file); + // FIXME: This really should cause an error + } + storeRecord(record); + } + + public void recordCopy(File from, File to) { + if (to.exists()) { + recordChangeContent(to); + } + UndoRecord record = new UndoRecord(); + record.code = Code.COPIED; + record.file = from; + record.to = to; + storeRecord(record); + } + + public void recordCreateAsDirectory(File directory) { + UndoRecord record = new UndoRecord(); + record.code = Code.CREATED_DIRECTORY; + record.file = directory; + storeRecord(record); + } + + public void recordCreateAsFile(File file) { + UndoRecord record = new UndoRecord(); + record.code = Code.CREATED_FILE; + record.file = file; + storeRecord(record); + } + + public void recordDelete(File file) { + if (file.isFile()) { + recordChangeContent(file); + } else { + UndoRecord record = new UndoRecord(); + record.code = Code.DELETED_DIRECTORY; + record.file = file; + storeRecord(record); + } + } + + public void recordMove(File from, File to) { + if (to.exists()) { + recordChangeContent(to); + } + UndoRecord record = new UndoRecord(); + record.code = Code.MOVED; + record.file = from; + record.to = to; + storeRecord(record); + } + + public void recordChangeProperty(File file, String name, Object oldValue) { + UndoRecord record = new UndoRecord(); + record.code = Code.PROPERTY_CHANGED; + record.file = file; + record.propertyName = name; + record.oldValue = oldValue; + storeRecord(record); + } + + public void startRecord() { + localRecords.set(new ArrayList<UndoRecord>()); + } + + public void undoRecord() { + List<UndoRecord> records = new ArrayList<UndoRecord>(localRecords.get()); + Collections.reverse(records); + for (UndoRecord record : records) { + record.undo(); + } + } + + public void forgetRecord() { + localRecords.set(null); + } + + protected void storeRecord(UndoRecord record) { + List<UndoRecord> records = localRecords.get(); + records.add(record); + } + + protected static class UndoRecord { + Code code; + + File file; + + File to; + + String propertyName; + + Object oldValue; + + InputStream oldConent; + + // FIXME: Needs implementation (not that hard) + // ugly c-style - who cares? + public void undo() { + // TODO + switch (code) { + + } + + } + } + +} Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java?view=diff&rev=558857&r1=558856&r2=558857 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java Mon Jul 23 13:54:15 2007 @@ -18,82 +18,46 @@ import java.io.Closeable; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.transaction.AbstractTransactionalResourceManager; -import org.apache.commons.transaction.TransactionalResourceManager; +import org.apache.commons.transaction.ManageableResourceManager; import org.apache.commons.transaction.AbstractTransactionalResourceManager.AbstractTxContext; +import org.apache.commons.transaction.file.FileResourceManager.FileResource; import org.apache.commons.transaction.locking.LockException; +import org.apache.commons.transaction.resource.ResourceException; import org.apache.commons.transaction.resource.ResourceManager; import org.apache.commons.transaction.resource.StreamableResource; -import org.apache.commons.transaction.util.FileHelper; public class TxFileResourceManager extends AbstractTransactionalResourceManager<TxFileResourceManager.FileTxContext> implements - ResourceManager<StreamableResource> { + ManageableResourceManager, ResourceManager<StreamableResource> { private Log logger = LogFactory.getLog(getClass()); protected String contextFileName = "transaction.log"; - protected PathManager idMapper; + protected String rootPath; - protected TransactionalResourceManager tm; + protected FileResourceManager wrapped; - public static void applyDeletes(File removeDir, File targetDir, File rootDir) - throws IOException { - if (removeDir.isDirectory() && targetDir.isDirectory()) { - File[] files = removeDir.listFiles(); - for (int i = 0; i < files.length; i++) { - File removeFile = files[i]; - File targetFile = new File(targetDir, removeFile.getName()); - if (!removeFile.isDirectory()) { - if (targetFile.exists()) { - if (!targetFile.delete()) { - throw new IOException("Could not delete file " + removeFile.getName() - + " in directory targetDir"); - } - } else if (!targetFile.isFile()) { - // this is likely a dangling link - targetFile.delete(); - } - // indicate, this has been done - removeFile.delete(); - } else { - applyDeletes(removeFile, targetFile, rootDir); - } - // delete empty target directories, except root dir - if (!targetDir.equals(rootDir) && targetDir.list().length == 0) { - targetDir.delete(); - } - } - } - } + protected FileResourceUndoManager undoManager; - public String getContextFileName() { - return contextFileName; + public TxFileResourceManager(String rootPath) { + this.rootPath = rootPath; + wrapped = new FileResourceManager(rootPath); } public void setContextFileName(String contextFile) { this.contextFileName = contextFile; } - public PathManager getIdMapper() { - return idMapper; - } - - public void setIdMapper(PathManager idMapper) { - this.idMapper = idMapper; - } - @Override protected FileTxContext createContext() { return new FileTxContext(); @@ -101,91 +65,175 @@ // TODO resource manager needs to forward requests to this context, locking // will happen here - public class FileTxContext extends AbstractTxContext implements FileResourceManager { + // FIXME + // needs + // - custom commit / rollback + // - proper resource tracking + public class FileTxContext extends AbstractTxContext implements + ResourceManager<StreamableResource> { // list of streams participating in this tx private Collection<Closeable> openStreams = new ArrayList<Closeable>(); public FileTxContext() { - super(); - String changeDir = getIdMapper().getChangeBaseDir(); - String deleteDir = getIdMapper().getDeleteBaseDir(); - - new File(changeDir).mkdirs(); - new File(deleteDir).mkdirs(); } - public void commit() { - super.commit(); - String changeDir = getIdMapper().getChangeBaseDir(); - String deleteDir = getIdMapper().getDeleteBaseDir(); - String storeDir = getIdMapper().getStoreDir(); - - try { - applyDeletes(new File(deleteDir), new File(storeDir), new File(storeDir)); - FileHelper.moveRec(new File(changeDir), new File(storeDir)); - } catch (IOException e) { - throw new LockException(LockException.Code.COMMIT_FAILED, e); - } + protected void registerStream(Closeable stream) { + openStreams.add(stream); } - public void cleanUp() { - String baseDir = getIdMapper().getTransactionBaseDir(); - FileHelper.removeRec(new File(baseDir)); + public StreamableResource getResource(String path) throws ResourceException { + return new TxFileResource(path); } - public boolean copy(String sourceId, String destinationId) throws IOException, - LockException { - // TODO Auto-generated method stub - return false; + public String getRootPath() { + return TxFileResourceManager.this.getRootPath(); } - public boolean createDir(String id) throws IOException, LockException { - // TODO Auto-generated method stub - return false; - } + // FIXME needs custom implementations + // Details: + // - Hierarchical locking + // - Calls to configured undo manager + protected class TxFileResource extends FileResource { - public boolean move(String sourceId, String destinationId) throws IOException, - LockException { - // TODO Auto-generated method stub - return false; - } + public TxFileResource(File file) { + super(file); + } - public InputStream read(String id) throws IOException, LockException { - readLock(id); - String path = getIdMapper().getPathForRead(id); - InputStream is = new FileInputStream(new File(path)); - registerStream(is); - return is; - } + public TxFileResource(String path) { + super(path); + } - public OutputStream write(String id) throws IOException { - writeLock(id); - String path = getIdMapper().getPathForRead(id); - return new FileOutputStream(new File(path)); - } + public void copy(String destinationpath) throws ResourceException { + super.copy(destinationpath); + } - public boolean remove(String id) throws IOException { - writeLock(id); - String path = getIdMapper().getPathForDelete(id); - return new File(path).delete(); - } + public void createAsDirectory() throws ResourceException { + super.createAsDirectory(); + } - public boolean create(String id) throws IOException { - writeLock(id); - String path = getIdMapper().getPathForDelete(id); - return new File(path).createNewFile(); - } + public void createAsFile() throws ResourceException { + super.createAsFile(); + } + + public void delete() throws ResourceException { + super.delete(); + } + + public boolean exists() { + return super.exists(); + } + + public List<StreamableResource> getChildren() throws ResourceException { + return super.getChildren(); + } + + public StreamableResource getParent() throws ResourceException { + return super.getParent(); + } + + public String getPath() throws ResourceException { + return super.getPath(); + } + + public Object getProperty(String name) { + return super.getProperty(name); + } + + public boolean isDirectory() { + return super.isDirectory(); + } + + public boolean isFile() { + return super.isFile(); + } + + public void move(String destinationpath) throws ResourceException { + super.move(destinationpath); + } + + public InputStream readStream() throws ResourceException { + return super.readStream(); + } + + public void removeProperty(String name) { + super.removeProperty(name); + } + + public void setProperty(String name, Object newValue) { + super.setProperty(name, newValue); + } + + public boolean tryReadLock() { + try { + return getLm().tryLock(getName(), getPath(), false); + } catch (ResourceException e) { + // FIXME: ouch! + throw new LockException(e); + } + } + + public boolean tryWriteLock() { + try { + return getLm().tryLock(getName(), getPath(), true); + } catch (ResourceException e) { + // FIXME: ouch! + throw new LockException(e); + } + } + + public void readLock() { + try { + getLm().lock(getName(), getPath(), false); + } catch (ResourceException e) { + // FIXME: ouch! + throw new LockException(e); + } + super.readLock(); + } + + public void writeLock() { + try { + getLm().lock(getName(), getPath(), true); + } catch (ResourceException e) { + // FIXME: ouch! + throw new LockException(e); + } + super.writeLock(); + } + + public OutputStream writeStream(boolean append) throws ResourceException { + return super.writeStream(append); + } - public boolean removeDir(String id) throws IOException, LockException { - // TODO Auto-generated method stub - return false; } + } - protected void registerStream(Closeable stream) { - openStreams.add(stream); + @Override + public boolean commitCanFail() { + return false; + } + + public StreamableResource getResource(String path) throws ResourceException { + FileTxContext context = getActiveTx(); + if (context != null) { + return context.getResource(path); + } else { + return wrapped.getResource(path); } + } + + public String getRootPath() { + return rootPath; + } + + public FileResourceUndoManager getUndoManager() { + return undoManager; + } + + public void setUndoManager(FileResourceUndoManager undoManager) { + this.undoManager = undoManager; } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]