builder和nature是Eclipse中提供的两个扩展点。一般来说我们都是先有自己特定的project类型,然后在这类project上加上自定义的builder和nature。
其实所谓的特定的project通常都是由特有的nature来标识的;而又一般builder是建立在某类特定的project上,所以我们可以得出:Nature决定了project和builder。
1、创建nature扩展点
<extension
id="nature"
name="WorkFlow Project Nature"
point="org.eclipse.core.resources.natures">
<runtime>
<run
class="com.workflow.nature.WorkflowProjectNature">
</run>
</runtime>
<builder
id="MyDesigner.builder"><!--builder的扩展点ID为plugin的ID加上builder扩展的ID-->
</builder>
</extension>
2、创建builder扩展点
<extension
id="builder"
name="WorkFlow Project Builder"
point="org.eclipse.core.resources.builders">
<builder
hasNature="true"
isConfigurable="false">
<run
class="com.workflow.builder.ProjectBuilder">
</run>
</builder>
</extension>
3、nature的实现类
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.runtime.CoreException;
import com.workflow.builder.ProjectBuilder;
import com.workflow.tool.ProjectUtil;
/**
* 自定义的nature实现类
* @author lww
*
*/
public class WorkflowProjectNature implements IProjectNature {
private IProject project;
public static final String ID = "MyDesigner.nature";//nature的ID为plugin的ID加上nature扩展的ID
/**
* builder安装
*/
@Override
public void configure() throws CoreException {
IProjectDescription description = project.getDescription();
ProjectUtil.addBuilderToProject(description,
new String[] { ProjectBuilder.ID }, null);
project.setDescription(description, null);
}
/**
* builder卸载
*/
@Override
public void deconfigure() throws CoreException {
IProjectDescription description = project.getDescription();
ProjectUtil.removeBuilderFromProject(description,
new String[] { ProjectBuilder.ID }, null);
project.setDescription(description, null);
}
@Override
public IProject getProject() {
return project;
}
@Override
public void setProject(IProject project) {//在project.setDescription()的时候调用,如果那个project的description安了这个nature
this.project = project;
}
}
4、builder的实现类
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
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.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.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
*自定义 builder实现类
*org.eclipse.core.resources.builders用于提供一种操作,
*这种操作可以在IResource改变的时候自动去build,如同改变java文件,会自动进行build,
*显示错误一样,我们扩展这个builder,并且在自己的项目中使用。我们要做的就是实现build的过程,
*至于时机由eclipse控制
* @author lww
*
*/
public class ProjectBuilder extends IncrementalProjectBuilder {
private IProject project;
public static final String ID = "MyDesigner.builder";// Builder的ID为plugin的ID加上Builder扩展的ID.
private static final String MARKER_TYPE = "MyDesigner.xmlProblem";
private SAXParserFactory parserFactory;
/**
* 根据不同的build类型,来实现不同的build策略
*/
@Override
protected IProject[] build(int kind, Map<String, String> args,
IProgressMonitor monitor) throws CoreException {
switch (kind) {
case FULL_BUILD:
fullBuild(monitor);
break;
default:
IResourceDelta delta = getDelta(project);
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
break;
}
return null;
}
/**
* 点击project 菜单栏中clean Action的时候执行该方法
*/
@Override
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
/*
* remove all build files
*/
IFolder outputFiles = project.getFolder("Processes");
outputFiles.refreshLocal(IResource.DEPTH_INFINITE, monitor);
if (outputFiles.exists()) {
outputFiles.delete(true, monitor);
}
}
/**
* 调用一些初始信息,或者初始变量
*/
@Override
protected void startupOnInitialize() {
super.startupOnInitialize();
this.project = getProject();
}
/**
* 添加 标识,在Markers视图中显示该错误
* @param file
* @param message
* @param lineNumber
* @param severity
*/
private void addMarker(final IFile file, String message, int lineNumber,
int severity) {
try {
IMarker marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, severity);
if (lineNumber == -1) {
lineNumber = 1;
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
} catch (CoreException e) {
}
}
/**
* 检查文件后缀为.xml
* @param resource
*/
void checkXML(IResource resource) {
if (resource instanceof IFile && resource.getName().endsWith(".xml")) {
IFile file = (IFile) resource;
deleteMarkers(file);
XMLErrorHandler reporter = new XMLErrorHandler(file);
try {
getParser().parse(file.getContents(), reporter);
} catch (Exception e1) {
}
}
}
/**
* 删除Markers
* @param file
*/
private void deleteMarkers(IFile file) {
try {
file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
} catch (CoreException ce) {
}
}
private SAXParser getParser() throws ParserConfigurationException,
SAXException {
if (parserFactory == null) {
parserFactory = SAXParserFactory.newInstance();
}
return parserFactory.newSAXParser();
}
protected void fullBuild(final IProgressMonitor monitor)
throws CoreException {
try {
getProject().accept(new WorkFlowResourceVisitor());
} catch (CoreException e) {
}
}
protected void incrementalBuild(IResourceDelta delta,
IProgressMonitor monitor) throws CoreException {
// the visitor does the work.
delta.accept(new WorkFlowDeltaVisitor());
}
class WorkFlowDeltaVisitor implements IResourceDeltaVisitor {
@Override
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
switch (delta.getKind()) {
case IResourceDelta.ADDED:
// handle added resource
checkXML(resource);
break;
case IResourceDelta.REMOVED:
// handle removed resource
break;
case IResourceDelta.CHANGED:
// handle changed resource
checkXML(resource);
break;
}
// return true to continue visiting children.
return true;
}
}
class WorkFlowResourceVisitor implements IResourceVisitor {
@Override
public boolean visit(IResource resource) throws CoreException {
checkXML(resource);
return true;
}
}
class XMLErrorHandler extends DefaultHandler {
private IFile file;
public XMLErrorHandler(IFile file) {
this.file = file;
}
private void addMarker(SAXParseException e, int severity) {
ProjectBuilder.this.addMarker(file, e.getMessage(),
e.getLineNumber(), severity);
}
public void error(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
public void fatalError(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
public void warning(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_WARNING);
}
}
}
5、操作类
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* project的操作类(添加nature、builder)
* @author lww
*
*/
public class ProjectUtil {
/**
* 添加Nature信息到Project中
* 添加Comment信息
*/
public static void addNature2Project(IProjectDescription description, String[] natureIds) throws CoreException {
String[] prevNatures = description.getNatureIds();
String[] newNatures = new String[prevNatures.length + natureIds.length];
System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
for(int i = prevNatures.length;i<newNatures.length;i++){
newNatures[i] = natureIds[i-prevNatures.length];
}
description.setNatureIds(newNatures);
description.setComment("It's a WorkFlow project");
}
/**
* 添加builder到project中
* @param description
* @param builderIds
* @param monitor
* @throws CoreException
*/
public static void addBuilderToProject(IProjectDescription description,
String[] builderIds, IProgressMonitor monitor) throws CoreException {
ICommand[] buildSpec = description.getBuildSpec();
ICommand[] newBuilders = new ICommand[buildSpec.length
+ builderIds.length];
System.arraycopy(buildSpec, 0, newBuilders, 0, buildSpec.length);
for (int i = buildSpec.length; i < newBuilders.length; i++) {
ICommand command = description.newCommand();
command.setBuilderName(builderIds[i - buildSpec.length]);
newBuilders[i] = command;
}
description.setBuildSpec(newBuilders);
}
/**
* 移除builder从project中
* @param description
* @param builderIds
* @param monitor
*/
public static void removeBuilderFromProject(
IProjectDescription description, String[] builderIds,
IProgressMonitor monitor) {
ICommand[] buildSpec = description.getBuildSpec();
List<ICommand> newBuilders = new ArrayList<ICommand>();
for (ICommand command : buildSpec) {
boolean find = false;
for (String id : builderIds) {
if (command.getBuilderName().equals(id)) {
find = true;
break;
}
}
if (!find) {
newBuilders.add(command);
}
}
description.setBuildSpec(newBuilders.toArray(new ICommand[0]));
}
}
org.eclipse.core.resources.builders用于提供一种操作,这种操作可以在IResource改变的时候自动去build,如同改变java文件,会自动进行build,显示错误一样,我们扩展这个builder,并且在自己的项目中使用。我们要做的就是实现build的过程,至于时机由eclipse控制
上面的例子就在修改文件时,验证XML文件内容格式是否存在问题,并显示在markers视图中显示,所以还要添加扩展点org.eclipse.core.resources.markers。
6、markers扩展点
<extension
id="xmlProblem"
name="com.workflow.xmlProblem"
point="org.eclipse.core.resources.markers">
<persistent
value="true">
</persistent>
<super
type="org.eclipse.core.resources.problemmarker">
</super>
</extension>
7、创建工程
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
String projectName = "TestNPB";
IProject project = root.getProject(projectName);
if (!project.exists()) {
project.create(null);
project.open(null);
}
IProjectDescription description = project.getDescription();
ProjectUtil.addNature2Project(description, new String[]{LiugangProjectNature.ID}, null);
project.setDescription(description, null);
创建的工程变为
.project文件中多了buildSpec和natures
当修改后缀名为.xml的文件后,保存,它就会去检查xml文件内容,若内容存在问题就在markers中显示错误信息