001package org.eclipse.aether.internal.impl; 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.File; 023import java.io.FileInputStream; 024import java.io.FileOutputStream; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.OutputStream; 028import java.nio.Buffer; 029import java.nio.ByteBuffer; 030import java.nio.charset.StandardCharsets; 031 032import javax.inject.Named; 033import javax.inject.Singleton; 034 035import org.eclipse.aether.spi.io.FileProcessor; 036 037/** 038 * A utility class helping with file-based operations. 039 */ 040@Singleton 041@Named 042public class DefaultFileProcessor 043 implements FileProcessor 044{ 045 046 /** 047 * Thread-safe variant of {@link File#mkdirs()}. Creates the directory named by the given abstract pathname, 048 * including any necessary but nonexistent parent directories. Note that if this operation fails it may have 049 * succeeded in creating some of the necessary parent directories. 050 * 051 * @param directory The directory to create, may be {@code null}. 052 * @return {@code true} if and only if the directory was created, along with all necessary parent directories; 053 * {@code false} otherwise 054 */ 055 public boolean mkdirs( File directory ) 056 { 057 if ( directory == null ) 058 { 059 return false; 060 } 061 062 if ( directory.exists() ) 063 { 064 return false; 065 } 066 if ( directory.mkdir() ) 067 { 068 return true; 069 } 070 071 File canonDir; 072 try 073 { 074 canonDir = directory.getCanonicalFile(); 075 } 076 catch ( IOException e ) 077 { 078 return false; 079 } 080 081 File parentDir = canonDir.getParentFile(); 082 return ( parentDir != null && ( mkdirs( parentDir ) || parentDir.exists() ) && canonDir.mkdir() ); 083 } 084 085 public void write( File target, String data ) 086 throws IOException 087 { 088 mkdirs( target.getAbsoluteFile().getParentFile() ); 089 090 OutputStream out = null; 091 try 092 { 093 out = new FileOutputStream( target ); 094 095 if ( data != null ) 096 { 097 out.write( data.getBytes( StandardCharsets.UTF_8 ) ); 098 } 099 100 out.close(); 101 out = null; 102 } 103 finally 104 { 105 try 106 { 107 if ( out != null ) 108 { 109 out.close(); 110 } 111 } 112 catch ( final IOException e ) 113 { 114 // Suppressed due to an exception already thrown in the try block. 115 } 116 } 117 } 118 119 public void write( File target, InputStream source ) 120 throws IOException 121 { 122 mkdirs( target.getAbsoluteFile().getParentFile() ); 123 124 OutputStream out = null; 125 try 126 { 127 out = new FileOutputStream( target ); 128 129 copy( out, source, null ); 130 131 out.close(); 132 out = null; 133 } 134 finally 135 { 136 try 137 { 138 if ( out != null ) 139 { 140 out.close(); 141 } 142 } 143 catch ( final IOException e ) 144 { 145 // Suppressed due to an exception already thrown in the try block. 146 } 147 } 148 } 149 150 public void copy( File source, File target ) 151 throws IOException 152 { 153 copy( source, target, null ); 154 } 155 156 public long copy( File source, File target, ProgressListener listener ) 157 throws IOException 158 { 159 long total = 0L; 160 161 InputStream in = null; 162 OutputStream out = null; 163 try 164 { 165 in = new FileInputStream( source ); 166 167 mkdirs( target.getAbsoluteFile().getParentFile() ); 168 169 out = new FileOutputStream( target ); 170 171 total = copy( out, in, listener ); 172 173 out.close(); 174 out = null; 175 176 in.close(); 177 in = null; 178 } 179 finally 180 { 181 try 182 { 183 if ( out != null ) 184 { 185 out.close(); 186 } 187 } 188 catch ( final IOException e ) 189 { 190 // Suppressed due to an exception already thrown in the try block. 191 } 192 finally 193 { 194 try 195 { 196 if ( in != null ) 197 { 198 in.close(); 199 } 200 } 201 catch ( final IOException e ) 202 { 203 // Suppressed due to an exception already thrown in the try block. 204 } 205 } 206 } 207 208 return total; 209 } 210 211 private long copy( OutputStream os, InputStream is, ProgressListener listener ) 212 throws IOException 213 { 214 long total = 0L; 215 216 ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 ); 217 byte[] array = buffer.array(); 218 219 while ( true ) 220 { 221 int bytes = is.read( array ); 222 if ( bytes < 0 ) 223 { 224 break; 225 } 226 227 os.write( array, 0, bytes ); 228 229 total += bytes; 230 231 if ( listener != null && bytes > 0 ) 232 { 233 try 234 { 235 ( (Buffer) buffer ).rewind(); 236 ( (Buffer) buffer ).limit( bytes ); 237 listener.progressed( buffer ); 238 } 239 catch ( Exception e ) 240 { 241 // too bad 242 } 243 } 244 } 245 246 return total; 247 } 248 249 public void move( File source, File target ) 250 throws IOException 251 { 252 if ( !source.renameTo( target ) ) 253 { 254 copy( source, target ); 255 256 target.setLastModified( source.lastModified() ); 257 258 source.delete(); 259 } 260 } 261 262}