blob: 16c479f535262bfc82ea1e773cc14668b0e3d0a2 [file] [log] [blame]
/***************************************************************************************************
* Copyright (c) 2005 Eteration A.S. 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: Eteration A.S. - initial API and implementation
**************************************************************************************************/
package org.eclipse.jst.j2ee.ejb.annotations.internal.xdoclet;
import java.util.Map;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
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.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
public class XDocletBuilder extends IncrementalProjectBuilder implements IExecutableExtension {
private static final String JAVASOURCE_TYPE = "org.eclipse.jdt.core.javaSource"; //$NON-NLS-1$
private static final boolean performValidateEdit = false;
private static boolean isGloballyEnabled = true;
/**
* Add the XDocletBuilder to the build spec of a single IProject
*
* @param project -
* the IProject to add to, when needed
*/
public static void add(IProgressMonitor monitor, IProject project, Object validateEditContext) {
if (project == null || !project.isAccessible()) {
return;
}
boolean isBuilderPresent = false;
try {
IFile descriptionFile = project.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
if (descriptionFile.exists() && descriptionFile.isAccessible()) {
IProjectDescription description = project.getDescription();
ICommand[] commands = description.getBuildSpec();
if (commands != null) {
for (int i = 0; i < commands.length; i++) {
String builderName = commands[i].getBuilderName();
// builder name will be null if it has not been set
if (builderName != null && builderName.equals(getBuilderId())) {
isBuilderPresent = true;
break;
}
}
}
if (!isBuilderPresent && !monitor.isCanceled()) {
// validate for edit
IStatus status = null;
if (performValidateEdit) {
ISchedulingRule validateEditRule = null;
try {
IFile[] validateFiles = new IFile[] { descriptionFile };
IWorkspace workspace = descriptionFile.getWorkspace();
validateEditRule = workspace.getRuleFactory().validateEditRule(validateFiles);
Platform.getJobManager().beginRule(validateEditRule, monitor);
status = workspace.validateEdit(validateFiles, null);
} finally {
if (validateEditRule != null) {
Platform.getJobManager().endRule(validateEditRule);
}
}
}
if (status == null || status.isOK()) {
// add the builder
ICommand newCommand = description.newCommand();
newCommand.setBuilderName(getBuilderId());
ICommand[] newCommands = null;
if (commands != null) {
newCommands = new ICommand[commands.length + 1];
System.arraycopy(commands, 0, newCommands, 0, commands.length);
newCommands[commands.length] = newCommand;
} else {
newCommands = new ICommand[1];
newCommands[0] = newCommand;
}
description.setBuildSpec(newCommands);
/*
* This 'refresh' was added since unit tests were
* throwing exceptions about being out of sync. That may
* indicate a "deeper" problem such as needing to use
* scheduling rules, (although there don't appear to be
* examples of that) or something similar.
*/
// project.refreshLocal(IResource.DEPTH_ZERO,
// subMonitorFor(monitor, 1,
// IProgressMonitor.UNKNOWN));
try {
project.setDescription(description, monitor);
} catch (CoreException e) {
if (performValidateEdit) {
Logger
.log(
Logger.WARNING,
"Description for project \"" + project.getName() + "\" could not be updated despite successful build"); //$NON-NLS-2$//$NON-NLS-1$
} else {
Logger.log(Logger.WARNING,
"Description for project \"" + project.getName() + "\" could not be updated"); //$NON-NLS-2$//$NON-NLS-1$
}
}
}
}
} else {
Logger.log(Logger.WARNING, "Description for project \"" + project.getName() + "\" could not be updated"); //$NON-NLS-2$//$NON-NLS-1$
}
} catch (Exception e) {
// if we can't read the information, the project isn't open,
// so it can't run auto-validate
Logger.logException("Exception caught when adding Model Builder", e); //$NON-NLS-1$
}
}
/**
* Adds the Builder to every project in the Workspace
*
* @param root
*/
public synchronized static void add(IProgressMonitor monitor, IWorkspaceRoot root, Object validateEditContext) {
IProject[] allProjects = root.getProjects();
IProgressMonitor localMonitor = monitor;
localMonitor.beginTask("Starting to add builder to projects with EJB modules", 1); //$NON-NLS-1$
for (int i = 0; i < allProjects.length && !monitor.isCanceled(); i++) {
if (XDocletPreferenceStore.forProject(allProjects[i]).isPropertyActive(XDocletPreferenceStore.XDOCLETBUILDERACTIVE)) {
add(localMonitor, allProjects[i], validateEditContext);
}
localMonitor.worked(1);
}
localMonitor.done();
}
public static String getBuilderId() {
return "org.eclipse.jst.j2ee.ejb.annotations.internal.emitter.model.xdocletbuilder"; //$NON-NLS-1$
}
public static IProgressMonitor monitorFor(IProgressMonitor monitor) {
if (monitor == null)
return new NullProgressMonitor();
return monitor;
}
private String fName = "XDoclet Builder"; //$NON-NLS-1$
/**
*
*/
public XDocletBuilder() {
super();
}
/*
* (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 {
IProject currentProject = getProject();
// Currently, just use the Task Tags preference
boolean locallyEnabled = XDocletPreferenceStore.forProject(currentProject).isPropertyActive(
XDocletPreferenceStore.XDOCLETBUILDERACTIVE);
if (!locallyEnabled || currentProject == null || !currentProject.isAccessible()) {
return new IProject[] { currentProject };
}
IResourceDelta delta = getDelta(currentProject);
IProgressMonitor localMonitor = monitor;
localMonitor.beginTask(getDisplayName(), 1);
if (!localMonitor.isCanceled()) {
// check the kind of delta if one was given
if (kind == FULL_BUILD || kind == CLEAN_BUILD || delta == null) {
doFullBuild(kind, args, localMonitor, getProject());
} else {
doIncrementalBuild(kind, args, localMonitor);
}
}
localMonitor.worked(1);
localMonitor.done();
return new IProject[] { getProject() };
}
void build(int kind, Map args, IResource resource, IContentType[] types, IProgressMonitor monitor) {
if (!monitor.isCanceled() && resource.getType() == IResource.FILE) {
XDocletAntProjectBuilder antProjectBuilder = XDocletAntProjectBuilder.Factory.newInstance(resource);
if (antProjectBuilder != null)
antProjectBuilder.buildUsingAnt(resource, monitor);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
*/
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
IProject currentProject = getProject();
if (!isGloballyEnabled || currentProject == null || !currentProject.isAccessible()) {
return;
}
// doFullBuild(IncrementalProjectBuilder.CLEAN_BUILD, new HashMap(0),
// monitor, getProject());
}
boolean isXDocletAnnotatedResource(IResource resource) {
IContentType[] types = null;
if (resource.getType() == IResource.FILE && resource.isAccessible()) {
IContentDescription d = null;
try {
// optimized description lookup, might not succeed
d = ((IFile) resource).getContentDescription();
if (d != null && JAVASOURCE_TYPE.equals(d.getContentType().getId())) {
return XDoxletAnnotationUtil.isXDocletAnnotatedResource(resource);
}
} catch (CoreException e) {
// should not be possible given the accessible and file type
// check above
}
if (types == null) {
types = Platform.getContentTypeManager().findContentTypesFor(resource.getName());
for (int i = 0; i < types.length; i++) {
IContentType type = types[i];
if (JAVASOURCE_TYPE.equals(type.getId())) {
return XDoxletAnnotationUtil.isXDocletAnnotatedResource(resource);
}
}
}
return false;
} else if( resource.getType() == IResource.FILE && !resource.isAccessible()){
//Deleted - Check to see if this is an xdoclet bean!
// This is a crude hack to make sure the build runs is a resource is deleted.
String name = resource.getName();
boolean isXDocletBean = name.endsWith("Bean.java") ||name.endsWith("Servlet.java") || name.endsWith("Controller.java") || name.endsWith("EJB.java")|| name.endsWith("MDB.java") || name.endsWith("Ejb.java") || name.endsWith("Mdb.java") || name.endsWith("BEAN.java");
if(isXDocletBean)
return true;
}
return false;
}
/**
* Iterate through the list of resources and build each one
*
* @param monitor
* @param resources
*/
protected void doFullBuild(int kind, Map args, IProgressMonitor monitor, IProject project) {
final IProgressMonitor subMonitor = monitor;
final int localKind = kind;
final Map localArgs = args;
final IProgressMonitor visitorMonitor = monitor;
IResourceVisitor internalBuilder = new IResourceVisitor() {
// xdoclet builder completes the whole project at once so no need to
// repeat the build with each annotated bean. Stop after the first
// one
boolean buildComplete = false;
public boolean visit(IResource resource) throws CoreException {
if (resource.getType() == IResource.FILE && buildComplete == false) {
// for any supported file type, record the resource
if (!buildComplete && isXDocletAnnotatedResource(resource)) {
build(localKind, localArgs, resource, null, subMonitor);
buildComplete = true;
visitorMonitor.worked(1);
}
return false;
}
return true;
}
};
try {
project.accept(internalBuilder);
} catch (CoreException e) {
Logger.logException(e);
}
}
/**
*
*/
protected void doIncrementalBuild(int kind, Map args, IProgressMonitor monitor) {
IResourceDelta projectDelta = getDelta(getProject());
if (projectDelta == null) {
throw new IllegalArgumentException("delta is null, should do a full build"); //$NON-NLS-1$
}
final Map localArgs = args;
final int localKind = kind;
final IProgressMonitor localMonitor = monitor;
IResourceDeltaVisitor participantVisitor = new IResourceDeltaVisitor() {
// xdoclet builder completes the whole project at once so no need to
// repeat the build with each annotated bean. Stop after the first
// one
boolean buildComplete = false;
public boolean visit(IResourceDelta delta) throws CoreException {
if (!localMonitor.isCanceled() && delta.getResource().getType() == IResource.FILE) {
if (!buildComplete && isXDocletAnnotatedResource(delta.getResource())) {
build(localKind, localArgs, delta.getResource(), null, localMonitor);
buildComplete = true;
}
}
return delta.getAffectedChildren().length > 0;
}
};
try {
projectDelta.accept(participantVisitor);
} catch (CoreException e) {
Logger.logException(e);
}
monitor.worked(1);
}
private String getDisplayName() {
return fName;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
* java.lang.String, java.lang.Object)
*/
public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException {
if (config != null) {
fName = config.getDeclaringExtension().getLabel();
}
}
public static void shutdown() {
// Default
}
public static void startup() {
// Default
}
}