restx.core.shell.RestxArchive Maven / Gradle / Ivy
package restx.core.shell;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import restx.AppSettings;
import restx.build.RestxBuild;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
/**
* @author fcamblor
*/
public class RestxArchive {
private static final String CHROOT = "META-INF/restx/app/";
private Path jarFile;
public RestxArchive(Path jarFile) {
this.jarFile = jarFile;
}
private static class JarCopierFileVisitor extends SimpleFileVisitor {
private final Path startingDirectory;
private final String targetDirPrefix;
private List excludes;
private final JarOutputStream jarOS;
private JarCopierFileVisitor(Path startingDirectory, JarOutputStream jarOS, String targetDirPrefix, List excludes) {
this.startingDirectory = startingDirectory;
this.jarOS = jarOS;
this.targetDirPrefix = targetDirPrefix;
this.excludes = excludes;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
super.preVisitDirectory(dir, attrs);
String directoryRelativizedName = startingDirectory.relativize(dir).toString().replace("\\", "/");
if(!directoryRelativizedName.isEmpty()) {
if(!directoryRelativizedName.endsWith("/")) {
directoryRelativizedName += "/";
}
for(String exclude : excludes){
if(directoryRelativizedName.startsWith(exclude)){
return FileVisitResult.SKIP_SUBTREE;
}
}
String targetDirectoryPath = targetDirPrefix + directoryRelativizedName;
JarEntry dirEntry = new JarEntry(targetDirectoryPath);
dirEntry.setTime(Files.getLastModifiedTime(dir).toMillis());
jarOS.putNextEntry(dirEntry);
jarOS.closeEntry();
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
super.visitFile(file, attrs);
copyFileToJar(jarOS, startingDirectory, targetDirPrefix, file);
return FileVisitResult.CONTINUE;
}
}
private static void createJarDirIfNotExists(JarOutputStream jarOS, Path rootDir, String path) throws IOException {
if(!Files.exists(rootDir.resolve(path))){
JarEntry dirEntry = new JarEntry(path+"/");
jarOS.putNextEntry(dirEntry);
jarOS.closeEntry();
}
}
private static void copyFileToJar(JarOutputStream jarOS, Path rootDir, String targetDirPrefix, Path file) throws IOException {
JarEntry fileEntry = new JarEntry(targetDirPrefix + rootDir.relativize(file).toString());
try { fileEntry.setTime(Files.getLastModifiedTime(file).toMillis()); }
catch (IOException e) {}
jarOS.putNextEntry(fileEntry);
Files.copy(file, jarOS);
jarOS.closeEntry();
}
public void pack(Path workingDirectory, final Path targetClassesDirectory, List packagingExcludes) {
try(final JarOutputStream jarOS = new JarOutputStream(new FileOutputStream(jarFile.toFile()))) {
// Generating md.restx.json if it doesn't exist yet
// Because a restx archive without this descriptor won't be considered as valid restx archive
Path md = workingDirectory.resolve("md.restx.json");
boolean generatedMd = false;
if(!Files.exists(md)){
List foreignModuleDescriptors = RestxBuild.resolveForeignModuleDescriptorsIn(workingDirectory);
if(!foreignModuleDescriptors.isEmpty()) {
Path firstModuleDescriptor = Iterables.getFirst(foreignModuleDescriptors, null);
RestxBuild.convert(firstModuleDescriptor, md);
generatedMd = true;
} else {
throw new RuntimeException("Project descriptor (either a md.restx.json, or a foreign descriptor (pom, ivy, ...) file) is missing !");
}
}
try {
Files.walkFileTree(targetClassesDirectory, new JarCopierFileVisitor(targetClassesDirectory, jarOS, "", Collections.emptyList()));
// Ensuring CHROOT is made available in target jar
String path = "";
for(String chrootChunk : Splitter.on("/").split(CHROOT)){
if(!chrootChunk.isEmpty()) {
path += chrootChunk;
createJarDirIfNotExists(jarOS, targetClassesDirectory, path);
path += "/";
}
}
// Copying everything into CHROOT directory
Files.walkFileTree(workingDirectory, new JarCopierFileVisitor(workingDirectory, jarOS, CHROOT, packagingExcludes));
} finally {
if(generatedMd) {
md.toFile().delete();
}
}
} catch (IOException e) {
Throwables.propagate(e);
}
}
public void unpack(Path destinationDirectory, AppSettings appSettings) {
Path targetClassesDir = destinationDirectory.resolve(appSettings.targetClasses());
try ( JarFile jar = new JarFile(jarFile.toFile()) ) {
if(jar.getJarEntry(CHROOT+"md.restx.json") == null) {
throw new IllegalArgumentException("File "+jarFile+" is not a restx archive (no md.restx.json file found) !");
}
for(Enumeration jarEntries = jar.entries(); jarEntries.hasMoreElements();){
JarEntry entry = jarEntries.nextElement();
String entryPath = entry.getName();
if(!entry.isDirectory()) {
Path destinationFile;
// Unpacking chrooted files in app root directory..
if(entryPath.startsWith(CHROOT)) {
Path chrootedFile = destinationDirectory.resolve(entryPath.substring(CHROOT.length()));
destinationFile = chrootedFile;
// ... and unpacking other files in classes directory
} else {
destinationFile = targetClassesDir.resolve(entryPath);
}
com.google.common.io.Files.createParentDirs(destinationFile.toFile());
try(InputStream jarInputStream = jar.getInputStream(entry)) {
Files.copy(jarInputStream, destinationFile);
}
}
}
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy