package fr.inria.diverse.k3.ui.builder;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.osgi.framework.BundleException;
import fr.inria.diverse.commons.eclipse.pde.manifest.ManifestChanger;
import fr.inria.diverse.commons.eclipse.pde.manifest.ManifestChangerExportPackage;
import fr.inria.diverse.commons.eclipse.pde.manifest.ManifestChangerPluginDependency;
import fr.inria.diverse.k3.ui.Activator;
/**
* This builder is for handling automated and incremental build of K3 elements that
* aren't already taken into account by the xTend annotation processor
*
*/
public class K3Builder extends IncrementalProjectBuilder {
class K3BuilderDeltaVisitor implements IResourceDeltaVisitor {
/*
* (non-Javadoc)
*
* @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
*/
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
switch (delta.getKind()) {
case IResourceDelta.ADDED:
// handle added resource
checkAspectJNature(resource);
break;
case IResourceDelta.REMOVED:
// handle removed resource
break;
case IResourceDelta.CHANGED:
// handle changed resource
if(_aspectMappingPropertiesChecker == null){
_aspectMappingPropertiesChecker = new AspectMappingPropertiesChecker(K3Builder.this);
}
_aspectMappingPropertiesChecker.checkK3AspectMappingPropertiesForGeneratedJava(resource);
if (resource instanceof IFile && resource.getName().endsWith(".xtend")) {
IProject project = resource.getProject();
if(project.hasNature("org.eclipse.pde.PluginNature")){
IFolder root = project.getFolder("xtend-gen");
Set<String> packs = findPackage(root);
updateManifest(project, packs);
}
}
break;
}
//return true to continue visiting children.
return true;
}
private void updateManifest(IProject project, Set<String> packs) {
IFile manifest = project.getFile("META-INF/MANIFEST.MF");
ManifestChanger changer = new ManifestChanger(manifest);
ManifestChangerExportPackage updater = new ManifestChangerExportPackage(changer);
for(String pack : packs){
try {
updater.add(pack);
changer.commit();
} catch (BundleException e) {
Activator.logErrorMessage(e.getMessage(), e);
} catch (IOException e) {
Activator.logErrorMessage(e.getMessage(), e);
} catch (CoreException e) {
Activator.logErrorMessage(e.getMessage(), e);
}
}
}
/**
* Search for package in @resource.
* Return empty list if none.
*
* @param resource Explored resource
* @param folderName Name of the containing package
*/
private Set<String> findPackage(IFolder root) {
Set<String> res = new HashSet<String>();
try {
for(IResource member : root.members()){
if(member.getType() == IResource.FOLDER){
Set<String> subRes = findPackageRec(member, member.getName());
res.addAll(subRes);
}
}
} catch (CoreException e) {Activator.logErrorMessage(e.getMessage(), e);}
return res;
}
/**
* Recursive search for package in @resource.
* Return empty list if none.
*
* @param resource Explored resource
* @param folderName Name of the containing package
*/
private Set<String> findPackageRec(IResource resource, String packageName) {
Set<String> res = new HashSet<String>();
if(resource.getType() == IResource.FOLDER){
try {
for(IResource member : ((IFolder)resource).members()){
if(member.getType() == IResource.FOLDER){
Set<String> subRes = findPackageRec(member, packageName+"."+member.getName());
res.addAll(subRes);
}
else if(member.getType() == IResource.FILE && member.getFileExtension().equals("java")){
res.add(packageName);
}
}
} catch (CoreException e) {Activator.logErrorMessage(e.getMessage(), e);}
}
return res;
}
private boolean hasAjFile(IResource resource) {
if(resource.getType() == IResource.FOLDER){
try {
for(IResource member : ((IFolder)resource).members()){
if(member.getType() == IResource.FOLDER){
if(hasAjFile(member)){
return true;
}
}
else if(member.getType() == IResource.FILE && member.getFileExtension().equals("aj")){
return true;
}
}
} catch (CoreException e) {Activator.logErrorMessage(e.getMessage(), e);}
}
return false;
}
}
protected AspectMappingPropertiesChecker _aspectMappingPropertiesChecker;
class K3BuilderResourceVisitor implements IResourceVisitor {
public boolean visit(IResource resource) {
if(_aspectMappingPropertiesChecker == null){
_aspectMappingPropertiesChecker = new AspectMappingPropertiesChecker(K3Builder.this);
}
_aspectMappingPropertiesChecker.checkK3AspectMappingPropertiesForGeneratedJava(resource);
try {
checkAspectJNature(resource);
} catch (CoreException e) {
Activator.logErrorMessage(e.getMessage(), e);
}
//return true to continue visiting children.
return true;
}
}
public static final String BUILDER_ID = "fr.inria.diverse.k3.ui.k3Builder";
private static final String MARKER_TYPE = "fr.inria.diverse.k3.ui.k3Problem";
protected void checkAspectJNature(IResource resource) throws CoreException{
if (resource instanceof IFile && resource.getName().endsWith(".aj")) {
IProject project = resource.getProject();
if(!project.hasNature("org.eclipse.ajdt.ui.ajnature")){
//Add nature
try {
IProjectDescription desc = project.getDescription();
String[] prevNatures = desc.getNatureIds();
String[] newNatures = new String[prevNatures.length + 1];
System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
newNatures[prevNatures.length] = "org.eclipse.ajdt.ui.ajnature";
desc.setNatureIds(newNatures);
project.setDescription(desc, new NullProgressMonitor());
} catch (CoreException e) {
Activator.logErrorMessage(e.getMessage(), e);
}
//Add Aspectj dependency
try {
if(project.hasNature("org.eclipse.pde.PluginNature")){
IFile manifest = project.getFile("META-INF/MANIFEST.MF");
ManifestChanger changer = new ManifestChanger(manifest);
ManifestChangerPluginDependency updater = new ManifestChangerPluginDependency(changer);
updater.add("org.aspectj.runtime");
changer.commit();
}
} catch (BundleException e) {
Activator.logErrorMessage(e.getMessage(), e);
} catch (IOException e) {
Activator.logErrorMessage(e.getMessage(), e);
}
}
}
}
/**
* convenient method for marking file associated with this builder
* @param file
* @param message
* @param lineNumber
* @param severity
*/
public void addMarker(IFile file, String message, int lineNumber,
int severity) {
try {
IMarker marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, severity);
if (lineNumber == -1) {
lineNumber = 1;
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
} catch (CoreException e) {
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.internal.events.InternalBuilder#build(int,
* java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
if (kind == FULL_BUILD) {
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
}
return null;
}
protected void clean(IProgressMonitor monitor) throws CoreException {
// delete markers set and files created
getProject().deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_INFINITE);
// delete properties file
IFile mappingPropertyFile = getProject().getFile("/META-INF/xtend-gen/"+getProject().getName()+".k3_aspect_mapping.properties");
if(mappingPropertyFile.exists()){
mappingPropertyFile.delete(true, monitor);
}
}
/**
* convenient method for removing marks associated with this builder
* @param file
* @param message
* @param lineNumber
* @param severity
*/
public void deleteMarkers(IFile file) {
try {
file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
} catch (CoreException ce) {
}
}
protected void fullBuild(final IProgressMonitor monitor)
throws CoreException {
try {
getProject().accept(new K3BuilderResourceVisitor());
} catch (CoreException e) {
}
}
/*
private SAXParser getParser() throws ParserConfigurationException,
SAXException {
if (parserFactory == null) {
parserFactory = SAXParserFactory.newInstance();
}
return parserFactory.newSAXParser();
}*/
protected void incrementalBuild(IResourceDelta delta,
IProgressMonitor monitor) throws CoreException {
// the visitor does the work.
delta.accept(new K3BuilderDeltaVisitor());
}
}