001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Named; 022import javax.inject.Singleton; 023 024import java.io.BufferedInputStream; 025import java.io.BufferedOutputStream; 026import java.io.BufferedReader; 027import java.io.File; 028import java.io.IOException; 029import java.io.InputStream; 030import java.io.InputStreamReader; 031import java.io.OutputStream; 032import java.io.UncheckedIOException; 033import java.nio.ByteBuffer; 034import java.nio.charset.StandardCharsets; 035import java.nio.file.Files; 036import java.nio.file.StandardCopyOption; 037 038import org.eclipse.aether.spi.io.FileProcessor; 039import org.eclipse.aether.util.FileUtils; 040 041/** 042 * A utility class helping with file-based operations. 043 * 044 * @deprecated 045 */ 046@Deprecated 047@Singleton 048@Named 049public class DefaultFileProcessor implements FileProcessor { 050 051 /** 052 * Thread-safe variant of {@link File#mkdirs()}. Creates the directory named by the given abstract pathname, 053 * including any necessary but nonexistent parent directories. Note that if this operation fails it may have 054 * succeeded in creating some of the necessary parent directories. 055 * 056 * @param directory The directory to create, may be {@code null}. 057 * @return {@code true} if and only if the directory was created, along with all necessary parent directories; 058 * {@code false} otherwise 059 */ 060 @Override 061 public boolean mkdirs(File directory) { 062 if (directory == null) { 063 return false; 064 } 065 066 if (directory.exists()) { 067 return false; 068 } 069 if (directory.mkdir()) { 070 return true; 071 } 072 073 File canonDir; 074 try { 075 canonDir = directory.getCanonicalFile(); 076 } catch (IOException e) { 077 throw new UncheckedIOException(e); 078 } 079 080 File parentDir = canonDir.getParentFile(); 081 return (parentDir != null && (mkdirs(parentDir) || parentDir.exists()) && canonDir.mkdir()); 082 } 083 084 @Override 085 public void write(File target, String data) throws IOException { 086 FileUtils.writeFile(target.toPath(), p -> Files.write(p, data.getBytes(StandardCharsets.UTF_8))); 087 } 088 089 @Override 090 public void write(File target, InputStream source) throws IOException { 091 FileUtils.writeFile(target.toPath(), p -> Files.copy(source, p, StandardCopyOption.REPLACE_EXISTING)); 092 } 093 094 @Override 095 public void copy(File source, File target) throws IOException { 096 copy(source, target, null); 097 } 098 099 @Override 100 public long copy(File source, File target, ProgressListener listener) throws IOException { 101 try (InputStream in = new BufferedInputStream(Files.newInputStream(source.toPath())); 102 FileUtils.CollocatedTempFile tempTarget = FileUtils.newTempFile(target.toPath()); 103 OutputStream out = new BufferedOutputStream(Files.newOutputStream(tempTarget.getPath()))) { 104 long result = copy(out, in, listener); 105 tempTarget.move(); 106 return result; 107 } 108 } 109 110 private long copy(OutputStream os, InputStream is, ProgressListener listener) throws IOException { 111 long total = 0L; 112 byte[] buffer = new byte[1024 * 32]; 113 while (true) { 114 int bytes = is.read(buffer); 115 if (bytes < 0) { 116 break; 117 } 118 119 os.write(buffer, 0, bytes); 120 121 total += bytes; 122 123 if (listener != null && bytes > 0) { 124 try { 125 listener.progressed(ByteBuffer.wrap(buffer, 0, bytes)); 126 } catch (Exception e) { 127 // too bad 128 } 129 } 130 } 131 132 return total; 133 } 134 135 @Override 136 public void move(File source, File target) throws IOException { 137 if (!source.renameTo(target)) { 138 copy(source, target); 139 140 target.setLastModified(source.lastModified()); 141 142 source.delete(); 143 } 144 } 145 146 @Override 147 public String readChecksum(final File checksumFile) throws IOException { 148 // for now do exactly same as happened before, but FileProcessor is a component and can be replaced 149 String checksum = ""; 150 try (BufferedReader br = new BufferedReader( 151 new InputStreamReader(Files.newInputStream(checksumFile.toPath()), StandardCharsets.UTF_8), 512)) { 152 while (true) { 153 String line = br.readLine(); 154 if (line == null) { 155 break; 156 } 157 line = line.trim(); 158 if (!line.isEmpty()) { 159 checksum = line; 160 break; 161 } 162 } 163 } 164 165 if (checksum.matches(".+= [0-9A-Fa-f]+")) { 166 int lastSpacePos = checksum.lastIndexOf(' '); 167 checksum = checksum.substring(lastSpacePos + 1); 168 } else { 169 int spacePos = checksum.indexOf(' '); 170 171 if (spacePos != -1) { 172 checksum = checksum.substring(0, spacePos); 173 } 174 } 175 176 return checksum; 177 } 178 179 @Override 180 public void writeChecksum(final File checksumFile, final String checksum) throws IOException { 181 // for now do exactly same as happened before, but FileProcessor is a component and can be replaced 182 write(checksumFile, checksum); 183 } 184}