package com.subhajit.build;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipFile;
import org.apache.tools.ant.taskdefs.ManifestException;
import com.subhajit.common.util.CommonUtils;
import com.subhajit.common.util.CompletionExecutor;
import com.subhajit.common.util.IProgress;
import com.subhajit.common.util.CommonUtils.IRepositoryParser;
import com.subhajit.common.util.CommonUtils.IResource;
import com.subhajit.common.util.streams.StreamUtils;
public class CombineJars {
// private static final Logger sLog = Logger.getLogger(CombineJars.class);
public void createCombinedJar(String mainClass, File[] jarFiles,
File outputFile, IProgress... progresses) throws ManifestException,
IOException {
// Read resources from all the JARs.
CompletionExecutor<Map<String, byte[]>> executor = new CompletionExecutor<Map<String, byte[]>>(
5);
for (final File file : jarFiles) {
executor.submit(new Callable<Map<String, byte[]>>() {
public Map<String, byte[]> call() throws Exception {
Map<String, byte[]> ret = new HashMap<String, byte[]>();
IRepositoryParser parser = null;
try {
if (file.isFile()) {
parser = new CommonUtils.ZipParser(
new ZipFile(file));
} else {
parser = new CommonUtils.DirectoryParser(file);
}
Iterator<IResource> it = parser.iterator();
while (it.hasNext()) {
IResource resource = it.next();
if (!resource.isDirectory()) {
InputStream in = null;
try {
in = resource.getInputStream();
ret.put(resource.getName(), StreamUtils
.readFully(in));
} finally {
if (in != null) {
in.close();
}
}
}
}
return ret;
} finally {
if (parser != null) {
parser.close();
}
}
}
});
}
Manifest manifest = null;
Map<String, byte[]> resources = new HashMap<String, byte[]>();
while (true) {
Map.Entry<Boolean, Map<String, byte[]>> result = null;
try {
result = executor.getNextCompleted();
} catch (InterruptedException exc) {
exc.printStackTrace(System.out);
Thread.currentThread().interrupt();
return;
} catch (ExecutionException exc) {
if (exc.getCause() instanceof ManifestException) {
throw new RuntimeException(exc);
} else if (exc.getCause() instanceof IOException) {
throw (IOException) exc.getCause();
} else if (exc.getCause() instanceof RuntimeException) {
throw (RuntimeException) exc.getCause();
} else {
throw new UndeclaredThrowableException(exc.getCause());
}
}
if (!result.getKey()) {
break;
}
for (IProgress progress : progresses) {
progress.increment(1, null);
}
// If there is a manifest in the results, ingest it and remove it
// from the results map.
if (result.getValue().containsKey("META-INF/MANIFEST.MF")) {
BufferedReader reader = null;
try {
InputStream in = null;
try {
in = new ByteArrayInputStream(result.getValue().get(
"META-INF/MANIFEST.MF"));
reader = new BufferedReader(new InputStreamReader(in));
if (manifest == null) {
manifest = new Manifest(reader);
} else {
manifest.merge(new Manifest(reader));
}
} finally {
if (in != null) {
in.close();
}
}
} finally {
if (reader != null) {
reader.close();
}
}
result.getValue().remove("META-INF/MANIFEST.MF");
}
resources.putAll(result.getValue());
}
if (manifest != null) {
if (manifest.getMainSection() != null
&& manifest.getMainSection().getAttribute("Main-Class") != null) {
manifest.getMainSection().removeAttribute("Main-Class");
}
manifest.getMainSection().addConfiguredAttribute(
new Manifest.Attribute("Main-Class", mainClass));
} else {
manifest = new Manifest();
manifest.getMainSection().addConfiguredAttribute(
new Manifest.Attribute("Main-Class", mainClass));
}
resources.put("META-INF/MANIFEST.MF", manifest.toString().getBytes());
new JarCreator().createJarFile(outputFile, resources);
}
}