This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.transaction;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.commons.io.FileUtils;
023import org.codehaus.plexus.digest.Digester;
024import org.codehaus.plexus.digest.DigesterException;
025
026import java.io.File;
027import java.io.IOException;
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.HashMap;
031import java.util.Iterator;
032import java.util.List;
033import java.util.Map;
034
035/**
036 * Abstract class for the TransactionEvents
037 *
038 *
039 */
040public abstract class AbstractTransactionEvent
041    implements TransactionEvent
042{
043    private Map<File, File> backups = new HashMap<>();
044
045    private List<File> createdDirs = new ArrayList<>();
046
047    private List<File> createdFiles = new ArrayList<>();
048
049    /**
050     * {@link List}&lt;{@link Digester}&gt;
051     */
052    private List<? extends Digester> digesters;
053
054    protected AbstractTransactionEvent()
055    {
056        this( new ArrayList<Digester>( 0 ) );
057    }
058
059    protected AbstractTransactionEvent( List<? extends Digester> digesters )
060    {
061        this.digesters = digesters;
062    }
063
064    protected List<? extends Digester> getDigesters()
065    {
066        return digesters;
067    }
068
069    /**
070     * Method that creates a directory as well as all the parent directories needed
071     *
072     * @param dir The File directory to be created
073     * @throws IOException when an unrecoverable error occurred
074     */
075    protected void mkDirs( File dir )
076        throws IOException
077    {
078        List<File> createDirs = new ArrayList<>();
079
080        File parent = dir;
081        while ( !parent.exists() || !parent.isDirectory() )
082        {
083            createDirs.add( parent );
084
085            parent = parent.getParentFile();
086        }
087
088        while ( !createDirs.isEmpty() )
089        {
090            File directory = createDirs.remove( createDirs.size() - 1 );
091
092            if ( directory.mkdir() )
093            {
094                createdDirs.add( directory );
095            }
096            else
097            {
098                throw new IOException( "Failed to create directory: " + directory.getAbsolutePath() );
099            }
100        }
101    }
102
103    protected void revertMkDirs()
104        throws IOException
105    {
106        if ( createdDirs != null )
107        {
108            Collections.reverse( createdDirs );
109
110            while ( !createdDirs.isEmpty() )
111            {
112                File dir = (File) createdDirs.remove( 0 );
113
114                if ( dir.isDirectory() && dir.list().length == 0 )
115                {
116                    FileUtils.deleteDirectory( dir );
117                }
118                else
119                {
120                    //cannot rollback created directory if it still contains files
121                    break;
122                }
123            }
124        }
125    }
126
127    protected void revertFilesCreated()
128        throws IOException
129    {
130        Iterator<File> it = createdFiles.iterator();
131        while ( it.hasNext() )
132        {
133            File file = (File) it.next();
134            file.delete();
135            it.remove();
136        }
137    }
138
139    protected void createBackup( File file )
140        throws IOException
141    {
142        if ( file.exists() && file.isFile() )
143        {
144            File backup = File.createTempFile( "temp-", ".backup" );
145
146            FileUtils.copyFile( file, backup );
147
148            backup.deleteOnExit();
149
150            backups.put( file, backup );
151        }
152    }
153
154    protected void restoreBackups()
155        throws IOException
156    {
157        for ( Map.Entry<File, File> entry : backups.entrySet() )
158        {
159            FileUtils.copyFile( entry.getValue(), entry.getKey() );
160        }
161    }
162
163    protected void restoreBackup( File file )
164        throws IOException
165    {
166        File backup = (File) backups.get( file );
167        if ( backup != null )
168        {
169            FileUtils.copyFile( backup, file );
170        }
171    }
172
173    /**
174     * Create checksums of file using all digesters defined at construction time.
175     *
176     * @param file
177     * @param force whether existing checksums should be overwritten or not
178     * @throws IOException
179     */
180    protected void createChecksums( File file, boolean force )
181        throws IOException
182    {
183        for ( Digester digester : getDigesters() )
184        {
185            File checksumFile = new File( file.getAbsolutePath() + "." + getDigesterFileExtension( digester ) );
186            if ( checksumFile.exists() )
187            {
188                if ( !force )
189                {
190                    continue;
191                }
192                createBackup( checksumFile );
193            }
194            else
195            {
196                createdFiles.add( checksumFile );
197            }
198
199            try
200            {
201                writeStringToFile( checksumFile, digester.calc( file ) );
202            }
203            catch ( DigesterException e )
204            {
205                throw (IOException) e.getCause();
206            }
207        }
208    }
209
210    /**
211     * TODO: Remove in favor of using FileUtils directly.
212     */
213    protected void writeStringToFile( File file, String content )
214        throws IOException
215    {
216        FileUtils.writeStringToFile( file, content );
217    }
218
219    /**
220     * File extension for checksums
221     * TODO should be moved to plexus-digester ?
222     */
223    protected String getDigesterFileExtension( Digester digester )
224    {
225        return digester.getAlgorithm().toLowerCase().replaceAll( "-", "" );
226    }
227
228}