Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WELD-1930 Weld SE - basic support for nested archives #1046

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -102,14 +102,16 @@ protected String getBeanArchiveReference(URL url) {

} else if(PROCOTOL_JAR.equals(url.getProtocol())) {
// Adapt JAR file URL, e.g. "jar:file:/home/duke/duke.jar!/META-INF/beans.xml" becomes "/home/duke/duke.jar"
// NOTE: Some class loaders may support nested jars, e.g. "jar:file:/home/duke/duke.jar!/lib/foo.jar!/META-INF/beans.xml" becomes
// "/home/duke/duke.jar!/lib/foo.jar"

// The decoded part without protocol part, i.e. without "jar:"
ref = uri.getSchemeSpecificPart();

if(ref.lastIndexOf(JAR_URL_SEPARATOR) > 0) {
ref = ref.substring(0, ref.lastIndexOf(JAR_URL_SEPARATOR));
}
return getBeanArchiveReferenceForJar(ref, url);
ref = getBeanArchiveReferenceForJar(ref, url);
} else {
logger.warnv("Unable to adapt URL: {0}, using its external form instead", url);
ref = url.toExternalForm();
Expand Down
Expand Up @@ -16,6 +16,7 @@
*/
package org.jboss.weld.environment.deployment.discovery;

import static org.jboss.weld.environment.util.URLUtils.JAR_URL_SEPARATOR;
import static org.jboss.weld.environment.util.URLUtils.PROCOTOL_JAR;

import java.io.File;
Expand All @@ -24,8 +25,8 @@
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.jboss.logging.Logger;
import org.jboss.weld.environment.logging.CommonLogger;
Expand All @@ -47,7 +48,16 @@ public class FileSystemBeanArchiveHandler implements BeanArchiveHandler {
@Override
public BeanArchiveBuilder handle(String path) {

File file = new File(path);
boolean nested = false;
File file;

if (path.contains(JAR_URL_SEPARATOR)) {
// Most probably a nested archive, e.g. "/home/duke/duke.jar!/lib/foo.jar"
file = new File(path.substring(0, path.indexOf(JAR_URL_SEPARATOR)));
nested = true;
} else {
file = new File(path);
}

if(!file.canRead()) {
return null;
Expand All @@ -57,55 +67,44 @@ public BeanArchiveBuilder handle(String path) {

try {
log.debugv("Handle path: {0}", path);

if (file.isDirectory()) {
handleDirectory(new DirectoryEntry().setFile(file), builder);
} else {
handleFile(file, builder);
if(nested) {
handleNestedFile(path, file, builder);
} else {
handleFile(file, builder);
}
}
} catch (IOException e) {
log.warn("Could not handle path: "+path , e);
} catch (Exception e) {
CommonLogger.LOG.cannotHandleFilePath(file, path, e);
return null;
}
return builder;
}

protected void handleFile(File file, BeanArchiveBuilder builder) throws IOException {

log.debugv("Handle archive file: {0}", file);

try {
ZipFile zip = new ZipFile(file);
try (ZipFile zip = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
ZipFileEntry entry = new ZipFileEntry(PROCOTOL_JAR + ":" + file.toURI().toURL().toExternalForm() + "!/");
ZipFileEntry entry = new ZipFileEntry(PROCOTOL_JAR + ":" + file.toURI().toURL().toExternalForm() + JAR_URL_SEPARATOR);
while (entries.hasMoreElements()) {
add(entry.setName(entries.nextElement().getName()), builder);
}
zip.close();
} catch (ZipException e) {
throw CommonLogger.LOG.cannotHandleFile(file, e);
}
}

protected void handleDirectory(DirectoryEntry entry, BeanArchiveBuilder builder) throws IOException {

log.debugv("Handle directory: {0}", entry.getFile());

File[] files = entry.getFile().listFiles();

if(files == null) {
log.warnv("Unable to list directory files: {0}", entry.getFile());
}
String parentPath = entry.getName();

for (File child : files) {

if(entry.getName() != null ) {
entry.setPath(entry.getName() + "/" + child.getName());
} else {
entry.setPath(child.getName());
}
entry.setFile(child);

if (child.isDirectory()) {
handleDirectory(entry, builder);
} else {
Expand All @@ -115,6 +114,39 @@ protected void handleDirectory(DirectoryEntry entry, BeanArchiveBuilder builder)
}
}

protected void handleNestedFile(String path, File file, BeanArchiveBuilder builder) throws IOException {
log.debugv("Handle nested archive\n File: {0}\n Path: {1}", file, path);

String nestedEntryName = path.substring(path.indexOf(JAR_URL_SEPARATOR) + JAR_URL_SEPARATOR.length(), path.length());
if (nestedEntryName.contains(JAR_URL_SEPARATOR)) {
throw new IllegalArgumentException("Recursive nested archives are not supported");
}

try (ZipFile zip = new ZipFile(file)) {

Enumeration<? extends ZipEntry> entries = zip.entries();

while (entries.hasMoreElements()) {

ZipEntry zipEntry = entries.nextElement();

if (zipEntry.getName().equals(nestedEntryName)) {

// Reconstruct the archive URL, e.g. "jar:file:/home/duke/duke.jar!/lib/foo.jar"
ZipFileEntry entry = new ZipFileEntry(PROCOTOL_JAR + ":" + file.toURI().toURL().toExternalForm() + JAR_URL_SEPARATOR + zipEntry.getName());

// Add entries from the nested archive
try (ZipInputStream nestedZip = new ZipInputStream(zip.getInputStream(zipEntry))) {
ZipEntry nestedEntry;
while ((nestedEntry = nestedZip.getNextEntry()) != null) {
add(entry.setName(nestedEntry.getName()), builder);
}
}
}
}
}
}

protected void add(Entry entry, BeanArchiveBuilder builder) throws MalformedURLException {
if (Files.isClass(entry.getName())) {
builder.addClass(Files.filenameToClassname(entry.getName()));
Expand Down
Expand Up @@ -43,8 +43,9 @@ public interface CommonLogger extends WeldEnvironmentLogger {
@Message(id = 6, value = "Could not invoke JNLPClassLoader#getJarFile(URL) on context class loader", format = Format.MESSAGE_FORMAT)
void jnlpClassLoaderInvocationException(@Cause Throwable cause);

@Message(id = 7, value = "Error handling file {0}", format = Format.MESSAGE_FORMAT)
RuntimeException cannotHandleFile(Object param1, @Cause Throwable cause);
@LogMessage(level = Level.WARN)
@Message(id = 7, value = "Error handling file path\n File: {0}\n Path: {1}", format = Format.MESSAGE_FORMAT)
void cannotHandleFilePath(Object file, Object path, @Cause Throwable cause);

@LogMessage(level = Level.ERROR)
@Message(id = 8, value = "Error loading file {0}", format = Format.MESSAGE_FORMAT)
Expand Down