| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.ignite.mesos.resource; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.nio.channels.Channels; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.nio.file.StandardCopyOption; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import java.util.stream.Collectors; |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import org.apache.ignite.mesos.ClusterProperties; |
| |
| import static org.apache.ignite.mesos.ClusterProperties.IGNITE_VERSION; |
| |
| /** |
| * Class downloads and stores Ignite. |
| */ |
| public class IgniteProvider { |
| /** Logger. */ |
| private static final Logger log = Logger.getLogger(IgniteProvider.class.getSimpleName()); |
| |
| /** */ |
| private static final String DOWNLOAD_URL_PATTERN = "https://archive.apache.org/dist/ignite/%s/apache-ignite-%s-bin.zip"; |
| |
| /** URL for request Ignite latest version. */ |
| private static final String IGNITE_LATEST_VERSION_URL = "https://ignite.apache.org/latest"; |
| |
| /** Mirrors. */ |
| private static final String APACHE_MIRROR_URL = "https://www.apache.org/dyn/closer.cgi?as_json=1"; |
| |
| /** Ignite on Apache URL path. */ |
| private static final String IGNITE_PATH = "/ignite/%s/apache-ignite-%s-bin.zip"; |
| |
| /** Version pattern. */ |
| private static final Pattern VERSION_PATTERN = Pattern.compile("(?<=version=).*\\S+"); |
| |
| /** */ |
| private String downloadFolder; |
| |
| /** |
| * @param downloadFolder Folder with ignite. |
| */ |
| public IgniteProvider(String downloadFolder) { |
| this.downloadFolder = downloadFolder; |
| } |
| |
| /** |
| * @param ver Ignite version. |
| * @return Path to latest ignite. |
| * @throws IOException If downloading failed. |
| */ |
| public String getIgnite(String ver) throws IOException { |
| return downloadIgnite(ver); |
| } |
| |
| /** |
| * @param ver Ignite version which will be downloaded. If {@code null} will download the latest ignite version. |
| * @return Ignite archive. |
| * @throws IOException If downloading failed. |
| */ |
| public String downloadIgnite(String ver) throws IOException { |
| assert ver != null; |
| |
| URL url; |
| |
| // get the latest version. |
| if (ver.equals(ClusterProperties.DEFAULT_IGNITE_VERSION)) { |
| try { |
| ver = findLatestVersion(); |
| |
| // and try to retrieve from a mirror. |
| url = new URL(String.format(findMirror() + IGNITE_PATH, ver, ver)); |
| } |
| catch (Exception e) { |
| // fallback to archive. |
| url = new URL(String.format(DOWNLOAD_URL_PATTERN, ver, ver)); |
| } |
| } |
| else { |
| // or from archive. |
| url = new URL(String.format(DOWNLOAD_URL_PATTERN, ver, ver)); |
| } |
| |
| return downloadIgnite(url); |
| } |
| |
| /** |
| * Attempts to retrieve the preferred mirror. |
| * |
| * @return Mirror url. |
| * @throws IOException If failed. |
| */ |
| private String findMirror() throws IOException { |
| String response = getHttpContents(new URL(APACHE_MIRROR_URL)); |
| |
| if (response == null) |
| throw new RuntimeException("Failed to retrieve mirrors"); |
| |
| ObjectMapper mapper = new ObjectMapper(); |
| JsonNode mirrorUrl = mapper.readTree(response).get("preferred"); |
| |
| if (mirrorUrl == null) |
| throw new RuntimeException("Failed to find the preferred mirror"); |
| |
| return mirrorUrl.asText(); |
| } |
| |
| /** |
| * Attempts to obtain the latest version. |
| * |
| * @return Latest version. |
| * @throws IOException If failed. |
| */ |
| private String findLatestVersion() throws IOException { |
| String response = getHttpContents(new URL(IGNITE_LATEST_VERSION_URL)); |
| |
| if (response == null) |
| throw new RuntimeException("Failed to identify the latest version. Specify it with " + IGNITE_VERSION); |
| |
| Matcher m = VERSION_PATTERN.matcher(response); |
| if (m.find()) |
| return m.group(); |
| else |
| throw new RuntimeException("Failed to retrieve the latest version. Specify it with " + IGNITE_VERSION); |
| } |
| |
| /** |
| * @param url Url. |
| * @return Contents. |
| * @throws IOException If failed. |
| */ |
| private String getHttpContents(URL url) throws IOException { |
| HttpURLConnection conn = (HttpURLConnection)url.openConnection(); |
| |
| int code = conn.getResponseCode(); |
| |
| if (code != 200) |
| throw null; |
| |
| BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); |
| return rd.lines().collect(Collectors.joining()); |
| } |
| |
| /** |
| * Downloads ignite by URL if this version wasn't downloaded before. |
| * |
| * @param url URL to Ignite. |
| * @return File name. |
| */ |
| private String downloadIgnite(URL url) { |
| assert url != null; |
| |
| try { |
| HttpURLConnection conn = (HttpURLConnection)url.openConnection(); |
| |
| int code = conn.getResponseCode(); |
| |
| if (code == 200) { |
| checkDownloadFolder(); |
| |
| String fileName = fileName(url.toString()); |
| |
| if (fileExist(fileName)) |
| return fileName; |
| |
| log.log(Level.INFO, "Downloading from {0}", url.toString()); |
| |
| FileOutputStream outFile = new FileOutputStream(Paths.get(downloadFolder, fileName).toFile()); |
| |
| outFile.getChannel().transferFrom(Channels.newChannel(conn.getInputStream()), 0, Long.MAX_VALUE); |
| |
| outFile.close(); |
| |
| return fileName; |
| } |
| else |
| throw new RuntimeException("Got unexpected response code. Response code: " + code + " from " + url); |
| } |
| catch (IOException e) { |
| throw new RuntimeException("Failed to download Ignite.", e); |
| } |
| } |
| |
| /** |
| * Checks that file exists. |
| * |
| * @param fileName File name. |
| * @return {@code True} if file exist otherwise {@code false}. |
| */ |
| private boolean fileExist(String fileName) { |
| String pathToIgnite = downloadFolder + (downloadFolder.endsWith("/") ? "" : '/') + fileName; |
| |
| return new File(pathToIgnite).exists(); |
| } |
| |
| /** |
| * Copy file to working directory. |
| * |
| * @param filePath File path. |
| * @return File name. |
| * @throws IOException If coping failed. |
| */ |
| String copyToWorkDir(String filePath) throws IOException { |
| Path srcFile = Paths.get(filePath); |
| |
| if (Files.exists(srcFile)) { |
| checkDownloadFolder(); |
| |
| Path newDir = Paths.get(downloadFolder); |
| |
| Path fileName = srcFile.getFileName(); |
| |
| Files.copy(srcFile, newDir.resolve(fileName), StandardCopyOption.REPLACE_EXISTING); |
| |
| return fileName.toString(); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @return Download folder. |
| */ |
| private File checkDownloadFolder() { |
| File file = new File(downloadFolder); |
| |
| if (!file.exists()) |
| file.mkdirs(); |
| |
| if (!file.exists()) |
| throw new IllegalArgumentException("Failed to create working directory: " + downloadFolder); |
| |
| return file; |
| } |
| |
| /** |
| * @param url URL. |
| * @return File name. |
| */ |
| private static String fileName(String url) { |
| String[] split = url.split("/"); |
| |
| return split[split.length - 1]; |
| } |
| } |