/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.gd.jpdl.wizard;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard;
import org.jboss.tools.jbpm.preferences.JbpmInstallation;
import org.jboss.tools.jbpm.preferences.PreferencesManager;
import org.jbpm.gd.jpdl.Logger;
import org.jbpm.gd.jpdl.util.JbpmClasspathContainer;
public class NewProcessProjectWizard extends Wizard implements INewWizard, IExecutableExtension {
private WizardNewProjectCreationPage mainPage;
private ConfigureRuntimePage configureRuntimePage;
private NewProcessProjectDetailsWizardPage coreJbpmPage;
private IProject newProject;
private IWorkbench workbench;
private IConfigurationElement configElement;
public boolean canFinish() {
return super.canFinish() && coreJbpmPage.combo.getItemCount() > 0 && coreJbpmPage.combo.getSelectionIndex() != -1;
}
public void init(IWorkbench w, IStructuredSelection currentSelection) {
this.workbench = w;
setNeedsProgressMonitor(true);
setWindowTitle("New Process Project");
}
public void addPages() {
addMainPage();
if (!isJbpm3RuntimeAvailable()) {
addConfigureRuntimePage();
}
addChooseRuntimePage();
}
private boolean isJbpm3RuntimeAvailable() {
Map<String, JbpmInstallation> installations = PreferencesManager.getInstance().getJbpmInstallationMap();
Iterator<String> iterator = installations.keySet().iterator();
while (iterator.hasNext()) {
JbpmInstallation installation = installations.get(iterator.next());
if ("jBPM3".equals(installation.version)) {
return true;
}
}
return false;
}
private void addConfigureRuntimePage() {
configureRuntimePage = new ConfigureRuntimePage();
addPage(configureRuntimePage);
}
private void addChooseRuntimePage() {
coreJbpmPage = new NewProcessProjectDetailsWizardPage();
addPage(coreJbpmPage);
}
private void addMainPage() {
super.addPages();
setWindowTitle("New Process Project");
mainPage = new WizardNewProjectCreationPage("basicNewProjectPage");
mainPage.setTitle("Process Project");
mainPage.setDescription("Create a new process project.");
addPage(mainPage);
}
private IProject createNewProject() {
final IProject newProjectHandle = mainPage.getProjectHandle();
final IProjectDescription description = createProjectDescription(newProjectHandle);
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
protected void execute(IProgressMonitor monitor)
throws CoreException {
createProject(description, newProjectHandle, monitor);
}
};
runProjectCreationOperation(op, newProjectHandle);
return newProjectHandle;
}
private void addJRELibraries(IJavaProject javaProject) throws JavaModelException {
ArrayList entries = new ArrayList();
entries.addAll(Arrays.asList(javaProject.getRawClasspath()));
entries.addAll(Arrays.asList(PreferenceConstants.getDefaultJRELibrary()));
javaProject.setRawClasspath((IClasspathEntry[])entries.toArray(new IClasspathEntry[entries.size()]), null);
}
private void addSourceFolders(IJavaProject javaProject) throws JavaModelException, CoreException {
ArrayList entries = new ArrayList();
entries.addAll(Arrays.asList(javaProject.getRawClasspath()));
addSourceFolder(javaProject, entries, "src/main/java");
addSourceFolder(javaProject, entries, "src/main/config");
addSourceFolder(javaProject, entries, "src/main/jpdl");
addSourceFolder(javaProject, entries, "src/test/java");
javaProject.setRawClasspath((IClasspathEntry[])entries.toArray(new IClasspathEntry[entries.size()]), null);
}
private void addSourceFolder(IJavaProject javaProject, ArrayList entries, String path) throws CoreException {
IFolder folder = javaProject.getProject().getFolder(path);
createFolder(folder);
IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(folder);
entries.add(JavaCore.newSourceEntry(root.getPath()));
}
private void createFolder(IFolder folder) throws CoreException {
IContainer parent = folder.getParent();
if (parent != null && !parent.exists() && parent instanceof IFolder) {
createFolder((IFolder)parent);
}
if (!(folder.exists())) {
folder.create(true, true, null);
}
}
private JbpmInstallation getJbpmInstallation() {
return PreferencesManager.getInstance().getJbpmInstallation(getCoreJbpmName());
}
private void createJbpmLibraryContainer(IJavaProject javaProject) throws JavaModelException {
JavaCore.setClasspathContainer(
new Path("JBPM/" + getJbpmInstallation().name),
new IJavaProject[] { javaProject },
new IClasspathContainer[] { new JbpmClasspathContainer(javaProject, getJbpmInstallation()) },
null);
}
private String getCoreJbpmName() {
return coreJbpmPage.getCoreJbpmName();
}
private void addJbpmLibraries(IJavaProject javaProject) throws JavaModelException {
createJbpmLibraryContainer(javaProject);
ArrayList entries = new ArrayList();
entries.addAll(Arrays.asList(javaProject.getRawClasspath()));
entries.add(JavaCore.newContainerEntry(new Path("JBPM/" + getJbpmInstallation().name)));
javaProject.setRawClasspath((IClasspathEntry[])entries.toArray(new IClasspathEntry[entries.size()]), null);
}
private void createOutputLocation(IJavaProject javaProject) throws JavaModelException, CoreException {
IFolder binFolder = javaProject.getProject().getFolder("bin");
createFolder(binFolder);
IPath outputLocation = binFolder.getFullPath();
javaProject.setOutputLocation(outputLocation, null);
}
private void addJavaBuilder(IJavaProject javaProject) throws CoreException {
IProjectDescription desc = javaProject.getProject().getDescription();
ICommand command = desc.newCommand();
command.setBuilderName(JavaCore.BUILDER_ID);
desc.setBuildSpec(new ICommand[] { command });
javaProject.getProject().setDescription(desc, null);
}
private void createJavaProject() {
try {
newProject = createNewProject();
newProject.setPersistentProperty(new QualifiedName("", "jbpmName"), getCoreJbpmName());
IJavaProject javaProject = JavaCore.create(newProject);
createOutputLocation(javaProject);
addJavaBuilder(javaProject);
setClasspath(javaProject);
createInitialContent(javaProject);
newProject.build(IncrementalProjectBuilder.FULL_BUILD, null);
} catch (JavaModelException e) {
ErrorDialog.openError(getShell(), "Problem creating java project", null, e.getStatus());
} catch (CoreException e) {
ErrorDialog.openError(getShell(), "Problem creating java project", null, e.getStatus());
} catch (IOException e) {
ErrorDialog.openError(getShell(), "Problem creating java project", null, null);
}
}
private void createInitialContent(IJavaProject javaProject) throws CoreException, JavaModelException, IOException {
if (coreJbpmPage.checkbox.getSelection()) {
createMessageActionHandler(javaProject);
createSimpleProcessTest(javaProject);
createSimpleProcessDefinition(javaProject);
}
copyJbpmResources(javaProject);
}
private void createSimpleProcessDefinition(IJavaProject javaProject) throws CoreException, JavaModelException, IOException {
JbpmInstallation jbpmInstallation = PreferencesManager.getInstance().getJbpmInstallation(getCoreJbpmName());
if (jbpmInstallation == null) return;
// IFolder processesFolder = javaProject.getProject().getFolder("processes");
// if (!processesFolder.exists()) {
// processesFolder.create(true, true, null);
// }
IFolder folder = javaProject.getProject().getFolder("src/main/jpdl");
if (!folder.exists()) {
folder.create(true, true, null);
}
String location = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(jbpmInstallation.location);
String fromPath = getLocation("examples", location);
if (fromPath == null) {
fromPath = "/src/process.examples/simple.par";
} else {
fromPath = fromPath + "/simple/src/main/jpdl";
}
fromPath = new Path(location).append(fromPath).toOSString();
File fromDir = new File(fromPath);
if (!fromDir.exists()) return;
File[] files = fromDir.listFiles();
IFile destination = null;
for (int i = 0; i < files.length; i++) {
if ("processdefinition.xml".equals(files[i].getName())) {
destination = folder.getFile("simple.jpdl.xml");
} else if ("gpd.xml".equals(files[i].getName())) {
destination = folder.getFile(".simple.gpd.xml");
} else if ("processimage.jpg".equals(files[i].getName())) {
destination = folder.getFile("simple.jpg");
}
if (destination != null) {
destination.create(new FileInputStream(files[i]), true, null);
}
}
}
private void createSimpleProcessTest(IJavaProject javaProject) throws JavaModelException, IOException {
String resourceName = "org/jbpm/gd/jpdl/resource/SimpleProcessTest.java.template";
IFolder folder = javaProject.getProject().getFolder("src/test/java");
IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(folder);
IPackageFragment pack = root.createPackageFragment("com.sample", true, null);
InputStream stream = getClass().getClassLoader().getResourceAsStream(resourceName);
byte[] content = readStream(stream);
pack.createCompilationUnit("SimpleProcessTest.java", new String(content), true, null);
}
private void createMessageActionHandler(IJavaProject javaProject) throws JavaModelException, IOException {
String resourceName = "org/jbpm/gd/jpdl/resource/MessageActionHandler.java.template";
IFolder folder = javaProject.getProject().getFolder("src/main/java");
IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(folder);
IPackageFragment pack = root.createPackageFragment("com.sample.action", true, null);
InputStream stream = getClass().getClassLoader().getResourceAsStream(resourceName);
byte[] content = readStream(stream);
pack.createCompilationUnit("MessageActionHandler.java", new String(content), true, null);
}
private void copyJbpmResources(IJavaProject javaProject) throws CoreException {
JbpmInstallation jbpmInstallation = PreferencesManager.getInstance().getJbpmInstallation(getCoreJbpmName());
if (jbpmInstallation == null) return;
String location = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(jbpmInstallation.location);
IFolder folder = javaProject.getProject().getFolder("src/main/config");
String fromPath = getLocation("config", location);
if (fromPath == null) {
fromPath = "/src/config.files";
}
fromPath = new Path(location).append(fromPath).toOSString();
File fromDir = new File(fromPath);
if (!fromDir.exists()) return;
File[] files = fromDir.listFiles();
for (int i = 0; i < files.length; i++) {
if (!files[i].isDirectory()) {
copyJbpmResource(files[i], folder);
}
}
}
private String getLocation(String selector, String baseLocation) {
String result = null;
try {
IPath locationPath = new Path(baseLocation);
Document document = new SAXReader().read(locationPath.append("src/resources/gpd/version.info.xml").toFile());
XPath xpath = document.createXPath("/jbpm-version-info/" + selector);
List list = xpath.selectNodes(document);
if (!list.isEmpty()) {
result = (String)((Element)list.get(0)).attribute("path").getData();
}
}
catch (MalformedURLException e) { }
catch (DocumentException e) { }
return result;
}
private void copyJbpmResource(File source, IFolder destination) throws CoreException {
try {
IFile file = destination.getFile(source.getName());
file.create(new FileInputStream(source), true, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private void setClasspath(IJavaProject javaProject) throws JavaModelException, CoreException {
javaProject.setRawClasspath(new IClasspathEntry[0], null);
addSourceFolders(javaProject);
addJRELibraries(javaProject);
addJbpmLibraries(javaProject);
// Hack to overcome the problems of the classpath container not being created in the classpath.
javaProject.getRawClasspath();
}
private IProjectDescription createProjectDescription(
IProject newProjectHandle) {
IPath newPath = null;
if (!mainPage.useDefaults())
newPath = mainPage.getLocationPath();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProjectDescription description = workspace
.newProjectDescription(newProjectHandle.getName());
description.setLocation(newPath);
addJavaNature(description);
return description;
}
private void addJavaNature(IProjectDescription description) {
ArrayList natures = new ArrayList();
natures.addAll(Arrays.asList(description.getNatureIds()));
natures.add(JavaCore.NATURE_ID);
description.setNatureIds((String[])natures.toArray(new String[natures.size()]));
}
private void runProjectCreationOperation(WorkspaceModifyOperation op,
IProject newProjectHandle) {
try {
getContainer().run(false, true, op);
} catch (InterruptedException e) {
Logger.logError("InterruptedException while creating project", e);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof CoreException) {
handleCoreException(newProjectHandle, (CoreException) t);
} else {
handleOtherProblem(t);
}
}
}
private void handleOtherProblem(Throwable t) {
MessageDialog.openError(getShell(), "Creation Problems",
"Internal error: " + t.getMessage());
}
private void handleCoreException(final IProject newProjectHandle,
CoreException e) {
if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
MessageDialog
.openError(
getShell(),
"Creation Problems",
"The underlying file system is case insensitive. There is an existing project which conflicts with '"
+ newProjectHandle.getName() + "'.");
} else {
ErrorDialog.openError(getShell(), "Creation Problems", null, e
.getStatus());
}
}
void createProject(IProjectDescription description, IProject projectHandle,
IProgressMonitor monitor) throws CoreException,
OperationCanceledException {
try {
monitor.beginTask("", 2000);
projectHandle.create(description, new SubProgressMonitor(monitor,
1000));
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
projectHandle.open(IResource.BACKGROUND_REFRESH,
new SubProgressMonitor(monitor, 1000));
} finally {
monitor.done();
}
}
public IProject getNewProject() {
return newProject;
}
public boolean performFinish() {
if (!isJbpm3RuntimeAvailable()) {
String name = configureRuntimePage.nameText.getText();
String location = configureRuntimePage.locationText.getText();
String version = "jBPM3";
PreferencesManager.getInstance().initializeDefaultJbpmInstallation(name, location, version);
}
getContainer().updateButtons();
createJavaProject();
if (newProject == null) {
getContainer().updateButtons();
return false;
}
updatePerspective();
selectAndReveal(newProject);
getContainer().updateButtons();
return true;
}
protected void updatePerspective() {
try {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page.findView("org.eclipse.ui.views.PropertySheet") == null) {
page.showView("org.eclipse.ui.views.PropertySheet");
}
BasicNewProjectResourceWizard.updatePerspective(configElement);
} catch (PartInitException e) {
e.printStackTrace();
}
}
protected void selectAndReveal(IResource newResource) {
selectAndReveal(newResource, workbench.getActiveWorkbenchWindow());
}
private void selectAndReveal(IResource resource,
IWorkbenchWindow window) {
if (!inputValid(resource, window)) return;
Iterator itr = getParts(window.getActivePage()).iterator();
while (itr.hasNext()) {
selectAndRevealTarget(
window,
new StructuredSelection(resource),
getTarget((IWorkbenchPart)itr.next()));
}
}
private boolean inputValid(IResource resource, IWorkbenchWindow window) {
if (window == null || resource == null) return false;
else if (window.getActivePage() == null) return false;
else return true;
}
private void selectAndRevealTarget(IWorkbenchWindow window, final ISelection selection, ISetSelectionTarget target) {
if (target == null) return;
final ISetSelectionTarget finalTarget = target;
window.getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
finalTarget.selectReveal(selection);
}
});
}
private ISetSelectionTarget getTarget(IWorkbenchPart part) {
ISetSelectionTarget target = null;
if (part instanceof ISetSelectionTarget) {
target = (ISetSelectionTarget)part;
}
else {
target = (ISetSelectionTarget)part.getAdapter(ISetSelectionTarget.class);
}
return target;
}
private List getParts(IWorkbenchPage page) {
List result = new ArrayList();
addParts(result, page.getViewReferences());
addParts(result, page.getEditorReferences());
return result;
}
private void addParts(List parts, IWorkbenchPartReference[] refs) {
for (int i = 0; i < refs.length; i++) {
IWorkbenchPart part = refs[i].getPart(false);
if (part != null) {
parts.add(part);
}
}
}
private byte[] readStream(InputStream in) throws IOException {
byte[] contents = null;
int fileSize = 0;
byte[] buffer = new byte[1024];
int bytesRead = in.read(buffer);
while (bytesRead != -1) {
byte[] newContents = new byte[fileSize + bytesRead];
if (fileSize > 0) {
System.arraycopy(contents, 0, newContents, 0, fileSize);
}
System.arraycopy(buffer, 0, newContents, fileSize, bytesRead);
contents = newContents;
fileSize += bytesRead;
bytesRead = in.read(buffer);
}
return contents;
}
public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) {
configElement = cfig;
}
}