/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform 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 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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 the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.visitors;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
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.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourceAttributes;
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.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.whole.lang.artifacts.model.FileArtifact;
import org.whole.lang.artifacts.model.FolderArtifact;
import org.whole.lang.artifacts.model.LocationURI;
import org.whole.lang.artifacts.model.Nature;
import org.whole.lang.artifacts.model.Natures;
import org.whole.lang.artifacts.model.PackageArtifact;
import org.whole.lang.artifacts.model.Project;
import org.whole.lang.artifacts.model.Workspace;
import org.whole.lang.artifacts.reflect.ArtifactsEntityDescriptorEnum;
import org.whole.lang.artifacts.visitors.AbstractArtifactsGeneratorVisitor;
import org.whole.lang.codebase.IFilePersistenceProvider;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.InterpreterOperation;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.util.StringUtils;
/**
* @author Riccardo Solmi
*/
public class WorkspaceArtifactsGeneratorVisitor extends AbstractArtifactsGeneratorVisitor {
private IProgressMonitor progressMonitor;
public final IProgressMonitor progressMonitor() {
if (progressMonitor == null) {
progressMonitor = getOperation().getProgressMonitor().getAdapter(IProgressMonitor.class);
if (progressMonitor == null)
progressMonitor = new NullProgressMonitor();
}
return progressMonitor;
}
protected ISchedulingRule getSchedulingRule() {
ISchedulingRule rule = (ISchedulingRule) env().wGetValue(env().wIsSet("folder") ? "folder" : "project");
return rule;
}
protected boolean inWorkspaceRunnable;
public void visit(final Workspace entity) {
if (inWorkspaceRunnable)
visitWorkspace(entity);
else
try {
inWorkspaceRunnable = true;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRunnable operation = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
visitWorkspace(entity);
}
};
ISchedulingRule rule = workspace.getRoot();
env().wDefValue("schedulingRule", rule);
workspace.run(operation, rule, IWorkspace.AVOID_UPDATE, progressMonitor());
} catch (CoreException e) {
throw new VisitException(e);
} finally {
inWorkspaceRunnable = false;
}
}
public void visit(final Project entity) {
if (inWorkspaceRunnable)
visitProject(entity);
else
try {
inWorkspaceRunnable = true;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
IProject project = workspaceRoot.getProject(env().wStringValue("projectName"));
IWorkspaceRunnable operation = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
visitProject(entity);
}
};
ISchedulingRule rule = project.exists() ? project : workspaceRoot;
env().wDefValue("schedulingRule", rule);
workspace.run(operation, rule, IWorkspace.AVOID_UPDATE, progressMonitor());
} catch (CoreException e) {
throw new VisitException(e);
} finally {
inWorkspaceRunnable = false;
}
}
public void visit(final PackageArtifact entity) {
if (inWorkspaceRunnable)
visitPackageArtifact(entity);
else
try {
inWorkspaceRunnable = true;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRunnable operation = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
visitPackageArtifact(entity);
}
};
ISchedulingRule rule = getSchedulingRule();
env().wDefValue("schedulingRule", rule);
workspace.run(operation, rule, IWorkspace.AVOID_UPDATE, progressMonitor());
} catch (CoreException e) {
throw new VisitException(e);
} finally {
inWorkspaceRunnable = false;
}
}
public void visit(final FolderArtifact entity) {
if (inWorkspaceRunnable)
visitFolderArtifact(entity);
else
try {
inWorkspaceRunnable = true;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRunnable operation = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
visitFolderArtifact(entity);
}
};
ISchedulingRule rule = getSchedulingRule();
env().wDefValue("schedulingRule", rule);
workspace.run(operation, rule, IWorkspace.AVOID_UPDATE, progressMonitor());
} catch (CoreException e) {
throw new VisitException(e);
} finally {
inWorkspaceRunnable = false;
}
}
public void visit(final FileArtifact entity) {
if (inWorkspaceRunnable)
visitFileArtifact(entity);
else
try {
inWorkspaceRunnable = true;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRunnable operation = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
visitFileArtifact(entity);
}
};
ISchedulingRule rule = getSchedulingRule();
env().wDefValue("schedulingRule", rule);
workspace.run(operation, rule, IWorkspace.AVOID_UPDATE, progressMonitor());
} catch (CoreException e) {
throw new VisitException(e);
} finally {
inWorkspaceRunnable = false;
}
}
public void visitWorkspace(Workspace entity) {
env().wEnterScope();
entity.getMetadata().accept(this);
entity.getProjects().accept(this);
env().wExitScope();
}
public void visitProject(final Project entity) {
env().wUnset("folder"); // unset the default folder
env().wEnterScope();
if (!Matcher.matchImplAndBind(ArtifactsEntityDescriptorEnum.Name,
entity.getName(), env(), "projectName"))
throw new VisitException("No Project name");
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
String projectName = env().wStringValue("projectName");
IProject project = workspaceRoot.getProject(projectName);
try {
if (!project.exists()) {
LocationURI locationURI = entity.getLocationURI();
if (DataTypeUtils.getDataKind(locationURI).isString()) {
try {
IProjectDescription description =
workspace.newProjectDescription(projectName);
description.setLocationURI(new URI(locationURI.getValue()));
project.create(description, progressMonitor());
} catch (Exception e) {
throw new VisitException(e);
}
} else
project.create(progressMonitor());
}
project.open(progressMonitor());
env().wDefValue("project", project);
entity.getNatures().accept(this);
entity.getMetadata().accept(this);
if (project.hasNature(JavaCore.NATURE_ID))
env().wDefValue("javaProject", JavaCore.create(project));
entity.getArtifacts().accept(this);
} catch (CoreException e) {
throw new VisitException(e);
}
env().wExitScope();
}
public void visit(Natures entity) {
int size = entity.wSize();
if (size == 0)
return;
String[] natures = new String[size];
for (int i = 0; i < size; i++) {
IEntity nature = entity.wGet(i);
if (!EntityUtils.isResolver(nature)) {
((Nature) nature).accept(this);
natures[i] = env().wStringValue("nature");
}
}
IProject project = (IProject) env().wGetValue("project");
IProjectDescription desc = null;
String[] oldNatures = null;
try {
desc = project.getDescription();
oldNatures = desc.getNatureIds();
desc.setNatureIds(natures);
project.setDescription(desc, progressMonitor());
} catch (CoreException e) {
if (desc != null && oldNatures != null) {
desc.setNatureIds(natures);
try {
project.setDescription(desc, progressMonitor());
} catch (CoreException e1) {
}
}
//TODO show error nature not available
}
}
public void visit(Nature entity) {
env().wDefValue("nature", entity.wStringValue());
}
public void visitPackageArtifact(PackageArtifact entity) {
env().wEnterScope();
if (!Matcher.matchImplAndBind(ArtifactsEntityDescriptorEnum.Name,
entity.getName(), env(), "packageName"))
throw new VisitException("No Package name");
entity.getMetadata().accept(this);
try {
IPath path;
if (env().wIsSet("folder")) {
IFolder parentFolder = (IFolder) env().wGetValue("folder");
path = parentFolder.getFullPath();
} else {
IProject project = (IProject) env().wGetValue("project");
path = project.getFullPath();
}
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IFolder folder = null;
String[] packagePath = env().wStringValue("packageName").split("\\.");
for (int i = 0; i < packagePath.length; i++) {
path = path.append(packagePath[i]);
folder = workspaceRoot.getFolder(path);
if (!folder.exists())
folder.create(true, true, progressMonitor());
}
env().wDefValue("folder", folder);
if (env().wIsSet("derived"))
folder.setDerived(true, progressMonitor());
if (env().wIsSet("readonly")) {
ResourceAttributes attributes = folder.getResourceAttributes();
if (attributes != null) {
attributes.setReadOnly(true);
folder.setResourceAttributes(attributes);
}
}
} catch (CoreException e) {
throw new VisitException(e);
// } catch (NullPointerException e) {
// throw new VisitException("No Project");
}
entity.getArtifacts().accept(this);
env().wExitScope();
}
public void visitFolderArtifact(FolderArtifact entity) {
env().wEnterScope();
if (!Matcher.matchImplAndBind(ArtifactsEntityDescriptorEnum.Name,
entity.getName(), env(), "folderName"))
throw new VisitException("No Folder name");
entity.getMetadata().accept(this);
try {
IPath path;
if (env().wIsSet("folder")) {
IFolder parentFolder = (IFolder) env().wGetValue("folder");
path = parentFolder.getFullPath();
} else {
IProject project = (IProject) env().wGetValue("project");
path = project.getFullPath();
}
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IFolder folder = null;
String[] folderPath = env().wStringValue("folderName").split("/");
for (int i = 0; i < folderPath.length; i++) {
path = path.append(folderPath[i]);
folder = workspaceRoot.getFolder(path);
if (!folder.exists())
folder.create(true, true, progressMonitor());
}
env().wDefValue("folder", folder);
if (env().wIsSet("derived"))
folder.setDerived(true, progressMonitor());
if (env().wIsSet("readonly")) {
ResourceAttributes attributes = folder.getResourceAttributes();
if (attributes != null) {
attributes.setReadOnly(true);
folder.setResourceAttributes(attributes);
}
}
if (env().wLocalNames().contains("source") && env().wIsSet("javaProject")) {
List<IClasspathEntry> classpathEntries = new ArrayList<IClasspathEntry>();
IJavaProject javaProject = (IJavaProject) env().wGetValue("javaProject");
classpathEntries.addAll(Arrays.asList(javaProject.getRawClasspath()));
IClasspathEntry sourceEntry = JavaCore.newSourceEntry(folder.getFullPath());
if (classpathEntries.size() == 1 && ((IClasspathEntry) classpathEntries.get(0)).getPath().equals(javaProject.getPath()))
classpathEntries.remove(0);
else
for (Iterator<IClasspathEntry> i = classpathEntries.iterator(); i.hasNext();) {
IClasspathEntry entry = i.next();
if (entry.getPath().equals(sourceEntry.getPath()))
i.remove();
}
classpathEntries.add(0, sourceEntry);
javaProject.setRawClasspath(
(IClasspathEntry[]) classpathEntries
.toArray(new IClasspathEntry[classpathEntries.size()]),
progressMonitor());
}
} catch (CoreException e) {
throw new VisitException(e);
// } catch (NullPointerException e) {
// throw new VisitException("No Project");
}
entity.getArtifacts().accept(this);
env().wExitScope();
}
public void visitFileArtifact(FileArtifact entity) {
env().wEnterScope();
entity.getName().accept(this);
if (!env().wIsSet("name"))
throw new VisitException("No File name");
String fileNameWithExtension = env().wStringValue("name");
if (!ResourcesPlugin.getWorkspace().validateName(fileNameWithExtension, IResource.FILE).isOK())
throw new VisitException("Invalid File name");
env().wDefValue("fileNameWithExtension", fileNameWithExtension);
env().wDefValue("fileName", StringUtils.stripFileExtension(fileNameWithExtension));
env().wDefValue("fileExtension", StringUtils.getFileExtension(fileNameWithExtension));
entity.getMetadata().accept(this);
IFile file;
if (env().wIsSet("folder")) {
IFolder folder = (IFolder) env().wGetValue("folder");
file = folder.getFile(fileNameWithExtension);
} else {
IProject project = (IProject) env().wGetValue("project");
file = project.getFile(fileNameWithExtension);
}
env().wDefValue("persistenceProvider", new IFilePersistenceProvider(file, env()));
IEntity result = InterpreterOperation.interpret(entity.getContent(), env()).getResult();
try {
if (result != null)
writeContents(result);
} catch (Exception e) {
throw new VisitException(e);
}
env().wExitScope();
}
}