--- /dev/null
+<?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>
--- /dev/null
+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}<{@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( "-", "" );
+ }
+
+}
--- /dev/null
+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}<{@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();
+ }
+}
--- /dev/null
+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}<{@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();
+ }
+}
--- /dev/null
+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}<{@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}<{@link Digester}> digesters to use for checksumming
+ */
+ public void createFile( String content, File destination, List digesters )
+ {
+ events.add( new CreateFileEvent( content, destination, digesters ) );
+ }
+}
--- /dev/null
+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;
+}
--- /dev/null
+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 );
+ }
+
+}
--- /dev/null
+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
--- /dev/null
+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 );
+ }
+}
--- /dev/null
+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" ) );
+ }
+}