Skip to content

Commit

Permalink
WELD-1930 Weld SE - basic nested archive support
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba committed Feb 23, 2016
1 parent 595cc32 commit b81ea51
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 27 deletions.
Expand Up @@ -109,14 +109,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 {
log.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,65 +48,63 @@ public class FileSystemBeanArchiveHandler implements BeanArchiveHandler {
@Override
public BeanArchiveBuilder handle(String path) {

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

if(!file.exists()) {
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.exists()) {
return null;
}

BeanArchiveBuilder builder = new BeanArchiveBuilder();

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

0 comments on commit b81ea51

Please sign in to comment.