Scripted Contributions to the Platform
Now you're ready to take a step forward and explore a way to directly access and modify the Eclipse platform using a scripting language and use scripts to add contributions to the platform. This requires the definition of a binding layer between scripted contributions and the platform. Such layer will have:
- Extension points that mimic the standard Eclipse ones such as scriptedView instead of a standard view contribution item to provide Eclipse views backed by a script
- Proxy classes that implement the standard Eclipse interfaces such as org.eclipse.ui.part.ViewPart and delegate method calls to the underlying script
- An extension to the org.eclipse.ui.startup extension point to perform all the plumbing and binding between the scripting contributions and the platform at startup time
Consider the sample case of an Eclipse view backed by a JavaScript implementation. Figure 4 shows the entire cycle for the sample case and differentiates between actions performed at configuration/startup time and those performed at runtime. (See the sample code for other types of contributions, such as Eclipse action sets.)
| Figure 4. The Cycle That Handles Scripted Contributions |
The first step is defining the contribution, as shown in the following listing:
<plugin>
<extension
point="com.devx.scripting.scriptedContribution">
<scriptedView
allowMultiple="false"
id="com.devx.scripting.jsCalculator
name="JavaScript Calculator">
<script
extension="js"
id="com.devx.scripting.jsCalculator.script"
uri="scripts/jsCalculator.js">
</script>
</scriptedView>
</extension>
</plugin>
The extension is very similar to the standard org.eclipse.ui.views. The only difference is the additional <script> element, which defines the underlying script (the uri attribute can point to either a resource within the plug-in by using a relative URI or an external resource using the file:// scheme).
When the application starts up, the class com.devx.scripting.ScriptingStartup, registered as an extension to the org.eclipse.ui.startup extension point, scans available scripted contributions and dynamically adds them to the platform via the IExtensionRegistry.addContribution() method. Note that dynamic contributions require a special permit, which you give by adding the -Declipse.registry.nulltoken=true command-line option when launching the application.
The ScriptingStartup class translates between the scripted contribution and the contribution that will act as a proxy for your scripts. Listing 2 shows the getContribution() method involved in the translation process.
As you can see, the code just copies the scripted contribution and translates it into a standard contribution to org.eclipse.ui.views. The view implementation class com.devx.scripting.view.ScriptProxyView will delegate to the underlying script the calls made to the view by the Eclipse platform. For example, the following listing shows the delegation of the rendering process to the script, performed when Eclipse calls createPartControl(Composite parent) to draw the view:
scriptParent = new Composite(parent,SWT.NONE);
scriptParent.setLayoutData(new
GridData(GridData.FILL_BOTH));
scriptParent.setLayout(new FillLayout(SWT.HORIZONTAL));
// this call returns the script associated with this view
IScript script = getScript();
Map<String,Object> params = new HashMap<String,Object>();
params.put("parent", scriptParent);
new ScriptSupport().runScript(script, params);
This approach enables the developer to perform fast UI prototyping, since a change to the script is immediately reflected in the view (he or she can just close and reopen it).
You are now able to use the benefits of scripting languages to achieve results that are complex to obtain with traditional Java code, such as a simple calculator. Using JavaScript and its eval() function, you do not have to worry about writing code to evaluate the mathematical expressions submitted by the user. Figure 5 shows the final result, and Listing 3 shows the JavaScript code that produces it.
The refresh button will reload the script and immediately apply changes to the UI.
Scripting languages can help draw interfaces within Eclipse in many other scenarios. For example, you can take advantage of the builder paradigm by using Groovy to build SWT interfaces or this Ruby library to build SWT interfaces with Ruby.
Towards Full Integration of Scripting Languages Within Eclipse
Now that you know how easy the integration between Eclipse and the new scripting capabilities offered by the Java platform is, you can wrap engines into the Eclipse plug-in architecture and invoke scripts from the Eclipse environment. You have also learned a way (not necessarily the best way) to use scripting languages at the very core of the Eclipse platform to provide extensions to standard extension points, such as views and action sets.
In addition to the approach described here, other projects bring scripting support to the Eclipse platform, namely the Eclipse Monkey and the EclipseShell projects. They were omitted from this discussion mainly because at the time of writing they weren't yet updated to support JSR-223, which is the main focus of the article. However, both feature some interesting ideas that have in part been ported into the sample code (such as monkey doms, which use Eclipse extensions to provide custom objects to the scripts). It's worth spending some time with them.