]> source.dussan.org Git - archiva.git/commitdiff
Moving maven-transaction to archiva-transaction
authorJoakim Erdfelt <joakime@apache.org>
Tue, 29 May 2007 14:09:25 +0000 (14:09 +0000)
committerJoakim Erdfelt <joakime@apache.org>
Tue, 29 May 2007 14:09:25 +0000 (14:09 +0000)
git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/trunk@542526 13f79535-47bb-0310-9956-ffa450edef68

archiva-base/maven-transaction/pom.xml [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/AbstractTransactionEvent.java [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CopyFileEvent.java [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CreateFileEvent.java [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/FileTransaction.java [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionEvent.java [new file with mode: 0644]
archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionException.java [new file with mode: 0644]
archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/AbstractFileEventTest.java [new file with mode: 0644]
archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CopyFileEventTest.java [new file with mode: 0644]
archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CreateFileEventTest.java [new file with mode: 0644]

diff --git a/archiva-base/maven-transaction/pom.xml b/archiva-base/maven-transaction/pom.xml
new file mode 100644 (file)
index 0000000..31cde74
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.maven.shared</groupId>
+    <artifactId>maven-shared-components</artifactId>
+    <version>6</version>
+  </parent>
+  <artifactId>maven-transaction</artifactId>
+  <version>1.0-alpha-2-SNAPSHOT</version>
+  <name>Maven Transactions</name>
+  <description>API for managing transaction.</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-digest</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-container-default</artifactId>
+      <version>1.0-alpha-9</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/AbstractTransactionEvent.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/AbstractTransactionEvent.java
new file mode 100644 (file)
index 0000000..e9d1409
--- /dev/null
@@ -0,0 +1,242 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.digest.Digester;
+import org.codehaus.plexus.digest.DigesterException;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class for the TransactionEvents
+ *
+ * @author Edwin Punzalan
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public abstract class AbstractTransactionEvent
+    extends AbstractLogEnabled
+    implements TransactionEvent
+{
+    private Map backups = new HashMap();;
+
+    private List createdDirs = new ArrayList();
+
+    private List createdFiles = new ArrayList();
+
+    /** {@link List}&lt;{@link Digester}> */
+    private List digesters;
+
+    protected AbstractTransactionEvent()
+    {
+        this( new ArrayList( 0 ) );
+    }
+
+    protected AbstractTransactionEvent( List digesters )
+    {
+        this.digesters = digesters;
+    }
+
+    protected List getDigesters()
+    {
+        return digesters;
+    }
+
+    /**
+     * Method that creates a directory as well as all the parent directories needed
+     *
+     * @param dir The File directory to be created
+     * @throws IOException when an unrecoverable error occurred
+     */
+    protected void mkDirs( File dir )
+        throws IOException
+    {
+        List createDirs = new ArrayList();
+
+        File parent = dir;
+        while ( !parent.exists() || !parent.isDirectory() )
+        {
+            createDirs.add( parent );
+
+            parent = parent.getParentFile();
+        }
+
+        while ( !createDirs.isEmpty() )
+        {
+            File directory = (File) createDirs.remove( createDirs.size() - 1 );
+
+            if ( directory.mkdir() )
+            {
+                createdDirs.add( directory );
+            }
+            else
+            {
+                throw new IOException( "Failed to create directory: " + directory.getAbsolutePath() );
+            }
+        }
+    }
+
+    protected void revertMkDirs()
+        throws IOException
+    {
+        if ( createdDirs != null )
+        {
+            Collections.reverse( createdDirs );
+
+            while ( !createdDirs.isEmpty() )
+            {
+                File dir = (File) createdDirs.remove( 0 );
+
+                if ( dir.isDirectory() && dir.list().length == 0 )
+                {
+                    FileUtils.deleteDirectory( dir );
+                }
+                else
+                {
+                    //cannot rollback created directory if it still contains files
+                    break;
+                }
+            }
+        }
+    }
+
+    protected void revertFilesCreated()
+        throws IOException
+    {
+        Iterator it = createdFiles.iterator();
+        while ( it.hasNext() )
+        {
+            File file = (File) it.next();
+            file.delete();
+            it.remove();
+        }
+    }
+
+    protected void createBackup( File file )
+        throws IOException
+    {
+        if ( file.exists() && file.isFile() )
+        {
+            File backup = File.createTempFile( "temp-", ".backup" );
+
+            FileUtils.copyFile( file, backup );
+
+            backup.deleteOnExit();
+
+            backups.put( file, backup );
+        }
+    }
+
+    protected void restoreBackups()
+        throws IOException
+    {
+        Iterator it = backups.entrySet().iterator();
+        while ( it.hasNext() )
+        {
+            Map.Entry entry = (Map.Entry) it.next();
+            FileUtils.copyFile( (File) entry.getValue(), (File) entry.getKey() );
+        }
+    }
+
+    protected void restoreBackup( File file )
+        throws IOException
+    {
+        File backup = (File) backups.get( file );
+        if ( backup != null )
+        {
+            FileUtils.copyFile( backup, file );
+        }
+    }
+
+    /**
+     * Create checksums of file using all digesters defined at construction time.
+     * 
+     * @param file
+     * @param force whether existing checksums should be overwritten or not
+     * @throws IOException
+     */
+    protected void createChecksums( File file, boolean force )
+        throws IOException
+    {
+        Iterator it = getDigesters().iterator();
+        while ( it.hasNext() )
+        {
+            Digester digester = (Digester) it.next();
+            File checksumFile = new File( file.getAbsolutePath() + "." + getDigesterFileExtension( digester ) );
+            if ( checksumFile.exists() )
+            {
+                if ( !force )
+                {
+                    continue;
+                }
+                createBackup( checksumFile );
+            }
+            else
+            {
+                createdFiles.add( checksumFile );
+            }
+
+            try
+            {
+                writeStringToFile( checksumFile, digester.calc( file ) );
+            }
+            catch ( DigesterException e )
+            {
+                throw (IOException) e.getCause();
+            }
+        }
+    }
+
+    protected void writeStringToFile( File file, String content )
+        throws IOException
+    {
+        FileOutputStream out = null;
+        try
+        {
+            out = new FileOutputStream( file );
+            IOUtil.copy( content, out );
+        }
+        finally
+        {
+            IOUtil.close( out );
+        }
+    }
+
+    /**
+     * File extension for checksums
+     * TODO should be moved to plexus-digester ?
+     */
+    protected String getDigesterFileExtension( Digester digester )
+    {
+        return digester.getAlgorithm().toLowerCase().replaceAll( "-", "" );
+    }
+
+}
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CopyFileEvent.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CopyFileEvent.java
new file mode 100644 (file)
index 0000000..c04b5e1
--- /dev/null
@@ -0,0 +1,119 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.digest.Digester;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Event to copy a file.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class CopyFileEvent
+    extends AbstractTransactionEvent
+{
+    private final File source;
+
+    private final File destination;
+
+    /**
+     * 
+     * @param source
+     * @param destination
+     * @param digesters {@link List}&lt;{@link Digester}> digesters to use for checksumming 
+     */
+    public CopyFileEvent( File source, File destination, List digesters )
+    {
+        super( digesters );
+        this.source = source;
+        this.destination = destination;
+    }
+
+    public void commit()
+        throws IOException
+    {
+        createBackup( destination );
+
+        mkDirs( destination.getParentFile() );
+
+        FileUtils.copyFile( source, destination );
+
+        createChecksums( destination, true );
+        copyChecksums();
+
+        copyChecksum( "asc" );
+    }
+
+    /**
+     * Copy checksums of source file with all digesters if exist
+     * 
+     * @throws IOException
+     */
+    private void copyChecksums()
+        throws IOException
+    {
+        Iterator it = getDigesters().iterator();
+        while ( it.hasNext() )
+        {
+            Digester digester = (Digester) it.next();
+            copyChecksum( getDigesterFileExtension( digester ) );
+        }
+    }
+
+    /**
+     * Copy checksum of source file with extension provided if exists
+     * 
+     * @param extension
+     * @return whether the checksum exists or not 
+     * @throws IOException
+     */
+    private boolean copyChecksum( String extension )
+        throws IOException
+    {
+        File checksumSource = new File( source.getAbsolutePath() + "." + extension );
+        if ( checksumSource.exists() )
+        {
+            File checksumDestination = new File( destination.getAbsolutePath() + "." + extension );
+            FileUtils.copyFile( checksumSource, checksumDestination );
+            return true;
+        }
+        return false;
+    }
+
+    public void rollback()
+        throws IOException
+    {
+        destination.delete();
+
+        revertFilesCreated();
+
+        revertMkDirs();
+
+        restoreBackups();
+    }
+}
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CreateFileEvent.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/CreateFileEvent.java
new file mode 100644 (file)
index 0000000..c28b4cf
--- /dev/null
@@ -0,0 +1,83 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.digest.Digester;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Event for creating a file from a string content.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class CreateFileEvent
+    extends AbstractTransactionEvent
+{
+    private final File destination;
+
+    private final String content;
+
+    /**
+     * 
+     * @param content
+     * @param destination
+     * @param digesters {@link List}&lt;{@link Digester}> digesters to use for checksumming 
+     */
+    public CreateFileEvent( String content, File destination, List digesters )
+    {
+        super( digesters );
+        this.content = content;
+        this.destination = destination;
+    }
+
+    public void commit()
+        throws IOException
+    {
+        createBackup( destination );
+
+        mkDirs( destination.getParentFile() );
+
+        if ( !destination.exists() && !destination.createNewFile() )
+        {
+            throw new IOException( "Unable to create new file" );
+        }
+
+        writeStringToFile( destination, content );
+
+        createChecksums( destination, true );
+    }
+
+    public void rollback()
+        throws IOException
+    {
+        destination.delete();
+
+        revertFilesCreated();
+
+        revertMkDirs();
+
+        restoreBackups();
+    }
+}
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/FileTransaction.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/FileTransaction.java
new file mode 100644 (file)
index 0000000..ffe7305
--- /dev/null
@@ -0,0 +1,102 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Implement commit/rollback semantics for a set of files.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+public class FileTransaction
+{
+    private List events = new ArrayList();
+
+    public void commit()
+        throws TransactionException
+    {
+        List toRollback = new ArrayList( events.size() );
+
+        for ( Iterator i = events.iterator(); i.hasNext(); )
+        {
+            TransactionEvent event = (TransactionEvent) i.next();
+
+            try
+            {
+                event.commit();
+
+                toRollback.add( event );
+            }
+            catch ( IOException e )
+            {
+                try
+                {
+                    rollback( toRollback );
+
+                    throw new TransactionException( "Unable to commit file transaction", e );
+                }
+                catch ( IOException ioe )
+                {
+                    throw new TransactionException(
+                        "Unable to commit file transaction, and rollback failed with error: '" + ioe.getMessage() + "'",
+                        e );
+                }
+            }
+        }
+    }
+
+    private void rollback( List toRollback )
+        throws IOException
+    {
+        for ( Iterator i = toRollback.iterator(); i.hasNext(); )
+        {
+            TransactionEvent event = (TransactionEvent) i.next();
+
+            event.rollback();
+        }
+    }
+
+    /**
+     * 
+     * @param source
+     * @param destination
+     * @param digesters {@link List}&lt;{@link Digester}> digesters to use for checksumming 
+     */
+    public void copyFile( File source, File destination, List digesters )
+    {
+        events.add( new CopyFileEvent( source, destination, digesters ) );
+    }
+
+    /**
+     * 
+     * @param content
+     * @param destination
+     * @param digesters {@link List}&lt;{@link Digester}> digesters to use for checksumming 
+     */
+    public void createFile( String content, File destination, List digesters )
+    {
+        events.add( new CreateFileEvent( content, destination, digesters ) );
+    }
+}
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionEvent.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionEvent.java
new file mode 100644 (file)
index 0000000..5be7f1e
--- /dev/null
@@ -0,0 +1,46 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Interface for individual events in a transaction.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+public interface TransactionEvent
+{
+    /**
+     * Commit this event.
+     *
+     * @throws IOException if an error occurred committing the change
+     */
+    void commit()
+        throws IOException;
+
+    /**
+     * Rollback the even already committed.
+     *
+     * @throws IOException if an error occurred reverting the change
+     */
+    void rollback()
+        throws IOException;
+}
diff --git a/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionException.java b/archiva-base/maven-transaction/src/main/java/org/apache/maven/transaction/TransactionException.java
new file mode 100644 (file)
index 0000000..381a6ff
--- /dev/null
@@ -0,0 +1,51 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+/**
+ * TransactionException 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class TransactionException
+    extends Exception
+{
+
+    public TransactionException()
+    {
+    }
+
+    public TransactionException( String message )
+    {
+        super( message );
+    }
+
+    public TransactionException( Throwable cause )
+    {
+        super( cause );
+    }
+
+    public TransactionException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}
diff --git a/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/AbstractFileEventTest.java b/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/AbstractFileEventTest.java
new file mode 100644 (file)
index 0000000..4794718
--- /dev/null
@@ -0,0 +1,110 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.digest.Digester;
+import org.codehaus.plexus.util.IOUtil;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public abstract class AbstractFileEventTest
+    extends PlexusTestCase
+{
+    protected List digesters;
+
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        digesters = getContainer().lookupList( Digester.class.getName() );
+    }
+
+    protected void assertChecksumExists( File file, String algorithm )
+    {
+        assertChecksum( file, algorithm, true );
+    }
+
+    protected void assertChecksumDoesNotExist( File file, String algorithm )
+    {
+        assertChecksum( file, algorithm, false );
+    }
+
+    private void assertChecksum( File file, String algorithm, boolean exist )
+    {
+        String msg = exist ? "exists" : "does not exist";
+        File checksumFile = new File( file.getPath() + "." + algorithm );
+        assertEquals( "Test file " + algorithm + " checksum " + msg, exist, checksumFile.exists() );
+    }
+
+    protected void assertChecksumCommit( File file )
+        throws IOException
+    {
+        assertChecksumExists( file, "md5" );
+        assertChecksumExists( file, "sha1" );
+    }
+
+    protected void assertChecksumRollback( File file )
+        throws IOException
+    {
+        assertChecksumDoesNotExist( file, "md5" );
+        assertChecksumDoesNotExist( file, "sha1" );
+    }
+
+    protected String readFile( File file )
+        throws IOException
+    {
+        FileInputStream in = null;
+        try
+        {
+            in = new FileInputStream( file );
+            return IOUtil.toString( in );
+        }
+        finally
+        {
+            IOUtil.close( in );
+        }
+    }
+
+    protected void writeFile( File file, String content )
+        throws IOException
+    {
+        FileOutputStream out = null;
+        try
+        {
+            out = new FileOutputStream( file );
+            IOUtil.copy( content, out );
+        }
+        finally
+        {
+            IOUtil.close( out );
+        }
+    }
+}
\ No newline at end of file
diff --git a/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CopyFileEventTest.java b/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CopyFileEventTest.java
new file mode 100644 (file)
index 0000000..1bfc37a
--- /dev/null
@@ -0,0 +1,180 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Edwin Punzalan
+ */
+public class CopyFileEventTest
+    extends AbstractFileEventTest
+{
+    private File testDir = new File( PlexusTestCase.getBasedir(), "target/transaction-tests/copy-file" );
+
+    private File testDest = new File( testDir, "test-file.txt" );
+
+    private File testSource = new File( PlexusTestCase.getBasedir(), "target/transaction-tests/test-file.txt" );
+
+    private File testDestChecksum;
+
+    private String source, oldChecksum;
+
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        testSource.getParentFile().mkdirs();
+
+        testSource.createNewFile();
+
+        writeFile( testSource, "source contents" );
+
+        testDestChecksum = new File( testDest.getPath() + ".sha1" );
+
+        testDestChecksum.getParentFile().mkdirs();
+
+        testDestChecksum.createNewFile();
+
+        writeFile( testDestChecksum, "this is the checksum" );
+
+        assertTrue( "Test if the source exists", testSource.exists() );
+
+        assertTrue( "Test if the destination checksum exists", testDestChecksum.exists() );
+
+        source = readFile( testSource );
+
+        oldChecksum = readFile( testDestChecksum );
+    }
+
+    public void testCopyCommitRollback()
+        throws Exception
+    {
+        CopyFileEvent event = new CopyFileEvent( testSource, testDest, digesters );
+
+        assertFalse( "Test that the destination is not yet created", testDest.exists() );
+
+        event.commit();
+
+        assertTrue( "Test that the destination is created", testDest.exists() );
+
+        assertChecksumCommit( testDest );
+
+        String target = readFile( testDest );
+
+        assertTrue( "Test that the destination contents are copied correctly", source.equals( target ) );
+
+        event.rollback();
+
+        assertFalse( "Test that the destination file has been deleted", testDest.exists() );
+
+        assertChecksumRollback( testDest );
+    }
+
+    public void testCopyCommitRollbackWithBackup()
+        throws Exception
+    {
+        testDest.getParentFile().mkdirs();
+
+        testDest.createNewFile();
+
+        writeFile( testDest, "overwritten contents" );
+
+        assertTrue( "Test that the destination exists", testDest.exists() );
+
+        CopyFileEvent event = new CopyFileEvent( testSource, testDest, digesters );
+
+        String target = readFile( testDest );
+
+        assertTrue( "Test that the destination contents have not changed", target.equals( "overwritten contents" ) );
+
+        event.commit();
+
+        target = readFile( testDest );
+
+        assertTrue( "Test that the destination contents are copied correctly", source.equals( target ) );
+
+        assertChecksumCommit( testDest );
+
+        event.rollback();
+
+        target = readFile( testDest );
+
+        assertTrue( "Test the destination file contents have been restored", target.equals( "overwritten contents" ) );
+
+        assertChecksumRollback( testDest );
+    }
+
+    public void testCreateRollbackCommit()
+        throws Exception
+    {
+        CopyFileEvent event = new CopyFileEvent( testSource, testDest, digesters );
+
+        assertFalse( "Test that the destination is not yet created", testDest.exists() );
+
+        event.rollback();
+
+        assertFalse( "Test that the destination file is not yet created", testDest.exists() );
+
+        event.commit();
+
+        assertTrue( "Test that the destination is created", testDest.exists() );
+
+        assertChecksumCommit( testDest );
+
+        String target = readFile( testDest );
+
+        assertTrue( "Test that the destination contents are copied correctly", source.equals( target ) );
+    }
+
+    protected void tearDown()
+        throws Exception
+    {
+        super.tearDown();
+
+        FileUtils.deleteDirectory( new File( PlexusTestCase.getBasedir(), "target/transaction-tests" ) );
+    }
+
+    protected void assertChecksumCommit( File file )
+        throws IOException
+    {
+        super.assertChecksumCommit( file );
+
+        String target = readFile( testDestChecksum );
+
+        assertFalse( "Test that the destination checksum contents are created correctly", oldChecksum.equals( target ) );
+    }
+
+    protected void assertChecksumRollback( File file )
+        throws IOException
+    {
+        assertChecksumDoesNotExist( file, "md5" );
+        assertChecksumExists( file, "sha1" );
+
+        String target = readFile( testDestChecksum );
+
+        assertEquals( "Test that the destination checksum contents are reverted correctly", oldChecksum, target );
+    }
+}
diff --git a/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CreateFileEventTest.java b/archiva-base/maven-transaction/src/test/java/org/apache/maven/transaction/CreateFileEventTest.java
new file mode 100644 (file)
index 0000000..22a2006
--- /dev/null
@@ -0,0 +1,122 @@
+package org.apache.maven.transaction;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.maven.transaction.CreateFileEvent;
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * @author Edwin Punzalan
+ */
+public class CreateFileEventTest
+    extends AbstractFileEventTest
+{
+    private File testDir = new File( PlexusTestCase.getBasedir(), "target/transaction-tests/create-file" );
+
+    public void testCreateCommitRollback()
+        throws Exception
+    {
+        File testFile = new File( testDir, "test-file.txt" );
+
+        CreateFileEvent event = new CreateFileEvent( "file contents", testFile, digesters );
+
+        assertFalse( "Test file is not yet created", testFile.exists() );
+
+        event.commit();
+
+        assertTrue( "Test file has been created", testFile.exists() );
+
+        assertChecksumCommit( testFile );
+
+        event.rollback();
+
+        assertFalse( "Test file is has been deleted after rollback", testFile.exists() );
+
+        assertChecksumRollback( testFile );
+
+        assertFalse( "Test file parent directories has been rolledback too", testDir.exists() );
+        assertTrue( "target directory still exists", new File( PlexusTestCase.getBasedir(), "target" ).exists() );
+    }
+
+    public void testCreateCommitRollbackWithBackup()
+        throws Exception
+    {
+        File testFile = new File( testDir, "test-file.txt" );
+
+        testFile.getParentFile().mkdirs();
+
+        testFile.createNewFile();
+
+        writeFile( testFile, "original contents" );
+
+        CreateFileEvent event = new CreateFileEvent( "modified contents", testFile, digesters );
+
+        String contents = readFile( testFile );
+
+        assertEquals( "Test contents have not changed", "original contents", contents );
+
+        event.commit();
+
+        contents = readFile( testFile );
+
+        assertEquals( "Test contents have not changed", "modified contents", contents );
+
+        assertChecksumCommit( testFile );
+
+        event.rollback();
+
+        contents = readFile( testFile );
+
+        assertEquals( "Test contents have not changed", "original contents", contents );
+
+        assertChecksumRollback( testFile );
+    }
+
+    public void testCreateRollbackCommit()
+        throws Exception
+    {
+        File testFile = new File( testDir, "test-file.txt" );
+
+        CreateFileEvent event = new CreateFileEvent( "file contents", testFile, digesters );
+
+        assertFalse( "Test file is not yet created", testFile.exists() );
+
+        event.rollback();
+
+        assertFalse( "Test file is not yet created", testFile.exists() );
+
+        event.commit();
+
+        assertTrue( "Test file is not yet created", testFile.exists() );
+
+        assertChecksumCommit( testFile );
+    }
+
+    protected void tearDown()
+        throws Exception
+    {
+        super.tearDown();
+
+        FileUtils.deleteDirectory( new File( PlexusTestCase.getBasedir(), "target/transaction-tests" ) );
+    }
+}