/**
* Copyright (c) 2016 Inria
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* - Philippe Merle <philippe.merle@inria.fr>
*/
package org.occiware.clouddesigner.occi.gen.connector.ui.wizards;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
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.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.JavaRuntime;
// FIXME import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.pde.internal.ui.wizards.tools.ConvertProjectToPluginOperation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard;
import org.occiware.clouddesigner.occi.OCCIRegistry;
import org.occiware.clouddesigner.occi.OcciCoreConstants;
import org.occiware.clouddesigner.occi.gen.connector.ui.Activator;
import org.occiware.clouddesigner.occi.gen.connector.ui.common.GenerateAll;
import org.occiware.clouddesigner.occi.util.Occi2Ecore;
/**
* The wizard to create a new OCCI connector project.
*
* @author Philippe Merle - Inria
*/
public class NewConnectorWizard extends BasicNewProjectResourceWizard {
private CheckboxTableViewer refExtensionViewer;
private final class NewExtensionWizardPage extends WizardNewProjectCreationPage {
private NewExtensionWizardPage(String pageName) {
super(pageName);
}
@Override
public void createControl(Composite parent) {
super.createControl(parent);
Composite control = (Composite) getControl();
Composite extensionGroup = new Composite(control, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
extensionGroup.setLayout(layout);
extensionGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Label refOccieLabel = new Label(extensionGroup, SWT.NONE);
refOccieLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
refOccieLabel.setText(Messages.NewConnectorWizard_RefExtensionLabel);
refOccieLabel.setFont(parent.getFont());
Composite composite = new Composite(extensionGroup, SWT.NULL);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
composite.setLayoutData(layoutData);
TableColumnLayout tableLayout = new TableColumnLayout();
composite.setLayout(tableLayout);
Table table = new Table(composite,
SWT.CHECK | SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
refExtensionViewer = new CheckboxTableViewer(table);
refExtensionViewer.setContentProvider(ArrayContentProvider.getInstance());
refExtensionViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
setPageComplete(validatePage());
}
});
Collection<String> registeredExtensions = new ArrayList<String>(
OCCIRegistry.getInstance().getRegisteredExtensions());
// removed the OCCI core extension as it is added by default.
registeredExtensions.remove(OcciCoreConstants.OCCI_CORE_SCHEME);
refExtensionViewer.setInput(registeredExtensions);
}
@Override
protected boolean validatePage() {
// TODO add error messages
return super.validatePage() && refExtensionViewer.getCheckedElements().length == 1;
}
}
protected NewExtensionWizardPage newProjectPage;
/**
* Create a default model then select it in the explorer and switch to
* modeling perspective. The project, the rootObjectName and the
* newUmlModelFileName must be initialized before calling the performFinish
* method. {@inheritDoc}
*/
@Override
public boolean performFinish() {
try {
getContainer().run(false, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
String selectExtensionScheme = (String)refExtensionViewer.getCheckedElements()[0];
createConnectorJavaProject(newProjectPage.getProjectName(), selectExtensionScheme, monitor);
} catch (CoreException e) {
Activator.getDefault().getLog()
.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
}
}
});
} catch (InvocationTargetException | InterruptedException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
}
return true;
}
private void createConnectorJavaProject(String connectorProjectName, String extensionScheme, IProgressMonitor monitor) throws CoreException
{
// Get the file containing the OCCI extension.
String extensionFile = OCCIRegistry.getInstance().getFileURI(extensionScheme);
// This connector project will require the bundle containing the OCCI extension.
// Warning extensionFile must be a platform URI (plugin or resource).
String tmp = extensionFile.substring("platform:/".length());
tmp = tmp.substring(tmp.indexOf('/')+1);
String requireBundle = tmp.substring(0, tmp.indexOf('/'));
// FIXME we suppose that the project name is equals to the bundle name.
IProject requireProject = ResourcesPlugin.getWorkspace().getRoot().getProject(requireBundle);
// See https://sdqweb.ipd.kit.edu/wiki/JDT_Tutorial:_Creating_Eclipse_Java_Projects_Programmatically
// Create an Eclipse project.
IProject connectorProject = ResourcesPlugin.getWorkspace().getRoot().getProject(connectorProjectName);
connectorProject.create(null);
connectorProject.open(null);
// Because we need a java project, we have to set the Java nature to the created project:
IProjectDescription description = connectorProject.getDescription();
description.setNatureIds(new String[] { JavaCore.NATURE_ID });
connectorProject.setDescription(description, null);
// Now we can create our Java project
IJavaProject javaProject = JavaCore.create(connectorProject);
// However, it's not enough if we want to add Java source code to the project. We have to set the Java build path:
// (1) We first specify the output location of the compiler (the bin folder):
IFolder binFolder = connectorProject.getFolder("bin");
binFolder.create(false, true, null);
javaProject.setOutputLocation(binFolder.getFullPath(), null);
// (2) Define the class path entries.
IClasspathEntry[] entries = new IClasspathEntry[ (requireProject.exists()) ? 3 : 2];
// Add JRE System Library.
entries[0] = JavaRuntime.getDefaultJREContainerEntry();
// (3) We have not yet the source folder created:
IFolder sourceFolder = connectorProject.getFolder("src");
sourceFolder.create(false, true, null);
// (4) Now the created source folder should be added to the class entries of the project, otherwise compilation will fail:
IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(sourceFolder);
entries[1] = JavaCore.newSourceEntry(root.getPath());
// Add the extension project.
if(requireProject.exists()) {
entries[2] = JavaCore.newSourceEntry(requireProject.getFullPath());
}
// (5) Set the Java build path.
javaProject.setRawClasspath(entries, null);
// Convert this project to a plugin project.
try {
new ConvertProjectToPluginOperation(new IProject[] { connectorProject }, false).run(monitor);
} catch (InvocationTargetException | InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Generate META-INF/MANIFEST.MF
IFile manifest = PDEProject.getManifest(connectorProject);
String manifestContent =
"Manifest-Version: 1.0\n" +
"Bundle-ManifestVersion: 2\n" +
"Bundle-Name: " + connectorProjectName + "\n" +
"Bundle-SymbolicName: " + connectorProjectName + ";singleton:=true\n" +
"Bundle-Version: 0.1.0.qualifier\n" +
"Bundle-ClassPath: .\n" +
"Bundle-Vendor: OCCIware\n" +
// "Bundle-Localization: plugin\n" + // FIXME generate plugin.properties
"Bundle-RequiredExecutionEnvironment: JavaSE-1.7\n" +
"Bundle-ActivationPolicy: lazy\n" +
"Require-Bundle: org.slf4j.api,\n" +
" org.occiware.clouddesigner.occi,\n" +
" " + requireBundle + "\n" +
"Export-Package: " + connectorProjectName + "\n";
manifest.setContents(new ByteArrayInputStream(manifestContent.getBytes()), true, false, monitor);
// Generate build.properties
IFile build = PDEProject.getBuildProperties(connectorProject);
String buildContent =
"# Copyright (c) 2016 Inria\n" +
"#\n" +
"# All rights reserved. This program and the accompanying materials\n" +
"# are made available under the terms of the Eclipse Public License v1.0\n" +
"# which accompanies this distribution, and is available at\n" +
"# http://www.eclipse.org/legal/epl-v10.html\n" +
"#\n" +
"# Contributors:\n" +
"# - Philippe Merle <philippe.merle@inria.fr>\n" +
"#\n" +
"\n" +
"source.. = src/\n" +
"output.. = bin/\n" +
"bin.includes = META-INF/, plugin.xml, .\n";
build.setContents(new ByteArrayInputStream(buildContent.getBytes()), true, false, monitor);
// Generate plugin.xml
IFile pluginXML = PDEProject.getPluginXml(connectorProject);
String pluginContent =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<?eclipse version=\"3.0\"?>\n" +
"<!--\n" +
" Copyright (c) 2016 Inria\n" +
"\n" +
" All rights reserved. This program and the accompanying materials\n" +
" are made available under the terms of the Eclipse Public License v1.0\n" +
" which accompanies this distribution, and is available at\n" +
" http://www.eclipse.org/legal/epl-v10.html\n" +
"\n" +
" Contributors:\n" +
" - Philippe Merle <philippe.merle@inria.fr>\n" +
"-->\n" +
"<plugin>\n" +
"\n" +
" <!-- Register the factory of this connector. -->\n" +
" <extension point=\"org.eclipse.emf.ecore.factory_override\">\n" +
" <factory\n" +
" uri=\"" + Occi2Ecore.convertOcciScheme2EcoreNamespace(extensionScheme) + "\"\n" +
" class=\"" + connectorProjectName + ".ConnectorFactory\"/>\n" +
" </extension>\n" +
"\n" +
"</plugin>\n";
pluginXML.create(new ByteArrayInputStream(pluginContent.getBytes()), true, monitor);
// Generate Java code for the connector.
try {
URI modelURI = URI.createURI(extensionFile, true);
// Generate Java code for the connector.
IContainer target = connectorProject.getFolder("src");
// Compute the arguments of the generator.
ArrayList<String> arguments = new ArrayList<String>();
// The full name of the package to generate.
arguments.add(connectorProjectName);
// The full name of the package to extend.
arguments.add(requireBundle);
// Call the generator.
GenerateAll generator = new GenerateAll(modelURI, target, arguments);
generator.doGenerate(monitor);
} catch (IOException e) {
IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
Activator.getDefault().getLog().log(status);
} finally {
connectorProject.refreshLocal(IResource.DEPTH_INFINITE, monitor);
}
}
@Override
public void addPages() {
// we're not calling the super as we want to control the project
// creation, we don't want the default
// page.
// super.addPages();
newProjectPage = new NewExtensionWizardPage(Messages.NewConnectorWizard_PageName);
newProjectPage.setInitialProjectName(""); //$NON-NLS-1$
newProjectPage.setTitle(Messages.NewConnectorWizard_PageTitle);
newProjectPage.setDescription(Messages.NewConnectorWizard_PageDescription);
addPage(newProjectPage);
}
}