/*
* Copyright (C) 2009 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.common.metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* A set of utilities for processing a {@link DeploymentContext}
*
* @author Heiko Braun <hbraun@redhat.com>
\ */
public class PackagingUtil {
private static final Logger log = LoggerFactory.getLogger("ClasspathScanning");
public static File identifyDeployment(final URL url) {
String actualFilePath = url.getPath();
if (actualFilePath.startsWith("file:")) {
actualFilePath = actualFilePath.substring(5);
}
final int nestedSeperator = actualFilePath.indexOf('!');
if (nestedSeperator != -1) {
actualFilePath = actualFilePath.substring(0, nestedSeperator);
}
log.debug("scanning inside: " + actualFilePath);
return findActualDeploymentFile(new File(actualFilePath));
}
static File findActualDeploymentFile(File start) {
int pivotPoint;
String rootPath = start.getPath();
do {
start = new File(rootPath);
rootPath = rootPath.substring(0, (pivotPoint = rootPath.lastIndexOf(File.separator)) < 0 ? 0 : pivotPoint);
}
while (!start.exists() && pivotPoint > 0);
return start;
}
static void process(final DeploymentContext ctx) {
for (final URL url : ctx.getConfigUrls()) {
final File file = PackagingUtil.identifyDeployment(url);
/**
* several config urls may derive from the same archive
* don't process them twice
*/
if (!ctx.hasProcessed(file)) {
ctx.markProcessed(file);
if (file.getName().endsWith(".ear")){
PackagingUtil.processNestedZip(file, ctx);
}
}
}
}
private static void processNestedZip(final File file, final DeploymentContext ctx) {
try {
if (file.getName().matches(".+\\.(ear|war|sar)$") && !file.isDirectory()) // process only certain deployment types
{
if (file.getName().endsWith(".war"))
ctx.getSubContexts().put(file.getName(), file); // WEB-INF/classes
final ZipInputStream zipFile = new ZipInputStream(new FileInputStream(file));
ZipEntry zipEntry;
try {
while ((zipEntry = zipFile.getNextEntry()) != null) {
if (zipEntry.getName().matches(".+\\.(zip|jar|war)$")) // expand nested zip archives
{
if (!ctx.getSubContexts().containsKey(zipEntry.getName())) {
final File tmpUnZip = expandZipEntry(zipFile, zipEntry, ctx);
ctx.getSubContexts().put(zipEntry.getName(), tmpUnZip);
processNestedZip(tmpUnZip, ctx);
}
}
}
}
finally {
zipFile.close();
}
}
}
catch (Exception e) {
throw new RuntimeException("Failed to process nested zip", e);
}
}
protected static File expandZipEntry(final ZipInputStream stream, final ZipEntry entry, final DeploymentContext ctx) {
final String tmpUUID = "erraiBootstrap_" + UUID.randomUUID().toString().replaceAll("\\-", "_");
final String tmpDir = System.getProperty("java.io.tmpdir") + "/" + tmpUUID;
final int idx = entry.getName().lastIndexOf('/');
final String tmpFileName = tmpDir + "/" + entry.getName().substring(idx == -1 ? 0 : idx);
try {
final File tmpDirFile = new File(tmpDir);
if (!tmpDirFile.exists() && !tmpDirFile.mkdirs()) {
throw new RuntimeException("unable to create temporary directory: " + tmpDirFile.getAbsolutePath());
}
ctx.markTmpFile(tmpDirFile);
final File newFile = new File(tmpFileName);
final FileOutputStream outStream = new FileOutputStream(newFile);
final byte[] buf = new byte[1024];
int read;
while ((read = stream.read(buf)) != -1) {
outStream.write(buf, 0, read);
}
outStream.flush();
outStream.close();
return newFile;
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new RuntimeException("Error reading from stream", e);
}
}
}