001package org.eclipse.aether.internal.test.util;
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 java.io.BufferedOutputStream;
023import java.io.File;
024import java.io.FileInputStream;
025import java.io.FileOutputStream;
026import java.io.IOException;
027import java.io.OutputStream;
028import java.io.RandomAccessFile;
029import java.nio.charset.StandardCharsets;
030import java.util.ArrayList;
031import java.util.Collection;
032import java.util.Properties;
033import java.util.UUID;
034
035/**
036 * Provides utility methods to read and write (temporary) files.
037 */
038public class TestFileUtils
039{
040
041    private static final File TMP = new File( System.getProperty( "java.io.tmpdir" ), "aether-"
042        + UUID.randomUUID().toString().substring( 0, 8 ) );
043
044    static
045    {
046        Runtime.getRuntime().addShutdownHook( new Thread( () ->
047        {
048            try
049            {
050                deleteFile( TMP );
051            }
052            catch ( IOException e )
053            {
054                e.printStackTrace();
055            }
056        } ) );
057    }
058
059    private TestFileUtils()
060    {
061        // hide constructor
062    }
063
064    public static void deleteTempFiles()
065        throws IOException
066    {
067        deleteFile( TMP );
068    }
069
070    public static void deleteFile( File file )
071        throws IOException
072    {
073        if ( file == null )
074        {
075            return;
076        }
077
078        Collection<File> undeletables = new ArrayList<>();
079
080        delete( file, undeletables );
081
082        if ( !undeletables.isEmpty() )
083        {
084            throw new IOException( "Failed to delete " + undeletables );
085        }
086    }
087
088    private static void delete( File file, Collection<File> undeletables )
089    {
090        String[] children = file.list();
091        if ( children != null )
092        {
093            for ( String child : children )
094            {
095                delete( new File( file, child ), undeletables );
096            }
097        }
098
099        if ( !del( file ) )
100        {
101            undeletables.add( file.getAbsoluteFile() );
102        }
103    }
104
105    private static boolean del( File file )
106    {
107        for ( int i = 0; i < 10; i++ )
108        {
109            if ( file.delete() || !file.exists() )
110            {
111                return true;
112            }
113        }
114        return false;
115    }
116
117    public static boolean mkdirs( File directory )
118    {
119        if ( directory == null )
120        {
121            return false;
122        }
123
124        if ( directory.exists() )
125        {
126            return false;
127        }
128        if ( directory.mkdir() )
129        {
130            return true;
131        }
132
133        File canonDir = null;
134        try
135        {
136            canonDir = directory.getCanonicalFile();
137        }
138        catch ( IOException e )
139        {
140            return false;
141        }
142
143        File parentDir = canonDir.getParentFile();
144        return ( parentDir != null && ( mkdirs( parentDir ) || parentDir.exists() ) && canonDir.mkdir() );
145    }
146
147    public static File createTempFile( String contents )
148        throws IOException
149    {
150        return createTempFile( contents.getBytes( StandardCharsets.UTF_8 ), 1 );
151    }
152
153    public static File createTempFile( byte[] pattern, int repeat )
154        throws IOException
155    {
156        mkdirs( TMP );
157        File tmpFile = File.createTempFile( "tmpfile-", ".data", TMP );
158        writeBytes( tmpFile, pattern, repeat );
159        return tmpFile;
160    }
161
162    public static File createTempDir()
163        throws IOException
164    {
165        return createTempDir( "" );
166    }
167
168    public static File createTempDir( String suffix )
169        throws IOException
170    {
171        mkdirs( TMP );
172        File tmpFile = File.createTempFile( "tmpdir-", suffix, TMP );
173        deleteFile( tmpFile );
174        mkdirs( tmpFile );
175        return tmpFile;
176    }
177
178    public static long copyFile( File source, File target )
179        throws IOException
180    {
181        long total = 0;
182
183        FileInputStream fis = null;
184        OutputStream fos = null;
185        try
186        {
187            fis = new FileInputStream( source );
188
189            mkdirs( target.getParentFile() );
190
191            fos = new BufferedOutputStream( new FileOutputStream( target ) );
192
193            for ( byte[] buffer = new byte[ 1024 * 32 ];; )
194            {
195                int bytes = fis.read( buffer );
196                if ( bytes < 0 )
197                {
198                    break;
199                }
200
201                fos.write( buffer, 0, bytes );
202
203                total += bytes;
204            }
205
206            fos.close();
207            fos = null;
208
209            fis.close();
210            fis = null;
211        }
212        finally
213        {
214            try
215            {
216                if ( fos != null )
217                {
218                    fos.close();
219                }
220            }
221            catch ( final IOException e )
222            {
223                // Suppressed due to an exception already thrown in the try block.
224            }
225            finally
226            {
227                try
228                {
229                    if ( fis != null )
230                    {
231                        fis.close();
232                    }
233                }
234                catch ( final IOException e )
235                {
236                    // Suppressed due to an exception already thrown in the try block.
237                }
238            }
239        }
240
241        return total;
242    }
243
244    public static byte[] readBytes( File file )
245        throws IOException
246    {
247        RandomAccessFile in = null;
248        try
249        {
250            in = new RandomAccessFile( file, "r" );
251            byte[] actual = new byte[ (int) in.length() ];
252            in.readFully( actual );
253            in.close();
254            in = null;
255            return actual;
256        }
257        finally
258        {
259            try
260            {
261                if ( in != null )
262                {
263                    in.close();
264                }
265            }
266            catch ( final IOException e )
267            {
268                // Suppressed due to an exception already thrown in the try block.
269            }
270        }
271    }
272
273    public static void writeBytes( File file, byte[] pattern, int repeat )
274        throws IOException
275    {
276        file.deleteOnExit();
277        file.getParentFile().mkdirs();
278        OutputStream out = null;
279        try
280        {
281            out = new BufferedOutputStream( new FileOutputStream( file ) );
282            for ( int i = 0; i < repeat; i++ )
283            {
284                out.write( pattern );
285            }
286            out.close();
287            out = null;
288        }
289        finally
290        {
291            try
292            {
293                if ( out != null )
294                {
295                    out.close();
296                }
297            }
298            catch ( final IOException e )
299            {
300                // Suppressed due to an exception already thrown in the try block.
301            }
302        }
303    }
304
305    public static String readString( File file )
306        throws IOException
307    {
308        byte[] content = readBytes( file );
309        return new String( content, StandardCharsets.UTF_8 );
310    }
311
312    public static void writeString( File file, String content )
313        throws IOException
314    {
315        writeBytes( file, content.getBytes( StandardCharsets.UTF_8 ), 1 );
316    }
317
318    public static void readProps( File file, Properties props )
319        throws IOException
320    {
321        FileInputStream fis = null;
322        try
323        {
324            fis = new FileInputStream( file );
325            props.load( fis );
326            fis.close();
327            fis = null;
328        }
329        finally
330        {
331            try
332            {
333                if ( fis != null )
334                {
335                    fis.close();
336                }
337            }
338            catch ( final IOException e )
339            {
340                // Suppressed due to an exception already thrown in the try block.
341            }
342        }
343    }
344
345    public static void writeProps( File file, Properties props )
346        throws IOException
347    {
348        file.getParentFile().mkdirs();
349
350        FileOutputStream fos = null;
351        try
352        {
353            fos = new FileOutputStream( file );
354            props.store( fos, "aether-test" );
355            fos.close();
356            fos = null;
357        }
358        finally
359        {
360            try
361            {
362                if ( fos != null )
363                {
364                    fos.close();
365                }
366            }
367            catch ( final IOException e )
368            {
369                // Suppressed due to an exception already thrown in the try block.
370            }
371        }
372    }
373
374}