Monday, September 14, 2009

Implementing Incremental Project Builder for an Eclipse Web Runtime Plugin

In order to develop an Eclipse Plugin, you will need to install the Eclipse Plugin Development Environment (PDE) and for web development, you will need to install Eclipse Web Tools Platform (WTP).
This article discusses two major mechanisms that are associated with projects in an Eclipse workspace. The first of these is incremental project builders, which create a built state based on the project contents, and then keep that built state synchronized as the project contents change. The second is project natures, which define and manage the association between a given project and a particular plug-in or feature.



  • Builder - Builders take raw materials and produce some output based on those materials. In Eclipse, both the raw materials and the output of builders are resources in the Eclipse workspace.
  • Incremental - It would be inefficient if builders rebuilt their entire output from scratch every time they were invoked. Instead, builders in Eclipse are incremental. This means that after the first build, subsequent builds should only rebuild based on what has changed since the last build.
  • Project - A builder operates on the resources in a single project in the Eclipse workspace. If there are many projects in the workspace, builders need to be installed on each one separately.
How does the JavaScript compiler know which files need to be recompiled?

The Eclipse builder maintains a built state that includes a list of all types (classes or interfaces) that are referenced by each type in the workspace. This information is returned by the compiler each time a source file is compiled. This state is computed from scratch on a full build, and updated incrementally on each subsequent build.

Whenever files are modified, the builder receives a resource delta that describes which files were added, removed, or changed.

For deleted JavaScript source files, the corresponding class files are deleted. Added and changed source files are added to a queue of files that need to be compiled.

The builder then processes this queue as follows:  
  • Remove a file from the queue, and compile it.  
  • Compare the resulting type to the old class file, and see if the type has structural changes
  • Structural changes are changes that can affect the compilation of a referencing type: added or removed methods, fields or types, or changed method signatures. 
  • If the type has structural changes, find all types in the project that references the changed type, and add them to the queue. 
  • If the type has changed at all, write it to disk in the builder's output folder. Update the built state with the new reference information for the compiled type.  
  • Repeat until the queue is empty.  
  • As a final step, the builder generates problem markers for each compiled type that had compilation problems.
What are Project Natures?
Create an association between a project and a given tool, plug-in or feature set.  By adding a nature to a project, you indicate that your plug-in is configured to use that project.


Natures also provide a way of handling the lifecycle of a tool's interaction with a project.  When a nature is added to a project, the project nature's configure() method is called.  This gives the tool an opportunity to initialize its state for that project and install any incremental project builders that are needed for that project.  When a nature is removed from a project, the nature's deconfigure() method is called.  This gives the tool an opportunity to remove or clean up any meta-data it has created for that project, and to remove any listeners and builders associated with that tool.


How do we implement an Incremental Project Builder?  To implement an incremental project builder, you first have to create an extension: org.eclipse.core.resources.builders.  Next, create a Builder class that must extend the abstract IncrementalProjectBuilder superclass.

<extension
id="Builder"
name="eScript Builder"
point="org.eclipse.core.resources.builders">
<builder>
<run class="org.eclipse.escript.builder.Builder">
<parameter name="optimize" value="true"/>
<parameter name="comment" value="escriptBuilder"/>
</run>
</builder>
</extension>

public class Builder extends IncrementalProjectBuilder {

protected IProject[] build(int kind, Map args, IProgressMonitor monitor) { 
if (kind == IncrementalProjectBuilder.FULL_BUILD) { fullBuild(monitor);
} else { 
   IResourceDelta delta = getDelta(getProject()); 

if (delta == null) { 
   fullBuild(monitor); }
else { 
   incrementalBuild(delta, monitor); 
}

return null;
}

private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) {
System.out.println("incremental build on "+delta);
try {

delta.accept(new IResourceDeltaVisitor()
{ public boolean visit(IResourceDelta delta) {
System.out.println("changed: "+
delta.getResource().getRawLocation());
return true; // visit children too
}
});
} catch (CoreException e) { e.printStackTrace(); }
}

private void fullBuild(IProgressMonitor monitor) {
    System.out.println("full build");
}
}

If you are interested in seeing a Web Runtime (WRT) Plugin demo in action, then come to the Symbian Silicon Valley SIG event on September 16.  If you found this article useful, please retweet it!

1 comment:

John Steele said...

Do you know where to get the plugin and source for the eScript referenced from the Eclipse FAQ book?