/**
* Plugin for NanoVM.
*/
package org.eclipse.nanovm.internal.ui.project;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.eclipse.core.resources.ICommand;
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.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.dialogs.DialogSettings;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.nanovm.internal.ui.utils.FileUtil;
import org.eclipse.nanovm.runtime.NanoVMRuntime;
import org.eclipse.nanovm.tool.NanoVMTool;
import org.eclipse.nanovm.ui.NanoVMUI;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard;
/**
* NanoVM project wizard.
*
* @author tugstugi@yahoo.com
*/
public class NewNanoVMProjectWizard extends BasicNewProjectResourceWizard {
private static final String DIALOG_SETTINGS_KEY = "NewNanoVMProjectWizard";
private WizardNewProjectCreationPage mainPage;
private IProject newProject;
private String defaultProjectName;
public NewNanoVMProjectWizard() {
this(null);
}
public NewNanoVMProjectWizard(String defaultProjectName) {
this.defaultProjectName = defaultProjectName;
initDialogSettings();
}
@Override
public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
super.init(workbench, currentSelection);
setNeedsProgressMonitor(true);
setWindowTitle("New NanoVM Project");
}
protected void initDialogSettings() {
IDialogSettings pluginSettings = NanoVMUI.getDefault().getDialogSettings();
IDialogSettings wizardSettings = pluginSettings.getSection(DIALOG_SETTINGS_KEY);
if (wizardSettings == null) {
wizardSettings = new DialogSettings(DIALOG_SETTINGS_KEY);
pluginSettings.addSection(wizardSettings);
}
setDialogSettings(wizardSettings);
}
@Override
public void addPages() {
mainPage = new WizardNewProjectCreationPage("basicNewProjectPage");
mainPage.setTitle("NanoVM Project");
mainPage.setDescription("Create a new NanoVM project.");
if(defaultProjectName != null)
mainPage.setInitialProjectName(defaultProjectName);
this.addPage(mainPage);
}
@Override
public IProject getNewProject() {
return newProject;
}
@Override
public boolean performFinish() {
createNewNanoVMProject();
if (newProject == null) {
return false;
}
updatePerspective();
selectAndReveal(newProject);
return true;
}
private IProject createNewNanoVMProject() {
if (newProject != null) {
return newProject;
}
// get a project handle
final IProject newProjectHandle = mainPage.getProjectHandle();
// get a project descriptor
URI location = null;
if (!mainPage.useDefaults()) {
location = mainPage.getLocationURI();
}
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IProjectDescription description = workspace.newProjectDescription(newProjectHandle.getName());
description.setLocationURI(location);
// create the new project operation
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
protected void execute(IProgressMonitor monitor) throws CoreException {
createNanoVMProject(description, newProjectHandle, monitor);
}
};
// run the new project creation operation
try {
getContainer().run(true, true, op);
} catch (InterruptedException e) {
return null;
} catch (InvocationTargetException e) {
// ie.- one of the steps resulted in a core exception
Throwable t = e.getTargetException();
if (t instanceof CoreException) {
if (((CoreException) t).getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
MessageDialog.openError(getShell(), "Creation Problems", MessageFormat.format("The underlying file system is case insensitive. There is an existing project which conflicts with ''{0}''.", newProjectHandle.getName()));
} else {
ErrorDialog.openError(getShell(), "Creation Problems", null, ((CoreException) t).getStatus());
}
} else {
NanoVMUI.log(e);
}
return null;
}
newProject = newProjectHandle;
return newProject;
}
void createNanoVMProject(IProjectDescription description, IProject projectHandle, IProgressMonitor monitor) throws CoreException, OperationCanceledException {
try {
monitor.beginTask("", 7000);
addNature(JavaCore.NATURE_ID, description, monitor);
addNature(NanoVMUI.NATURE_ID, description, monitor);
addBuilder(JavaCore.BUILDER_ID, description, monitor);
//addBuilder(NanoVMUI.BUILDER_ID, description, monitor);
projectHandle.create(description, new SubProgressMonitor(monitor, 1000));
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
projectHandle.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 1000));
createFolderHierarchy(projectHandle, getFolderHierarchyFromPath("src"), new SubProgressMonitor(monitor, 300));
createFolderHierarchy(projectHandle, getFolderHierarchyFromPath("bin"), new SubProgressMonitor(monitor, 300));
createFolderHierarchy(projectHandle, getFolderHierarchyFromPath("config"), new SubProgressMonitor(monitor, 300));
createFolderHierarchy(projectHandle, getFolderHierarchyFromPath("lib"), new SubProgressMonitor(monitor, 300));
createConfigurationFiles(projectHandle.getFolder("config"), new SubProgressMonitor(monitor, 1000));
createToolLibrary(projectHandle.getFolder("lib"), new SubProgressMonitor(monitor, 1000));
createRuntimeLibrary(projectHandle.getFolder("lib"), new SubProgressMonitor(monitor, 1000));
IFile file= projectHandle.getFile(".classpath");
file.create(createClasspathEntries(), true, new SubProgressMonitor(monitor, 100));
} finally {
monitor.done();
}
}
private void addNature(String natureID, IProjectDescription description, IProgressMonitor monitor) throws CoreException {
if (monitor != null && monitor.isCanceled()) {
throw new OperationCanceledException();
}
if (!description.hasNature(natureID)) {
String[] prevNatures= description.getNatureIds();
String[] newNatures= new String[prevNatures.length + 1];
System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
newNatures[prevNatures.length]= natureID;
description.setNatureIds(newNatures);
}
if (monitor != null) {
monitor.worked(100);
}
}
private void addBuilder(String builderID, IProjectDescription description, IProgressMonitor monitor) throws CoreException {
if (monitor != null && monitor.isCanceled()) {
throw new OperationCanceledException();
}
if (!hasBuilder(builderID, description)) {
ICommand[] prevBuilders= description.getBuildSpec();
ICommand[] newBuilders= new ICommand[prevBuilders.length + 1];
System.arraycopy(prevBuilders, 0, newBuilders, 0, prevBuilders.length);
newBuilders[prevBuilders.length]= description.newCommand();
newBuilders[prevBuilders.length].setBuilderName(builderID);
description.setBuildSpec(newBuilders);
}
if (monitor != null) {
monitor.worked(100);
}
}
private boolean hasBuilder(String builderID, IProjectDescription description){
for(ICommand command : description.getBuildSpec()){
if(builderID.equals(command.getBuilderName()))
return true;
}
return false;
}
private String[] getFolderHierarchyFromPath(String path){
StringTokenizer tokenizer = new StringTokenizer(path, "/");
ArrayList<String> tokens = new ArrayList<String>();
while(tokenizer.hasMoreTokens())
tokens.add(tokenizer.nextToken());
return tokens.toArray(new String[tokens.size()]);
}
private void createFolderHierarchy(IProject projectHandle, String[] folders, IProgressMonitor monitor) throws CoreException {
IFolder last= null;
for(String folderName : folders) {
if(last == null) {
last= projectHandle.getFolder(folderName);
if(!last.exists())
last.create(true, true, monitor);
} else {
IFolder newFolder= last.getFolder(folderName);
if(!newFolder.exists())
newFolder.create(true, true, monitor);
last= newFolder;
}
}
}
private void createConfigurationFiles(IFolder destination, IProgressMonitor monitor){
try {
File configDirectory= new File(FileLocator.resolve(new URL(NanoVMTool.getDefault().getBundle().getEntry("/"), "config/")).getFile());
File files[] = configDirectory.listFiles();
monitor.beginTask("Copying configuration files", files.length);
for(File file : files){
if(file.getName().toLowerCase().endsWith(NanoVMTool.CONFIGURATION_FILE_EXTENSION) || file.getName().toLowerCase().endsWith(NanoVMTool.NATIVE_FILE_EXTENSION))
FileUtil.copyFile(file, destination, monitor);
monitor.worked(1);
}
} catch (MalformedURLException e) {
NanoVMUI.log(e);
} catch (IOException e) {
NanoVMUI.log(e);
}
monitor.done();
}
private void createToolLibrary(IFolder destination, IProgressMonitor monitor){
monitor.beginTask("Copying tool library", 1);
try {
File runtimeToolFile= new File(FileLocator.resolve(new URL(NanoVMTool.getDefault().getBundle().getEntry("/"), "lib/" + NanoVMTool.LIBRARY_NAME)).getFile());
FileUtil.copyFile(runtimeToolFile, destination, monitor);
monitor.worked(1);
} catch (MalformedURLException e) {
NanoVMUI.log(e);
} catch (IOException e) {
NanoVMUI.log(e);
}
monitor.done();
}
private void createRuntimeLibrary(IFolder destination, IProgressMonitor monitor){
monitor.beginTask("Copying runtime library", 1);
try {
if(Platform.inDevelopmentMode()){
File runtimeLibraryDirectory= new File(FileLocator.resolve(new URL(NanoVMRuntime.getDefault().getBundle().getEntry("/"), "bin")).getFile());
FileUtil.copyDirectory(runtimeLibraryDirectory, destination.getFolder(NanoVMRuntime.LIBRARY_NAME), monitor);
monitor.worked(1);
}else{
File runtimeLibraryFile= new File(FileLocator.resolve(new URL(NanoVMRuntime.getDefault().getBundle().getEntry("/"), NanoVMRuntime.LIBRARY_NAME)).getFile());
FileUtil.copyFile(runtimeLibraryFile, destination, monitor);
monitor.worked(1);
}
} catch (MalformedURLException e) {
NanoVMUI.log(e);
} catch (IOException e) {
NanoVMUI.log(e);
}
monitor.done();
}
private InputStream createClasspathEntries(){
ByteArrayOutputStream buffer= new ByteArrayOutputStream();
PrintStream classpath= new PrintStream(buffer, true);
classpath.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
classpath.println("<classpath>");
// src entries
insertEntry(classpath, "src", "src");
// output folder
insertEntry(classpath, "output", "bin");
// container
//insertEntry(classpath, "con", "org.eclipse.jdt.launching.JRE_CONTAINER");
insertEntry(classpath, "con", NanoVMUI.LIBRARY_CONTAINER_ID);
classpath.print("</classpath>");
return new ByteArrayInputStream(buffer.toByteArray());
}
private void insertEntry(PrintStream stream, String kind, String path) {
stream.append("\t<classpathentry kind=\"").append(kind).append("\" path=\"").append(path).println("\"/>");
}
}