/*******************************************************************************
* Copyright (c) 2009, 2014 Borland Software Corporation and others.
*
* 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:
* Borland Software Corporation - initial API and implementation
* Christopher Gerking - bugs 319078, 414662
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.ui.wizards.project;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Arrays;
import org.eclipse.core.filesystem.URIUtil;
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.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
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.SubMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.m2m.internal.qvt.oml.ui.QVTUIPlugin;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
class NewProjectCreationOperation extends WorkspaceModifyOperation {
private static final String BUILD_FILENAME_DESCRIPTOR = "build.properties"; //$NON-NLS-1$
private static final String PLUGIN_NATURE = "org.eclipse.pde.PluginNature"; //$NON-NLS-1$
// instance fields
private PluginClassCodeGenerator fGenerator;
private NewProjectData fData;
private IProject fProjectHandle;
public NewProjectCreationOperation(IProject projectHandle, NewProjectData projectData) {
if(projectHandle == null || projectData == null) {
throw new IllegalArgumentException();
}
fData = projectData;
fProjectHandle = projectHandle;
}
protected void createContents(IProgressMonitor monitor, IProject project) throws CoreException, InterruptedException {
}
private void createBuildProperties(IProject project, IProgressMonitor monitor) throws CoreException {
IFile buildProperties = project.getFile(BUILD_FILENAME_DESCRIPTOR);
StringWriter contents = new StringWriter();
PrintWriter wr = new PrintWriter(contents, true);
if(fData.isCreateJava()) {
IPath sourceFolder = asBinIncludesFolder(createJavaFolder(fData.getSourceFolderName(), monitor));
IPath outFolder = asBinIncludesFolder(createJavaFolder(fData.getOutFolderName(), monitor));
wr.append("source.. = ").println(sourceFolder.toString()); //$NON-NLS-1$
wr.append("output.. = ").println(outFolder.toString()); //$NON-NLS-1$
}
char[] alignChars = new char[15];
Arrays.fill(alignChars, ' ');
String indent = new String(alignChars);
wr.print("bin.includes = META-INF/"); //$NON-NLS-1$
if(fData.isCreateJava()) {
wr.println(",\\"); //$NON-NLS-1$
wr.append(indent).append('.');
}
IContainer qvtContainer = createJavaFolder(fData.getQVTSourceFolderName(), monitor);
IPath qvtFolder = asBinIncludesFolder(qvtContainer);
if(!fProjectHandle.equals(qvtContainer) || !fData.isCreateJava()) {
wr.println(",\\"); //$NON-NLS-1$
wr.append(indent).append(qvtFolder.toString());
}
wr.println();
wr.flush();
InputStream is = createContentStreamForNewFile(buildProperties, contents.getBuffer().toString());
buildProperties.create(is, false, monitor);
}
private void createManifest(IFolder metaFolder, IProgressMonitor monitor) throws CoreException {
IFile manifest = metaFolder.getFile("MANIFEST.MF"); //$NON-NLS-1$
StringWriter contents = new StringWriter();
PrintWriter wr = new PrintWriter(contents, true);
wr.println("Manifest-Version: 1.0"); //$NON-NLS-1$
wr.println("Bundle-ManifestVersion: 2"); //$NON-NLS-1$
wr.append("Bundle-Name: ").println(fData.getName()); //$NON-NLS-1$
wr.append("Bundle-SymbolicName: ").println(fData.getID()); //$NON-NLS-1$
wr.append("Bundle-Version: ").println(fData.getVersion()); //$NON-NLS-1$
if (fData.isDoGenerateClass() && fData.getClassName().length() > 0) {
wr.append("Bundle-Activator: ").println(fData.getClassName()); //$NON-NLS-1$
}
if (fData.getProviderName().length() > 0) {
wr.append("Bundle-Vendor: ").println(fData.getProviderName()); //$NON-NLS-1$
}
PluginReference[] dependencies = getDependencies();
if (dependencies.length > 0) {
wr.append("Require-Bundle:"); //$NON-NLS-1$
int i = 0;
for (PluginReference pluginReference : dependencies) {
if (i++ > 0) {
wr.println(',');
}
wr.append(' ');
wr.append(pluginReference.getId());
}
wr.println();
}
if (fData.isCreateJava()) {
String requiredEnv = JdtProjectIntegrationHelper.getRequiredExecutionEnv(fData.getfExecutionEnv());
if (requiredEnv != null) {
wr.println(requiredEnv);
}
}
wr.println("Bundle-ActivationPolicy: lazy"); //$NON-NLS-1$
wr.flush();
InputStream is = createContentStreamForNewFile(manifest, contents.getBuffer().toString());
manifest.create(is, false, monitor);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.actions.WorkspaceModifyOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException {
SubMonitor progress = SubMonitor.convert(monitor, Messages.NewProjectCreationOperation_createQVTProjectTask, 2);
createProject(progress.newChild(1));
createContents(progress.newChild(1), fProjectHandle);
monitor.done();
}
private void generateTopLevelPluginClass(IProgressMonitor monitor) throws CoreException {
fGenerator.generate(monitor);
monitor.done();
}
private PluginReference[] getDependencies() {
if (fGenerator == null) {
return new PluginReference[0];
}
return fGenerator.getDependencies();
}
private void createProject(IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, 7);
URI location = URIUtil.toURI(fData.getLocation());
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IProjectDescription description = workspace.newProjectDescription(fProjectHandle.getName());
if (location != null && ResourcesPlugin.getWorkspace().getRoot().getLocationURI().equals(location)) {
location = null;
}
description.setLocationURI(location);
if(!fProjectHandle.exists()) {
fProjectHandle.create(description, subMonitor.newChild(1));
}
subMonitor.setWorkRemaining(6);
if (subMonitor.isCanceled()) {
throw new OperationCanceledException();
}
fProjectHandle.open(IResource.BACKGROUND_REFRESH, subMonitor.newChild(1));
if (fData.isPlugin()) {
addNatureToProject(fProjectHandle, PLUGIN_NATURE, subMonitor.newChild(1));
fGenerator = new PluginClassCodeGenerator(fProjectHandle, fData);
if(fData.isCreateJava()) {
JdtProjectIntegrationHelper.setupJava(fProjectHandle, true,
fData.getSourceFolderName(), fData.getOutFolderName(), fData.getfExecutionEnv(), subMonitor.newChild(1));
if(fData.isDoGenerateClass()) {
generateTopLevelPluginClass(new SubProgressMonitor(monitor, 1));
}
monitor.worked(1);
}
subMonitor.setWorkRemaining(3);
// generate the manifest file
IFolder metaFolder = fProjectHandle.getFolder("META-INF"); //$NON-NLS-1$
metaFolder.create(true, true, subMonitor.newChild(1));
createManifest(metaFolder, subMonitor.newChild(1));
// generate the build.properties file
createBuildProperties(fProjectHandle, subMonitor.newChild(1));
} else if(fData.isCreateJava()) {
subMonitor.setWorkRemaining(1);
JdtProjectIntegrationHelper.setupJava(fProjectHandle, false,
fData.getSourceFolderName(), fData.getOutFolderName(), fData.getfExecutionEnv(), subMonitor.newChild(1));
if(fData.isDoGenerateClass()) {
generateTopLevelPluginClass(new SubProgressMonitor(monitor, 1));
}
monitor.worked(1);
}
}
private void addNatureToProject(IProject proj, String natureId, IProgressMonitor monitor) throws CoreException {
IProjectDescription description = proj.getDescription();
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);
proj.setDescription(description, monitor);
}
private InputStream createContentStreamForNewFile(IFile fileHandle, String contents) {
String charset = null;
try {
charset = fileHandle.getProject().getDefaultCharset();
} catch (CoreException e) {
QVTUIPlugin.log(e.getStatus());
}
if(charset == null) {
charset = ResourcesPlugin.getEncoding();
}
byte[] bytes;
try {
bytes = contents.getBytes(charset);
} catch (UnsupportedEncodingException e) {
bytes = contents.getBytes();
}
return new ByteArrayInputStream(bytes);
}
private IPath asBinIncludesFolder(IContainer container) {
if(container.equals(fProjectHandle)) {
return new Path("."); //$NON-NLS-1$
}
IPath result = container.getProjectRelativePath();
while(result.hasTrailingSeparator()) {
result = result.removeTrailingSeparator();
}
// ensure single trailing slash
return result.addTrailingSeparator();
}
private IContainer createJavaFolder(String folderName, IProgressMonitor monitor) throws CoreException {
if(folderName == null || folderName.trim().length() == 0) {
return fProjectHandle;
}
IFolder folder = fProjectHandle.getFolder(folderName);
if(!folder.exists()) {
folder.create(true, true, monitor);
}
return folder;
}
}