builder和nature是Eclipse中提供的两个扩展点。一般来说我们都是先有自己特定的project类型,然后在这类project上加上自定义的builder和nature。
其实所谓的特定的project通常都是由特有的nature来标识的;而又一般builder是建立在某类特定的project上,所以我们可以得出:Nature决定了project和builder。
下面简单介绍一下它们的使用。
一、扩展Nature
首先定义nature的扩展,如下:
<extension
id="nature"
point="org.eclipse.core.resources.natures">
<runtime>
<run
class="com.tibco.cdc.liugang.npb.LiugangProjectNature">
</run>
</runtime>
</extension>
除此之处,nature还有一些其他的约束属性,具体的可以参见帮助。
LiugangProjectNature的实现如下:
public class LiugangProjectNature implements IProjectNature {
private IProject project;
public static final String ID = "com.tibco.cdc.liugang.npb.nature";
public void configure() throws CoreException {
}
public void deconfigure() throws CoreException {
}
public IProject getProject() {
return project;
}
public void setProject(IProject project) {
this.project = project;
}
}
注意:nature的ID为plugin的ID加上nature扩展的ID.
方法说明:
- setProject()会在project.setDescription()的时候调用,如果那个project的description安了这个nature
- configure()和deconfigure()方法会在nature安上和卸掉的时候调用,一会我们可以看到builder在其中是怎么用的。
- setProject()和configure()的调用顺序是先调setProject()后调configure().
二、生成Project
有了nature,下面就可以创建一个project,并把这个nature加到这个project上,如下 :
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);
这里,我写了一个通用类来处理nature,builder的增加和删除,我们先看这个addNature2Project()方法:
public static void addNature2Project(IProjectDescription description, String[] natureIds,
IProgressMonitor monitor) 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);
}
三、定义Builder
按最初我们说的,builder一般安装在具有某种特定nature的project上。这里我们定义一个builder的扩展,然后再修改一下nature的扩展。分别如下:
Nature:
<extension id="nature" point="org.eclipse.core.resources.natures"> <runtime> <run class="com.tibco.cdc.liugang.npb.LiugangProjectNature"> </run> </runtime> <builder id="com.tibco.cdc.liugang.npb.builder"> </builder> </extension>
Builder:
<extension id="builder" point="org.eclipse.core.resources.builders"> <builder callOnEmptyDelta="true" hasNature="true" isConfigurable="false"> <run class="com.tibco.cdc.liugang.npb.LiugangIncrementalProjectBuilder"> </run> </builder> </extension>
回到代码,这里假设builder由nature控制。所以builder的安装与卸载分别在nature的configure()方法和deconfigure()方法中实现,如下:
public void configure() throws CoreException {
IProjectDescription description = project.getDescription();
ProjectUtil.addBuilderToProject(description,
new String[] { LiugangIncrementalProjectBuilder.ID }, null);
project.setDescription(description, null);
}
public void deconfigure() throws CoreException {
IProjectDescription description = project.getDescription();
ProjectUtil.removeBuilderFromProject(description,
new String[] { LiugangIncrementalProjectBuilder.ID }, null);
project.setDescription(description, null);
}
其中ProjectUtil中的实现如下:
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);
}
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]));
}
这样完成了nature和builder的增加。最后,我们稍稍看一下builder的实现。
四、builder的实现
对于builder的实现来说,我们通常关心以下几个方法:
public class LiugangIncrementalProjectBuilder extends IncrementalProjectBuilder {
public static final String ID = "com.tibco.cdc.liugang.npb.builder";
public LiugangIncrementalProjectBuilder() {
}
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
return null;
}
@Override
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
}
@Override
protected void startupOnInitialize() {
super.startupOnInitialize();
}
}
build()方法中,一般会根据不同的build类型,来实现不同的build策略,例如:
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
switch (kind) {
case FULL_BUILD:
processFullBuild(monitor);
break;
default:
IResourceDelta delta = getDelta(project);
if (delta == null) {
processFullBuild(monitor);
} else {
processIncrementalBuild(delta, monitor);
}
break;
}
return null;
}
clean()方法,在clean动作执行时被调用,通常用于清理之前build的信息,然后build()方法会被调用。clean()方法通常可以如下实现:
@Override
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
/*
* remove all build files
*/
IFolder outputFiles = project.getFolder(FILES_OUTPUT_PATH);
outputFiles .refreshLocal(IResource.DEPTH_INFINITE, monitor);
if (outputFiles .exists()) {
outputFiles .delete(true, monitor);
}
}
startupOnInitialize()可以调用一些初始信息,或者初始变量,例如上面用到的project变量就可以如下:
@Override
protected void startupOnInitialize() {
super.startupOnInitialize();
this.project = getProject();
}
这样,一个完整的nature,builder的添加处理过程就实现了。