Skip to content

Commit

Permalink
Add support for WAR and EAR files #107
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarsotovalero committed Dec 1, 2021
1 parent de9a9c8 commit 12e76e6
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 56 deletions.
Expand Up @@ -34,6 +34,7 @@
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
Expand Down Expand Up @@ -346,6 +347,7 @@ private void printString(final String string) {
System.out.println(string); //NOSONAR avoid a warning of non-used logger
}

@SneakyThrows
@Override
public final void execute() throws MojoExecutionException {
if (skipDepClean) {
Expand Down Expand Up @@ -423,7 +425,7 @@ public final void execute() throws MojoExecutionException {
project.getBuild().getDirectory() + "/" + DIRECTORY_TO_COPY_DEPENDENCIES;
File dependencyDirectory = new File(dependencyDirectoryName);
if (dependencyDirectory.exists()) {
JarUtils.decompressJars(dependencyDirectoryName);
JarUtils.decompress(dependencyDirectoryName);
}

/* Analyze dependencies usage status */
Expand Down
Expand Up @@ -17,15 +17,17 @@

package se.kth.depclean.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

/**
* Utility class to handle JAR files.
Expand All @@ -46,12 +48,12 @@ private JarUtils() {
*
* @param outputDirectory The directory path to put the decompressed files.
*/
public static void decompressJars(final String outputDirectory) {
public static void decompress(final String outputDirectory) {
File files = new File(outputDirectory);
for (File f : Objects.requireNonNull(files.listFiles())) {
if (f.getName().endsWith(".jar")) {
if (f.getName().endsWith(".jar") || f.getName().endsWith(".war") || f.getName().endsWith(".ear")) {
try {
JarUtils.decompressJarFile(outputDirectory, f.getAbsolutePath());
JarUtils.decompressDependencyFiles(f.getAbsolutePath());
// delete the original dependency jar file
org.apache.commons.io.FileUtils.forceDelete(f);
} catch (IOException e) {
Expand All @@ -62,52 +64,49 @@ public static void decompressJars(final String outputDirectory) {
}

/**
* Decompress a JAR file in a path to a directory (will be created if it doesn't exists).
* Decompress all JAR/WAR/EAR files withing a file (recursively).
*
* @param destDirectory The destine directory.
* @param jarFilePath The path to the Jar file to be decompressed.
* @throws IOException In case of IO issues.
* @param zipFile The file to be decompressed.
*/
private static void decompressJarFile(String destDirectory, String jarFilePath) throws IOException {
File destDir = new File(destDirectory);
if (!destDir.exists()) {
destDir.mkdir();
}
try (JarInputStream jarIn = new JarInputStream(new FileInputStream(jarFilePath))) {
JarEntry entry = jarIn.getNextJarEntry();
// iterates over all the entries in the jar file
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
private static void decompressDependencyFiles(String zipFile) throws IOException {
File file = new File(zipFile);
try (ZipFile zip = new ZipFile(file)) {
String newPath = zipFile.substring(0, zipFile.length() - 4);
new File(newPath).mkdir();
Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory()) {
new File(filePath).getParentFile().mkdirs(); //NOSONAR Triggers a false warning of path traversal attack
try {
// if the entry is a file, extracts it
extractFile(jarIn, filePath);
} catch (IOException e) {
log.warn("Could not extract file: " + filePath + " from jar " + jarFilePath);
BufferedInputStream is = new BufferedInputStream(zip.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte[] data = new byte[BUFFER_SIZE];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER_SIZE)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
is.close();
}
}
jarIn.closeEntry();
entry = jarIn.getNextJarEntry();
if (currentEntry.endsWith(".jar") || currentEntry.endsWith(".war") || currentEntry.endsWith(".ear")) {
// found a zip file, try to open
decompressDependencyFiles(destFile.getAbsolutePath());
FileUtils.forceDelete(new File(destFile.getAbsolutePath()));
}
}
}
}

/**
* Extracts an entry file.
*
* @param jarIn The jar file to be extracted.
* @param filePath Path to the file.
* @throws IOException In case of IO issues.
*/
private static void extractFile(final JarInputStream jarIn, final String filePath) throws IOException {
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(filePath))) { //NOSONAR Triggers a false warning of path traversal attack
byte[] bytesIn = new byte[BUFFER_SIZE];
int read;
while ((read = jarIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
}

}
Expand Up @@ -23,6 +23,8 @@ class JarUtilsTest {
// The JAR files used for testing
static final File jcabiSSHJar = new File("src/test/resources/JarUtilsResources_copy/jcabi-ssh-1.6.jar");
static final File jcabiXMLJar = new File("src/test/resources/JarUtilsResources_copy/jcabi-xml-0.22.2.jar");
static final File jLibraryEAR = new File("src/test/resources/JarUtilsResources_copy/jlibrary-ear-1.2.ear");
static final File warWAR = new File("src/test/resources/JarUtilsResources_copy/war-6.2.3.war");

@BeforeEach
void setUp() {
Expand Down Expand Up @@ -50,43 +52,66 @@ void afterEach() {
@Order(1)
@DisplayName("Test that the JAR files are removed after being decompressed")
void whenDecompressJarFiles_thenJarFilesAreRemoved() throws RuntimeException, IOException {
if (jcabiSSHJar.exists() && jcabiXMLJar.exists()) {
if (jcabiSSHJar.exists() && jcabiXMLJar.exists() && warWAR.exists() && jLibraryEAR.exists()) {
// Decompress all the jar files in the current directory
decompress();
assertFalse(FileUtils.directoryContains(copyDir, jcabiSSHJar));
assertFalse(FileUtils.directoryContains(copyDir, jcabiXMLJar));
assertFalse(FileUtils.directoryContains(copyDir, jLibraryEAR));
assertFalse(FileUtils.directoryContains(copyDir, warWAR));
}
}

@Test
@Order(2)
@DisplayName("Test that when decompressing JAR files other (decompressed) files are created")
void whenDecompressJarFiles_thenOtherFilesAreCreated() throws RuntimeException {
// Assert that POM files in JARs are decompressed
if (jcabiSSHJar.exists() && jcabiXMLJar.exists()) {
// Assert that POM files are decompressed
if (jcabiSSHJar.exists() && jcabiXMLJar.exists() && jLibraryEAR.exists() && jcabiXMLJar.exists()) {
decompress();
// JAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/META-INF/maven/com.jcabi/jcabi-ssh/pom.xml").exists()
new File("src/test/resources/JarUtilsResources_copy/jcabi-ssh-1.6/META-INF/maven/com.jcabi/jcabi-ssh/pom.xml").exists()
);
// JAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/META-INF/maven/com.jcabi/jcabi-xml/pom.xml").exists());
new File("src/test/resources/JarUtilsResources_copy/jcabi-xml-0.22.2/META-INF/maven/com.jcabi/jcabi-xml/pom.xml").exists()
);
// WAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/war-6.2.3/META-INF/maven/org.glassfish.main.admingui/war/pom.xml").exists()
);
// EAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/jlibrary-ear-1.2/META-INF/maven/org.jlibrary/jlibrary-ear/pom.xml").exists()
);
}
// Assert that CLASS files in JARs are decompressed
if (jcabiSSHJar.exists() && jcabiXMLJar.exists()) {
if (jcabiSSHJar.exists() && jcabiXMLJar.exists() && jLibraryEAR.exists() && jcabiXMLJar.exists()) {
// JAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/com/jcabi/ssh/Ssh.class").exists()
new File("src/test/resources/JarUtilsResources_copy/jcabi-ssh-1.6/com/jcabi/ssh/Ssh.class").exists()
);
// JAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/com/jcabi/xml/XML.class").exists()
new File("src/test/resources/JarUtilsResources_copy/jcabi-xml-0.22.2/com/jcabi/xml/XML.class").exists()
);
// WAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/war-6.2.3/WEB-INF/lib/console-core-6.2.3/org/glassfish/admingui/util/SunOptionUtil.class").exists()
);
// EAR
assertTrue(
new File("src/test/resources/JarUtilsResources_copy/jlibrary-ear-1.2/jlibrary/WEB-INF/lib/jcr-1.0/javax/jcr/Item.class").exists()
);
}
}

private void decompress() {
try {
JarUtils.decompressJars(copyDir.getAbsolutePath());
JarUtils.decompress(copyDir.getAbsolutePath());
} catch (RuntimeException e) {
System.out.println("Error decompressing jars in " + copyDir.getAbsolutePath());
}
}

}
Binary file not shown.
Binary file not shown.

0 comments on commit 12e76e6

Please sign in to comment.