com.igormaznitsa.mvnjlink.jdkproviders.AbstractJdkProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mvn-jlink-wrapper Show documentation
Show all versions of mvn-jlink-wrapper Show documentation
Maven plugin to autoload JDK distributions and provide easy way to use their internal tools
/*
* Copyright 2019 Igor Maznitsa.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.igormaznitsa.mvnjlink.jdkproviders;
import com.igormaznitsa.meta.annotation.MustNotContainNull;
import com.igormaznitsa.meta.common.utils.Assertions;
import com.igormaznitsa.mvnjlink.exceptions.IORuntimeWrapperException;
import com.igormaznitsa.mvnjlink.mojos.AbstractJdkToolMojo;
import com.igormaznitsa.mvnjlink.utils.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.maven.plugin.logging.Log;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import static com.igormaznitsa.meta.common.utils.Assertions.assertNotNull;
import static com.igormaznitsa.mvnjlink.utils.HttpUtils.doGetRequest;
import static java.lang.String.format;
import java.nio.file.Files;
import static java.nio.file.Files.*;
import static java.util.stream.Stream.of;
import static org.apache.commons.codec.digest.DigestUtils.sha256Hex;
public abstract class AbstractJdkProvider {
protected final AbstractJdkToolMojo mojo;
public AbstractJdkProvider(@Nonnull final AbstractJdkToolMojo mojo) {
this.mojo = assertNotNull(mojo);
}
protected static void assertParameters(@Nonnull final Map attrMap, @Nonnull @MustNotContainNull final String... names) {
final Optional notFoundAttribute = of(names).filter(x -> !attrMap.containsKey(x)).findAny();
if (notFoundAttribute.isPresent()) {
throw new IllegalArgumentException(format("Parameter named '%s' must be presented", notFoundAttribute.get()));
}
}
@Nonnull
protected static String calcSha256ForFile(@Nonnull final Path file) throws IOException {
try (final InputStream in = newInputStream(file)) {
return sha256Hex(in);
}
}
@Nonnull
protected File lockCache(@Nonnull final Path cacheFolder, @Nonnull final String jdkId) throws IOException {
final Log log = this.mojo.getLog();
final File lockFile = cacheFolder.resolve(".#" + jdkId).toFile();
lockFile.deleteOnExit();
if (!lockFile.createNewFile()) {
boolean locked = false;
log.info("Detected existing lock, waiting for unlocking");
while (!Thread.currentThread().isInterrupted()) {
locked = lockFile.createNewFile();
if (locked) {
break;
} else {
try {
Thread.sleep(500L);
} catch (InterruptedException ex) {
log.warn("Process interrupted");
Thread.currentThread().interrupt();
}
}
}
if (!locked) {
throw new IOException("Can't lock folder");
}
}
return lockFile;
}
protected boolean isOfflineMode() {
return this.mojo.isOfflineModeActive();
}
@Nonnull
protected String findCurrentOs(@Nonnull final String macOsId) {
final String defaultOs;
if (SystemUtils.IS_OS_MAC) {
defaultOs = macOsId;
} else if (SystemUtils.IS_OS_WINDOWS) {
defaultOs = "windows";
} else if (SystemUtils.IS_OS_AIX) {
defaultOs = "aix";
} else if (SystemUtils.IS_OS_FREE_BSD) {
defaultOs = "freebsd";
} else if (SystemUtils.IS_OS_IRIX) {
defaultOs = "irix";
} else if (SystemUtils.IS_OS_ZOS) {
defaultOs = "zos";
} else {
defaultOs = "linux";
}
return defaultOs;
}
@Nonnull
protected String doHttpGetText(
@Nonnull final HttpClient client,
@Nonnull final String url,
final int connectionRequestTimeout,
@Nonnull @MustNotContainNull String... acceptedContent
) throws IOException {
final AtomicReference result = new AtomicReference<>();
doGetRequest(client, url, this.mojo.getProxy(), x -> {
try {
result.set(EntityUtils.toString(x));
} catch (IOException ex) {
throw new IORuntimeWrapperException(ex);
}
}, connectionRequestTimeout, false, acceptedContent);
return result.get();
}
/**
* Download content file through GET request and calculate its SHA256 hash
*
* @param client http client
* @param url url of the content file
* @param targetFile target file to save the content
* @param digest calculator of needed digest
* @param connectionRequestTimeout timeout for connection request
* @param acceptedContent mime types of accepted content
* @return response headers
* @throws IOException it any transport error
*/
@MustNotContainNull
@Nonnull
protected Header[] doHttpGetIntoFile(
@Nonnull final HttpClient client,
@Nonnull final String url,
@Nonnull final Path targetFile,
@Nonnull final MessageDigest digest,
final int connectionRequestTimeout,
@Nonnull @MustNotContainNull final String... acceptedContent
) throws IOException {
final Log log = this.mojo.getLog();
log.debug(format("Loading %s into file %s, request timeout %d ms", url, targetFile.toString(), connectionRequestTimeout));
Header[] responseHeaders;
try {
responseHeaders = doGetRequest(client, url, this.mojo.getProxy(), httpEntity -> {
boolean showProgress = false;
try {
try (final OutputStream fileOutStream = newOutputStream(targetFile)) {
final byte[] buffer = new byte[1024 * 1024];
final long contentSize = httpEntity.getContentLength();
final InputStream inStream = httpEntity.getContent();
log.debug("Reported content size: " + contentSize + " bytes");
final int PROGRESSBAR_WIDTH = 10;
final String LOADING_TITLE = format("Loading %d Mb ", (contentSize / (1024L * 1024L)));
showProgress = contentSize > 0L && !this.mojo.getSession().isParallel();
if (!showProgress) {
log.info(String.format("Loading file %s, size %d bytes", targetFile.getFileName().toString(), contentSize));
}
long downloadByteCounter = 0L;
int lastShownProgress = -1;
if (showProgress) {
lastShownProgress = StringUtils.printTextProgress(LOADING_TITLE, downloadByteCounter, contentSize, PROGRESSBAR_WIDTH, lastShownProgress);
}
digest.reset();
while (!Thread.currentThread().isInterrupted()) {
final int length = inStream.read(buffer);
if (length < 0) {
break;
}
fileOutStream.write(buffer, 0, length);
digest.update(buffer, 0, length);
downloadByteCounter += length;
if (showProgress) {
lastShownProgress = StringUtils.printTextProgress(LOADING_TITLE, downloadByteCounter, contentSize, PROGRESSBAR_WIDTH, lastShownProgress);
}
}
fileOutStream.flush();
}
} catch (IOException ex) {
log.error(String.format("Can't download %s into %s: %s", url, targetFile, ex.getMessage()));
if (Files.exists(targetFile)) {
log.debug(String.format("Deleting file %s", targetFile));
try {
Files.delete(targetFile);
} catch (IOException exx) {
log.error(String.format("Can't delete file %s: %s", targetFile, exx.getMessage()));
}
}
throw new IORuntimeWrapperException(ex);
} finally {
if (showProgress) {
System.out.println();
}
}
}, connectionRequestTimeout, true, acceptedContent);
} catch (IORuntimeWrapperException ex) {
throw ex.getWrapped();
}
return Assertions.assertNotNull(responseHeaders);
}
@Nonnull
protected Path loadJdkIntoCacheIfNotExist(@Nonnull final Path cacheFolder, @Nonnull final String targetFolderName, @Nonnull IoLoader loader) throws IOException {
final Log log = this.mojo.getLog();
final Path tempFolder = cacheFolder.resolve(".TMP" + targetFolderName);
final Path resultFolder = cacheFolder.resolve(targetFolderName);
File lockingFile = null;
try {
lockingFile = this.lockCache(cacheFolder, targetFolderName);
if (isDirectory(resultFolder)) {
log.debug("Already cached JDK folder detected, skip loading: " + resultFolder);
} else {
log.debug("JDK cache has been locking, the locking file: " + lockingFile);
loader.doLoad(tempFolder);
if (tempFolder.toFile().renameTo(resultFolder.toFile())) {
log.debug("Renamed " + tempFolder.getFileName() + " to " + resultFolder.getFileName());
} else {
log.error("Can't rename " + tempFolder.getFileName() + " to " + resultFolder.getFileName());
throw new IOException("Can't rename temp folder " + tempFolder + " to " + resultFolder);
}
}
} finally {
if (lockingFile != null) {
log.debug("Locker delete status is " + lockingFile.delete());
} else {
log.debug("Locker is null");
}
}
return resultFolder;
}
@Nonnull
public abstract Path getPathToJdk(@Nonnull final Map config) throws IOException;
@FunctionalInterface
public interface IoLoader {
void doLoad(@Nonnull final Path destinationFolder) throws IOException;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy