View Javadoc
1   package org.eclipse.aether.internal.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.BufferedInputStream;
26  import java.io.BufferedOutputStream;
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.io.UncheckedIOException;
32  import java.nio.ByteBuffer;
33  import java.nio.charset.StandardCharsets;
34  import java.nio.file.Files;
35  import java.nio.file.StandardCopyOption;
36  
37  import org.eclipse.aether.spi.io.FileProcessor;
38  import org.eclipse.aether.util.ChecksumUtils;
39  import org.eclipse.aether.util.FileUtils;
40  
41  /**
42   * A utility class helping with file-based operations.
43   */
44  @Singleton
45  @Named
46  public class DefaultFileProcessor
47          implements FileProcessor
48  {
49  
50      /**
51       * Thread-safe variant of {@link File#mkdirs()}. Creates the directory named by the given abstract pathname,
52       * including any necessary but nonexistent parent directories. Note that if this operation fails it may have
53       * succeeded in creating some of the necessary parent directories.
54       *
55       * @param directory The directory to create, may be {@code null}.
56       * @return {@code true} if and only if the directory was created, along with all necessary parent directories;
57       * {@code false} otherwise
58       */
59      public boolean mkdirs( File directory )
60      {
61          if ( directory == null )
62          {
63              return false;
64          }
65  
66          if ( directory.exists() )
67          {
68              return false;
69          }
70          if ( directory.mkdir() )
71          {
72              return true;
73          }
74  
75          File canonDir;
76          try
77          {
78              canonDir = directory.getCanonicalFile();
79          }
80          catch ( IOException e )
81          {
82              throw new UncheckedIOException( e );
83          }
84  
85          File parentDir = canonDir.getParentFile();
86          return ( parentDir != null && ( mkdirs( parentDir ) || parentDir.exists() ) && canonDir.mkdir() );
87      }
88  
89      public void write( File target, String data )
90              throws IOException
91      {
92          FileUtils.writeFile( target.toPath(), p -> Files.write( p, data.getBytes( StandardCharsets.UTF_8 ) ) );
93      }
94  
95      public void write( File target, InputStream source )
96              throws IOException
97      {
98          FileUtils.writeFile( target.toPath(), p -> Files.copy( source, p, StandardCopyOption.REPLACE_EXISTING ) );
99      }
100 
101     public void copy( File source, File target )
102             throws IOException
103     {
104         copy( source, target, null );
105     }
106 
107     public long copy( File source, File target, ProgressListener listener )
108             throws IOException
109     {
110         try ( InputStream in = new BufferedInputStream( Files.newInputStream( source.toPath() ) );
111               FileUtils.CollocatedTempFile tempTarget = FileUtils.newTempFile( target.toPath() );
112               OutputStream out = new BufferedOutputStream( Files.newOutputStream( tempTarget.getPath() ) ) )
113         {
114             long result = copy( out, in, listener );
115             tempTarget.move();
116             return result;
117         }
118     }
119 
120     private long copy( OutputStream os, InputStream is, ProgressListener listener )
121             throws IOException
122     {
123         long total = 0L;
124         byte[] buffer = new byte[1024 * 32];
125         while ( true )
126         {
127             int bytes = is.read( buffer );
128             if ( bytes < 0 )
129             {
130                 break;
131             }
132 
133             os.write( buffer, 0, bytes );
134 
135             total += bytes;
136 
137             if ( listener != null && bytes > 0 )
138             {
139                 try
140                 {
141                     listener.progressed( ByteBuffer.wrap( buffer, 0, bytes ) );
142                 }
143                 catch ( Exception e )
144                 {
145                     // too bad
146                 }
147             }
148         }
149 
150         return total;
151     }
152 
153     public void move( File source, File target )
154             throws IOException
155     {
156         if ( !source.renameTo( target ) )
157         {
158             copy( source, target );
159 
160             target.setLastModified( source.lastModified() );
161 
162             source.delete();
163         }
164     }
165 
166     @Override
167     public String readChecksum( final File checksumFile ) throws IOException
168     {
169         // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
170         return ChecksumUtils.read( checksumFile );
171     }
172 
173     @Override
174     public void writeChecksum( final File checksumFile, final String checksum ) throws IOException
175     {
176         // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
177         write( checksumFile, checksum );
178     }
179 }