Java tutorial
/* * Copyright 2016 Fizzed, Inc. * * 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.fizzed.stork.deploy; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Archive { static private final Logger log = LoggerFactory.getLogger(Archive.class); private final Path file; private final String format; public Archive(Path file) { this.file = file; this.format = format(file); } public Path getFile() { return this.file; } public String getName() { return this.file.getFileName().toString(); } public String getNameWithNoExtension() { String name = getName(); return name.substring(0, name.length() - this.format.length() - 1); } /** * Returns the format of the archive such as "tar.gz" or ".zip" * @return */ public String getFormat() { return this.format; } public Path unpack(Path unpackDir) throws IOException { Files.createDirectories(unpackDir); log.info("Unpacking {} to {}", file, unpackDir); // we need to know the top-level dir(s) created by unpack final Set<Path> firstLevelPaths = new LinkedHashSet<>(); final AtomicInteger count = new AtomicInteger(); try (ArchiveInputStream ais = newArchiveInputStream(file)) { ArchiveEntry entry; while ((entry = ais.getNextEntry()) != null) { try { Path entryFile = Paths.get(entry.getName()); Path resolvedFile = unpackDir.resolve(entryFile); firstLevelPaths.add(entryFile.getName(0)); log.debug("{}", resolvedFile); if (entry.isDirectory()) { Files.createDirectories(resolvedFile); } else { unpackEntry(ais, resolvedFile); count.incrementAndGet(); } } catch (IOException | IllegalStateException | IllegalArgumentException e) { log.error("", e); throw new RuntimeException(e); } } } if (firstLevelPaths.size() != 1) { throw new IOException("Only archives with a single top-level directory are supported!"); } Path assemblyDir = unpackDir.resolve(firstLevelPaths.iterator().next()); log.info("Unpacked {} files to {}", count, assemblyDir); return assemblyDir; } static public String format(Path file) { String name = file.getFileName().toString(); if (name.endsWith(".tar.gz")) { return "tar.gz"; } else if (name.endsWith(".zip")) { return "zip"; } else { return null; } } static private ArchiveInputStream newArchiveInputStream(Path file) throws IOException { String name = file.getFileName().toString(); if (name.endsWith(".tar.gz")) { return new TarArchiveInputStream(new GzipCompressorInputStream(Files.newInputStream(file), true)); } else if (name.endsWith(".zip")) { return new ZipArchiveInputStream(Files.newInputStream(file)); } else { throw new IOException("Unsupported archive file type (we support .tar.gz and .zip)"); } } static private void unpackEntry(ArchiveInputStream ais, Path target) throws IOException { // always make sure parent dir exists Files.createDirectories(target.getParent()); try (OutputStream os = Files.newOutputStream(target, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { try (BufferedOutputStream bos = new BufferedOutputStream(os)) { int len = 0; byte[] BUFFER = new byte[1024]; while ((len = ais.read(BUFFER)) != -1) { bos.write(BUFFER, 0, len); } } } } static public Archive pack(Path unpackedDir, String format) throws IOException { String name = unpackedDir.getFileName().toString(); Path archiveFile = unpackedDir.resolveSibling(name + "." + format); return pack(unpackedDir, archiveFile, format); } static public Archive pack(Path unpackedDir, Path archiveFile, String format) throws IOException { log.info("Packing {} to {}", unpackedDir, archiveFile); try (ArchiveOutputStream aos = newArchiveOutputStream(archiveFile, format)) { packEntry(aos, unpackedDir, unpackedDir.getFileName().toString(), false); } return new Archive(archiveFile); } static private ArchiveOutputStream newArchiveOutputStream(Path file, String format) throws IOException { switch (format) { case "tar.gz": TarArchiveOutputStream tgzout = new TarArchiveOutputStream( new GzipCompressorOutputStream(Files.newOutputStream(file))); tgzout.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR); tgzout.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); return tgzout; case "zip": return new ZipArchiveOutputStream(Files.newOutputStream(file)); default: throw new IOException("Unsupported archive file type (we support .tar.gz and .zip)"); } } static public void packEntry(ArchiveOutputStream aos, Path dirOrFile, String base, boolean appendName) throws IOException { String entryName = base; if (appendName) { if (!entryName.equals("")) { if (!entryName.endsWith("/")) { entryName += "/" + dirOrFile.getFileName(); } else { entryName += dirOrFile.getFileName(); } } else { entryName += dirOrFile.getFileName(); } } ArchiveEntry entry = aos.createArchiveEntry(dirOrFile.toFile(), entryName); if (Files.isRegularFile(dirOrFile)) { if (entry instanceof TarArchiveEntry && Files.isExecutable(dirOrFile)) { // -rwxr-xr-x ((TarArchiveEntry) entry).setMode(493); } else { // keep default mode } } aos.putArchiveEntry(entry); if (Files.isRegularFile(dirOrFile)) { Files.copy(dirOrFile, aos); aos.closeArchiveEntry(); } else { aos.closeArchiveEntry(); List<Path> children = Files.list(dirOrFile).collect(Collectors.toList()); if (children != null) { for (Path childFile : children) { packEntry(aos, childFile, entryName + "/", true); } } } } }