Eclipse Yoxos Services Downloads Blogs About
Home > Blogs >

Posts Tagged ‘api’

on May 9th, 2012The new Application API in RAP

RAP 1.5 includes a new API to define and start RAP applications programmatically (up to RAP 1.4, this was only possible using Eclipse extensions or web.xml properties). With this new API, RAP can also be used for leightweight applications based on OSGi, but without the entire Eclipse stack, even with other OSGi containers like Apache Felix. Also traditional web applications, that use RWT as a library without OSGi, benefit from the new API.

This API contains a couple of interfaces that we had trouble to find suitable names for. If you’ve used this API already you know that there were two interfaces side-by-side in the same package with almost the same name: ApplicationConfigurator and ApplicationConfiguration. Even though these names seemed to be correct, it turned out that they were hard to tell apart, and if mixed up in a service declaration, the application did not start, without any warning.

So we reviewed the case and eventually came up with better names for the interfaces without changing the structure. Let me explain the new API and our reasoning behind it.

Implementing an ApplicationConfiguration

A RAP application consists of various parts, such as entrypoints, URL mappings, themes, service handlers, etc. All these parts constitute an ApplicationConfiguration. The configuration is like the blueprint for an application. Based on an ApplicationConfiguration, the framework can create and start an application instance. There can be more than one application instances at runtime, e.g. running on different network ports or different servlet contexts.

Hence, when you write a RAP application, you have to provide an ApplicationConfiguration.

An ApplicationConfiguration is used to configure an application before it is started. For this step, RAP follows a callback approach to leave the responsibility for creating and starting the application with the framework. Therefore, the configuration must actively configure the application. To do so, it has one method configure( Application ). The framework provides a reference to the created Application as a parameter to this method. Here’s how a simple implementation looks like:

public class SimpleConfiguration implements ApplicationConfiguration {
 
  public void configure( Application application ) {
    application.addEntryPoint( "/simple", SimpleEntryPoint.class, null );
    application.addEntryPoint( "/other", AnotherEntryPoint.class, null );
  }
}

Registering the ApplicationConfiguration

When using OSGi, the ApplicationConfiguration can be registered as a service. I’d recommend using OSGi declarative services (DS) like this:

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
   <implementation class="com.example.SimpleConfiguration"/>
   <service>
      <provide interface="org.eclipse.rwt.application.ApplicationConfiguration"/>
   </service>
</scr:component>

The bundle org.eclipse.rap.rwt.osgi will automatically start this application on every available HttpService. When using Equinox, don’t forget to also include the org.eclipse.equinox.ds bundle. You can find an example of a simple RAP application using DS on github.

When using RWT as a library in a traditional web application, i.e. without OSGi, you can register your ApplicationConfiguration in the web.xml by adding a context-param with the fully qualified class name of the implementation:

<context-param>
  <param-name>org.eclipse.rap.applicationConfiguration</param-name>
  <param-value>com.example.ExampleConfiguration</param-value>
</context-param>

You can always look up the param-name in the constant ApplicationConfiguration#CONFIGURATION_PARAM. The RAP FAQ has a complete example.

Starting an Application

When an ApplicationConfiguration has been registered as described above, the application is automatically started by the framework. Alternatively, it can also be started explicitly using an ApplicationRunner:

ApplicationConfiguration configuration = new SimpleConfiguration();
ApplicationRunner runner = new ApplicationRunner( configuration, servletContext );
runner.start();

There’s a saying that there were only two hard things in computer science, cache invalidation and naming things. I don’t happen to know what’s so tricky about cache invalidation icon wink The new Application API in RAP But I can hardly remember any technical problem that caused me as much of a headache as these few names did. I hope that after so many discussions, this new API will prove to be simple to understand and to use.

Thanks to Frank, Rüdiger, Holger and Jordi for great discussions and especially to Frank for contributing this new API to RAP!

The changes are part of RAP 1.5M7, published this Friday, May 11.

on Apr 27th, 2011Key Bindings in RAP

Support for key bindings (bug 282449) has been one of the most requested features for RAP. So I’m happy to say that since 1.4 M5, RAP implements the JFace key bindings API, provides the org.eclipse.ui.bindings extension point, and enables most of the default workbench key bindings. As a result, you can now use most* of the key shortcuts of your application also in the browser–if your application uses the workbench. But many use RAP without using the workbench. So how can you enable key bindings in a plain RWT application?

In M7, we now introduce a simple way of doing this. Let’s first have a look on how you would implement a key binding in SWT. You would have to register a global listener for key events on the display like this:

display.addFilter( SWT.KeyDown, new Listener() {
  public void handleEvent( Event event ) {
    if( event.stateMask == 0 && event.keyCode == SWT.ESCAPE ) {
      // handle escape key
    }
  }
} );

Well, you can now use the same code in RWT.

But there’s one more thing to it: RWT is a client-server architecture and we don’t want the browser client to send a request for each and every key stroke. The server should only be notified when the user presses one of the key sequences that we are really interested in. Therefore, we have to inform the client, which key sequences should be active. This information can now be attached to the display using Display.setData() with the new constant RWT.ACTIVE_KEYS as property key. The value of this property must be an array of strings, each one representing a single active key sequence. The syntax is the same that you know from key binding extensions for the workbench. So if you want to enable some simple key bindings like, for example, “c” for compose and “x” for delete, and maybe some more advanced key sequences like “Ctrl+F11″ for power-users, you could write something like this:

display.setData( RWT.ACTIVE_KEYS, new String[] { "C", "X", "CTRL+F11" } );
display.addFilter( SWT.KeyDown, new Listener() {
  public void handleEvent( Event event ) {
    if( event.stateMask == 0 && event.character == 'C' ) {
      handleCompose();
    } else if( event.stateMask == 0 && event.character == 'X' ) {
      handleDelete();
    } else if( event.stateMask == SWT.CTRL && event.keyCode == SWT.F11 ) {
      doSomeAdvancedStuff();
    }
  }
} );

Only the first line is RAP-specific. So for a single-sourcing RWT/SWT application, you only have to care about the constant. I’m sure you have an idea how to do that. M7 will be available on May 7–easy to remember.

*) Some shortcuts may be reserved by some browsers and cannot be used. Other shortcuts will override browser actions, like Ctrl-N (new window) Ctrl-T (new tab) etc. You also may not like to disable C&P in form fields by adding key bindings for Ctrl-C etc. So you have to choose your web key bindings wisely… Ah, and sequences of key strokes like Ctrl+X T are not yet supported.

on Nov 22nd, 2010A women’s way to clean code

A few weeks ago the news in Germany was that the average lifespan of German citizens has reached its highest level ever (Statistisches Bundesamt Deutschland).  This was good news but I was also surprised to hear that women still live longer than men. I can imagine a lot of contributing factors but maybe that’s a long discussion better done over beers. One thing that I’ve observed, that I think I can say without getting into trouble, is that some women I know, are simply smarter about their health. For example, if they develop symptoms, they’ll go more quickly to the doctor than I would (or other guys I know). Longevity led me to think about the lifetime of code, and how short that can be sometimes. And, how we often ignore symptoms of illness in code too.  This would be in the form of warnings during compile time, like in the following example, “death by internal API change”.

dbiac A womens way to clean code

With the right compiler settings, a modern IDE like Eclipse displays warnings when something isn’t right e.g. when using internal API.  By ignoring these warnings you are vulnerable to the ‘death by internal API change’ malady.  One day the owner of the API will change its internal structure. If you’re lucky you can adopt the new structure and your code will survive. But if you’re out of luck, the changes to the internal API are so drastic that you can’t repair your code and your application, built on top of internal API, is completely broken.

This death can be avoided by reacting to the symptoms. Let me explain this with the same example. Every programmer has found himself in the situation were a public API couldn’t do everything you needed.  If you’re writing code in a women’s way, you won’t ignore the symptoms.  A female would consult a doctor, in this case the creator of the API or the community around it. They would describe the symptoms, and with this kind of information the “doctor” can react by extending the public API of the framework. In this way, all symptoms (warnings) are recognized early and eliminated before the malady can take hold. It’s the same here as with people: if you consult the doctor early, the probability of illness will shrink.  So, be nice to your code…

Can you think of other examples where bad code is so easy to ‘catch’?  It would be great to hear your examples of  maladies like “death by internal API change” and hear your experiences.

on Jul 8th, 2009OSGi, Eclipse and API Management

Recently, a few people have come to me ask how Eclipse maintains its API and versions. The intent of this question was to see what lessons there are to be learned for other OSGi-based applications. If we step back a bit, in essence, Eclipse is a large OSG application. On top of that, Eclipse is a platform where people build their own OSGi applications on… it’s an OSGi party. As a result, there are many people dependent on the API Eclipse produces so the management of this API is important. If breaking API changes were common, people would have less desire to build on the platform. To help with this problem, Eclipse developed PDE API Tools.

I’ll discuss four main areas around API management that API Tools can help you with.

API Comparisons

I have seen some discussion of people wanting to know what new APIs were part of the Eclipse Galileo release. While it’s pretty easy to see the new and noteworthy items for the latest Eclipse release, it’s difficult to dive into and see what actual classes and methods were modified. To help alleviate this problem, PDE API Tools has the ability to produce API comparison reports to show exactly what has changed. I have mentioned the API Tooling view in a past blog entry for those who are interested.

api1 300x148 OSGi, Eclipse and API Management

API Compatibility

One thing that’s important is being able to see binary compatibility issues between a build and a baseline. This is currently possible within the Eclipse IDE if you use PDE API Tools in the workspace, however, if you wanted to generate a report via an Ant task you can do that. As a sample, I generated a report against Eclipse 3.4.2 and Eclipse 3.5:

<?xml version="1.0" encoding="UTF-8"?>
<project name="api_analysis_reporting" default="run" basedir=".">
    <property name="baseline" value="/Users/chrisaniszczyk/eclipses/eclipse-SDK-3.4.2/eclipse" />
	<property name="profile" value="/Users/chrisaniszczyk/eclipses/eclipse-SDK-3.5/eclipse" />
	<property name="report_location" value="${baseline}/api" />
	<property name="html_report_location" value="${baseline}/api-html"/>
 
	<target name="run">
	    <apitooling.analysis
	      	baseline="${baseline}"
	    	profile="${profile}"
	      	report="${report_location}"
	      	debug="true"
	     />
	    <apitooling.analysis_reportconversion
	      	htmlfiles="${html_report_location}"
	      	xmlfiles="${report_location}"
	      	debug="true"
	    />
	  </target>
</project>

API Freeze

Another aspect that’s important to Eclipse is the concept of an API Freeze.

galileoschedule 300x214 OSGi, Eclipse and API Management

Towards the end of the Eclipse release, we implement an API Freeze which means that no new API can be added or modified after this point. Why have an API Freeze? Well, it helps ensure stable APIs for consumers looking to adopt a new version of Eclipse. From a producer point of view, how do you ensure that the API Freeze is actually enforced? Developers are human and make mistakes. Developers can be also be sneaky by modifying API.

To help enforce an API Freeze, PDE API Tools has the ability to produce freeze reports:

<?xml version="1.0" encoding="UTF-8"?>
<project name="api_freeze_reporting" default="run" basedir=".">
    <property name="baseline" value="/Users/chrisaniszczyk/eclipses/eclipse-SDK-3.4.2/eclipse" />
	<property name="profile" value="/Users/chrisaniszczyk/eclipses/eclipse-SDK-3.5/eclipse" />
	<property name="report_location" value="${baseline}/api" />
	<property name="html_report_location" value="${baseline}/api-html"/>
 
	<target name="run">
	    <apitooling.apifreeze
	      	baseline="${baseline}"
	    	profile="${profile}"
	      	report="${report_location}"
	      	debug="true"
	     />
	    <apitooling.apifreeze_reportconversion
	      	htmlfile="${html_report_location}"
	      	xmlfile="${report_location}"
	      	debug="true"
	    />
	  </target>
</project>

As part of the Galileo release, we used freeze reports as a way to ensure API stability as we converged.

API Usage

From the consumer point of view, it’s interesting to see how people are consuming your APIs. To help with this, API Tools has the ability to run usage reports against a set of bundles. Awhile ago, I blogged about this topic and produced a report against most of the bundles included in the Galileo release:

<?xml version="1.0" encoding="UTF-8"?>
<project name="api_use_reporting" default="run" basedir=".">
    <property name="baseline" value="/Users/chrisaniszczyk/eclipses/eclipse-galileo" />
    <property name="report_location" value="${baseline}/api" />
	<property name="html_report_location" value="${baseline}/api-html"/>
 
	<target name="run">
	    <apitooling.apiuse
	      	baseline="${baseline}"
	    	proceedonerror="true"
	      	report="${report_location}"
	      	considerinternal="true"
	      	considerapi="true"
	      	debug="true"
	     />
	    <apitooling.apiuse_reportconversion
	      	htmlfiles="${html_report_location}"
	      	xmlfiles="${report_location}"
	      	debug="true"
	    />
	  </target>
</project>

I hope this helps and allows you to understand and adopt PDE API Tools.

Also, the PDE team is currently in the planning stages for the next release.

Please file any bugs if you have issues or suggestions so the PDE team can act on them.

on Jul 3rd, 2009Eclipse Galileo and the Rich Ajax Platform (RAP)

As Galileo is out in the wild and we are all already working on Helios… I thought it would be handy to give a quick overview of the New and Noteworthy features the RAP team worked on for Galileo. Besides many, many bug fixes… we still found time to provide several new features. On top of the new features, we focused on making single sourcing even easier to do.

New Look and Feel

rap addressbook business 300x258 Eclipse Galileo and the Rich Ajax Platform (RAP)

This is one of the biggest features of RAP released as part of the train. As Ian already pointed out correctly:

One of the common complaints about RAP was that it doesn’t look like a web application.

While this was true in the past, we worked really hard to provide the community a clean and easy way how to customize the whole workbench styling.

Cell Editors

It’s finally done – RAP supports cell editors in the Table. As this was a really long-standing issue we’re more than happy to have it in 1.2.

celleditors 300x199 Eclipse Galileo and the Rich Ajax Platform (RAP)

Ed, now it’s time to give the whole “generated EMF editor on RAP” idea a new spin! For anybody interested in this story, please CC yourself on this bug.

Performance & Memory

The RAP team really had a great time for this release – we just sat there and waited for the browsers to become even faster…as this was a really silly task we decided to do something:

Improvement of Session Startup Performance

First the creating of the startup page is less CPU intensive. Second the javascript library content is not embedded in the startup page anymore and will be delivered separately. As the library content doesn’t change after server start it can be zipped once and buffered. This reduces CPU usage significantly. The library is stored in the browser’s cache and need not to be reloaded on subsequent application visits.

Client-side memory improvements

Included is also a new version of the Javascript library qooxdoo. Thanks to the great support by the RAP community, most notably from Stefan Hansel who tracked down a number of significant memory leaks in qooxdoo and provided patches to the qooxdoo developers, this version now brings a major improvement in client memory consumption. With this qooxdoo version, the long-standing memory leakage problems of RAP especially in Internet Explorer are resolved. Thanks to everyone who helped making this possible!

New API & Widgets

With the idea of single sourcing in mind we concentrated on adding new API to allow even more reuse of existing SWT/RCP code. Besides many small things like Display#timerExec() we also tried to complete the set of widgets. With 8 (yes, eight) new widgets in this release, these two are my personal favorites and often requested by the community.

DateTime

RAPDateTime Eclipse Galileo and the Rich Ajax Platform (RAP)

FormText (Forms)

RAPFormText 300x148 Eclipse Galileo and the Rich Ajax Platform (RAP)

Cursor Support

RAPCustomCursor Eclipse Galileo and the Rich Ajax Platform (RAP)

Summary

In case you’re not yet sure how “single sourcing” works – Ralf and Rüdiger would be happy to explain it to you step-by-step in their upcoming webinar.

In summary, we’re quite happy with the current 1.2 release but are already looking forward to the Helios release train.

If you have anything you want to see in 1.3, don’t hesitate and drop us a note.

on Jun 25th, 2009API Layering for Distributed OSGi

 API Layering for Distributed OSGi

We’ve added to our distributed OSGi documentation (with examples+source) for ECF 3.0/Galileo:

We have API layering so service programmers can choose the simplest appropriate mechanism for their system requirements, while still providing access to ‘lower-level’ concerns when necessary:

  • failure handling
  • synchronous vs. asynchronous remote method invocation
  • serialization and wire protocol
  • and so on…

If you have any questions or comments, please let us know on the ECF mailing list.

on May 6th, 2009Those Leaky Networks

In previous blog posts I’ve blogged about ECF’s upcoming implementation of RFC 119.

In this post, I would like to jump out of the description of RFC 119 and talk about how the implementation of RFC 119 and ECF remote services fit together…as our implementation of RFC119 is layered on top of the ECF remote services API.

I think of remote procedure call as a leaky abstraction.  For those that haven’t read Joel Spolsky’s The Law of Leaky Abstractions, I highly recommend it.  The reason I would say that it’s a leaky abstraction is that although transparent RPC *looks* like a local method call, it’s clearly not under some situations:

  1. The remote call is very slow (or blocks) because of a network problem
  2. The remote call cannot complete because the network fails/goes down
  3. A parameter to the remote method call cannot be serialized…e.g. trying to make a remote call e.g. like this:  serviceProxy.setWorkspace(IWorkspace workspace…why would passing a workspace to a method call be a problem?)

There are others, but I think these are the most compelling.

Note that all three of the above are runtime issues…i.e. they can happen at runtime for lots of reasons that have nothing to do with the semantics of the RPC itself.  In the case of 1 and 2 they cannot be prevented.  And they are likely to happen for non-trivial procedures.

Note also that since OSGi services are method calls on some service interface (a pojo), that remote services will also have the above issues.  It doesn’t matter what your remoting implementation is, they will all be subject to such problems.  Unfortunately, we (the distribution system implementers) can’t prevent it.

So, to me this means remote procedure call is a leaky abstraction…because even though it looks like normal/local/in memory method call, there are occasions where the ‘truth’ about networks leaks out.

So what to do?   Well, I think there are several things to do, both from the service designer’s viewpoint (i.e. those defining the service to be remoted) and the distribution system implementer’s viewpoint (i.e. people that implement distribution infrastructures…like me).

From the service designer’s viewpoint you could design all of your services to prepared for 1, 2, 3 above…and/or document them as having these properties.  This can/does definately help.  But it is a major pain, and you can end up having services that are more complex (especially if they are used locally as well as remotely).

From the distribution system implementer’s viewpoint I feel one thing to do is what Joel describes in his paper as what TCP did for IP..layering.

That is the approach we’ve taken with implementing RFC 119…as the implementation of transparent remoting as specified in RFC119 is implemented on a non-transparent/explicit remoting API (ECF remote services).  I think this is nice, because it allows/supports more use cases:

“I want to create a simple remote service, as easily as I can and have it work”  (use RFC 119)

“I want to create a remote service that knows about or at least responds properly to the remoting leaks (1, 2, 3, etc above), and not simply crash/block/fail when the service is used”  (use ECF remote services)

So, we’ve implemented RFC119 itself using ECF remote services…and layered transparent remoting on top of a non-transparent remoting runtime API.  This gives choices to both service designers and service consumers about how much they want/need to care about the network leaking into remote OSGi services.   That is, if they care about the leaks they can do something about them, but if they (or the service consumers) don’t care about such leaks they can have a standard way of publishing, discovering, and receiving remote OSGi services.

on Mar 8th, 2009RFC 119 and ECF – part 3

I’ve blogged previously about what we (ECF) are doing WRT to RFC 119 (Distributed OSGi Services):  RFC 119 and ECF – part 2

The news for today…I’m rather excited to report…is that we now have a working implementation of RFC 119, with support for both discovery and distribution parts of the specification.  This will be part of the ECF 3.0/Galileo release, and of course we will be talking about it in Markus’ and my tutorial, as well as some other talks.

What’s So Cool About Yet Another Spec Implementation?

In my view, what makes this implementation interesting and useful is that we’ve used the abstract ECF discovery and remote services APIs to implement this spec, meaning that without doing any other work, RFC compliant distributed OSGi services are supported using the following transports

Distribution

  • r-OSGi (http)
  • XMPP
  • ECF Generic
  • Skype
  • Java Messaging Service (JMS)
  • JavaGroups

Discovery

And, of course any other transports that people are willing to create, as the ECF remote services API is completely open.

Our desire/hope is that others will implement ECF providers built from other protocols/transports of their choosing (both commercial and open source)…with the payoff to them being that they will then automagically have a RFC 119-compliant implementation…since all ECF providers are now RFC 119 compliant (and will remain so, as we will update the impl as the spec changes).  All the existing implementations done by the ECF team (e.g. r-OSGi, ECF generic, etc) are open source and so may be used/reused to create new providers as desired.

Another thing that I think is cool is that even though RFC 119 specifies using transparent proxies for accessing remote OSGi services, it allows (and even encourages) implementations to support non-transparent/asynchronous remoting (i.e. using one-ways, asynchronous rpc, and futures).  ECF’s remote services API already has support for futures, and asynchronous/non-blocking remote invocation via its IRemoteService interface.

With our current impl of RFC 119, clients can access the IRemoteService instance (in addition to or instead of the proxy), via a standard service property on the ServiceReference.  This gives clients a runtime choice of whether to access a remoted service via a proxy…or via asynchronous/non-blocking techniques like futures and one-ways.

One final thing…the size cost for the ECF remote services API is fairly small (<60k of code) next to the size of the implementations…making it possible to use in smaller (as well as larger) execution environments.

on Dec 19th, 2008RFC 119 and ECF – Part 1

There seems to be a lot of interest in doing distributed services with OSGi/Equinox, and so I wanted to begin a series of postings about what the ECF project is doing in this area (short story: a lot), and what we are planning for supporting standardization via RFC 119.

What is RFC 119?

First, here is the OSGi 4.2 early draft, which includes a draft of RFC 119 (toward end of PDF).  RFC 119 is an effort to standardize some aspects of creating, publishing, discovering, and accessing out-of-process OSGi services.  It is not yet complete, but is quickly moving toward standardization.

What is ECF Doing with Discovery and Remote OSGi Services?

For some time, ECF has had both a discovery API, and a remote services API.

These APIs have two interesting characteristics (relevant to this post, anyway):

  1. They are transport independent
  2. They expose both transparent and non-transparent remote method access

Why is Transport Independence Useful?

Transport independence means that multiple implementations can and do exist, for both the discovery and remote services APIs.  So, for example, for discovery ECF currently has two implementation…also known as ‘providers’:  the Service Locator Protocol (RFC 2608), and Zeroconf/Bonjour.

Transport independence also exists for the remote services API, and we already have implementations based upon r-OSGi, XMPP, a simple tcp-based protocol, and JMS.

In general, transport independence is helpful because provider implementations can be replaced/changed without affecting clients (i.e. code that uses remote services).

Among other things, this is important for interoperability and cross-vendor openness, as it allows multiple servers/services to be used without rewriting the clients of those services.

Exposing both transparent and non-transparent remote method access

There is a long (and sometimes bitter) dialog in the distributed systems literature about whether transparency in networked services is a ‘good idea’.   ECF has attempted to skirt this entire large and complicated philosophical issue by providing both transparent access to remote services (i.e. through the normal OSGi services registry), and non-transparent access (via IRemoteService interface…see javadocs here) and leaving the decision about which is appropriate to the service creator and service client.

For non-transparent access to remote service, ECF provides the IRemoteService interface.  It exposes methods to remotely invoke methods via non-blocking techniques (e.g. with listeners for receiving callbacks or with a ‘future’).  This gives clients the flexibility and the tools to use transparent invocation (via proxy) if desired/appropriate, or use the asynchronous, non-blocking mechanisms present on IRemoteService.

What about ECF and RFC 119?

The short story is that we have plans to implement RFC 119 with the ECF discovery and remote services APIs.  Specifically, see bug 249240.   Given the existing drafts of RFC 119, we believe that we can implement it by writing code above the ECF discovery and remote services APIs, without significant changes to the APIs themselves.   This would mean that all ECF providers would then implement RFC 119, without having to do any additional work.

More on this and other issues in subsequent posts.

on Sep 16th, 2008Eclipse API Tools Article

API is a pain in the ass… either crafting API or just maintaining it. Just ask any Eclipse committer who has:

  • broken API by introducing a subtle change to a class
  • forgotten to rev version numbers when adding new API
  • accidentally revved version numbers when not adding new API
  • maintained IWorkbenchPart3, ITextViewerExtension7, IContext2… etc…
  • tried to argue that API isn’t binding in the state of Texas

To help with this problem, PDE introduced API Tooling as part of the Ganymede release. Not too many people outside the Eclipse Platform team know about these tools so I have written an article that introduces the wonderful PDE API Tooling to everyone! Hopefully this will kick-start your adventure in using API Tools and making it easier to maintain API and versioning information.

Also, if the wonderful (and handsome!) Eclipse Summit Europe program committee decides to accept my talk on API Tooling, you can hear about it in person at one of my favorite European Eclipse conferences!

© EclipseSource 2008 - 2011