package org.jbpm.gd.jpdl.deployment;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.jbpm.gd.jpdl.Logger;
import org.jbpm.gd.jpdl.editor.JpdlEditor;
public class ProcessArchiveBuilder {
private JpdlEditor jpdlEditor;
public ProcessArchiveBuilder(JpdlEditor jpdlEditor) {
this.jpdlEditor = jpdlEditor;
}
public byte[] build() {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
if (jpdlEditor.getDeploymentInfo() != null) {
addProcessInfoFile(zipOutputStream);
addGraphicalInfoFile(zipOutputStream);
addProcessImageFile(zipOutputStream);
addAdditionalFiles(zipOutputStream);
addClassesAndResources(zipOutputStream);
}
zipOutputStream.close();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
showBuildProcessArchiveException();
return null;
}
}
private void showBuildProcessArchiveException() {
MessageDialog dialog = new MessageDialog(
jpdlEditor.getSite().getShell(),
"Build Process Archive Failed",
null,
"There was a problem creating the process archive to deploy.",
SWT.ICON_ERROR,
new String[] { "OK" },
0);
dialog.open();
}
private void addFile(ZipOutputStream zipOutputStream, IFile file, String entryName) throws Exception {
byte[] buffer = new byte[256];
InputStream inputStream;
try {
inputStream = file.getContents();
} catch (CoreException e) {
Logger.logError("CoreException getting contents of file " + file.getName(), e);
throw e;
}
try {
zipOutputStream.putNextEntry(new ZipEntry(entryName));
} catch (IOException e) {
Logger.logError("IOException creating entry '" + entryName + "'.", e);
}
int read;
try {
while ((read = inputStream.read(buffer)) != -1) {
zipOutputStream.write(buffer, 0, read);
}
} catch(IOException e) {
Logger.logError("IOException writing file '"+ entryName +"'.", e);
}
}
private void addProcessInfoFile(ZipOutputStream zipOutputStream) throws Exception {
IFile processInfoFile = jpdlEditor.getDeploymentInfo().getProcessInfoFile();
if (processInfoFile != null) {
addFile(zipOutputStream, processInfoFile, "processdefinition.xml");
}
}
private void addGraphicalInfoFile(ZipOutputStream zipOutputStream) throws Exception {
IFile graphicalInfoFile = jpdlEditor.getDeploymentInfo().getGraphicalInfoFile();
if (graphicalInfoFile != null) {
addFile(zipOutputStream, graphicalInfoFile, "gpd.xml");
}
}
private void addProcessImageFile(ZipOutputStream zipOutputStream) throws Exception {
IFile processImageFile = jpdlEditor.getDeploymentInfo().getImageFile();
if (processImageFile != null) {
addFile(zipOutputStream, processImageFile, "processimage.jpg");
}
}
private void addAdditionalFiles(ZipOutputStream zipOutputStream) throws Exception {
Object[] additionalFiles = jpdlEditor.getDeploymentInfo().getAdditionalFiles();
if (additionalFiles == null) return;
for (int i = 0; i < additionalFiles.length; i++) {
if (!(additionalFiles[i] instanceof IFile)) continue;
IFile file = (IFile)additionalFiles[i];
addFile(zipOutputStream, file, file.getName());
}
}
private void addClassesAndResources(ZipOutputStream zipOutputStream) throws Exception {
Object[] classesAndResources = jpdlEditor.getDeploymentInfo().getClassesAndResources();
if (classesAndResources == null) return;
for (int i = 0; i < classesAndResources.length; i++) {
if (classesAndResources[i] instanceof IFile) {
addFile(zipOutputStream, (IFile)classesAndResources[i]);
} else if (classesAndResources[i] instanceof ICompilationUnit) {
addCompilationUnit(zipOutputStream, (ICompilationUnit)classesAndResources[i]);
} else if (classesAndResources[i] instanceof IClassFile) {
addClassFile(zipOutputStream, (IClassFile)classesAndResources[i]);
}
}
}
private void addFile(ZipOutputStream zipOutputStream, String name, ClassLoader classLoader) throws Exception {
byte[] buff = new byte[256];
zipOutputStream.putNextEntry(new ZipEntry("classes/" + name));
InputStream is = classLoader.getResourceAsStream(name);
int read;
while ((read = is.read(buff)) != -1) {
zipOutputStream.write(buff, 0, read);
}
is.close();
}
private void addFile(ZipOutputStream zipOutputStream, IFile file) throws Exception {
addFile(zipOutputStream, getResourceName(file), getClassLoader());
}
private void addCompilationUnit(ZipOutputStream zipOutputStream, ICompilationUnit compilationUnit) throws Exception {
String name = getResourceName(compilationUnit.getResource());
name = name.substring(0, name.lastIndexOf(".java")) + ".class";
ClassLoader classLoader = getClassLoader();
addFile(zipOutputStream, name, classLoader);
addInnerClasses(zipOutputStream, name, classLoader);
}
private String[] getNestedClassNames(String name, ClassLoader classLoader) {
final String className =
name.substring(name.lastIndexOf('/') + 1, name.length() - 6) + '$';
URL url = classLoader.getResource(name);
File file = new File(url.getFile());
File folder = new File(file.getParent());
return folder.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith(className);
}
});
}
private void addInnerClasses(ZipOutputStream zipOutputStream, String name, ClassLoader classLoader) throws Exception {
String[] nestedClassNames = getNestedClassNames(name, classLoader);
if (nestedClassNames == null) return;
for (int i = 0; i < nestedClassNames.length; i++) {
String fileName = name.substring(0, name.lastIndexOf("/") + 1) + nestedClassNames[i];
addFile(zipOutputStream, fileName, classLoader);
}
}
private void addClassFile(ZipOutputStream zipOutputStream, IClassFile classFile) throws Exception {
String name = classFile.getParent().getElementName().replace('.', '/') + "/" + classFile.getElementName();
zipOutputStream.putNextEntry(new ZipEntry("classes/" + name));
zipOutputStream.write(classFile.getBytes());
}
private ClassLoader getClassLoader() throws Exception {
return new URLClassLoader(getProjectClasspathUrls(), getClass().getClassLoader());
}
private URL[] getProjectClasspathUrls() throws Exception {
URL[] urls = new URL[0];
IProject project = getProject();
IJavaProject javaProject = JavaCore.create(project);
if (javaProject == null) {
return urls;
}
String[] pathArray = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);
urls = new URL[pathArray.length];
for (int i = 0; i < pathArray.length; i++) {
urls[i] = new File(pathArray[i]).toURI().toURL();
}
return urls;
}
private IProject getProject() {
IEditorInput editorInput = jpdlEditor.getEditorInput();
if (!(editorInput instanceof IFileEditorInput)) return null;
IFile file = ((IFileEditorInput)editorInput).getFile();
return file.getProject();
}
private IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
IPackageFragmentRoot root = null;
IResource r = resource;
while (r != null) {
IJavaElement javaElement = JavaCore.create(r);
if (javaElement != null && javaElement instanceof IPackageFragmentRoot) {
root = (IPackageFragmentRoot)javaElement;
break;
}
r = r.getParent();
}
return root;
}
private String getResourceName(IResource resource) {
IPackageFragmentRoot root = getPackageFragmentRoot(resource);
if (root == null) {
return null;
} else {
int index = root.getResource().getProjectRelativePath().toString().length() + 1;
return resource.getProjectRelativePath().toString().substring(index);
}
}
}