Plug-in Best Practices for RCP

November 7th, 2007  |  Published in Uncategorized  |  8 Comments

Note: For those of you reading my posts on Planet Eclipse, you’ve probably noticed the titles have reverted to my WordPress user name. I’ve posted a Bugzilla entry about this, but if anyone has a clue what’s going on, I’d appreciate the help!

I just finished giving a talk at Eclipse World entitled Plug-in Best Practices for Rich Client Applications. For those who attended, and anyone else who’s interested, here is a summary list of the practices discusses. Feedback is obviously welcome and much appreciated.

Encapsulation

  • Design plug-ins to maximize encapsulation. Expose packages only when forced to.
  • Use a package structure that maximizes your ability to hide code.
  • Never mix public and private classes in the same package.
  • Consider incorporating the “internal” keyword into your package naming convention.

Cohesion and abstraction

  • Start thinking of plug-in contracts in addition to traditional class/type contracts.
  • Your plug-in should have a coherent API. In some cases, this can be composed of a set of factories that return a set of interfaces.
  • A plug-in should represent a coherent concept or subsystem.
  • A plug-in should do one thing and do it well.
  • Add a “New plug-in” refactoring to the list of design refactorings you look for.
  • Many fine-grained plug-ins should be preferred to a few large-grained ones. Don’t worry about plug-ins with a small number of classes.

Dual use code

  • If code is going to be used both inside and outside of an OSGi framework, make it into a plug-in. It’s still just a JAR!
  • If running plug-in code outside of an OSGi framework, remember that your encapsulation mechanisms will no longer be enforced at runtime. The “internal” keyword in package names can help here to inform non-OSGi developers that they should not access certain code.

Third party libraries

  • Third party libraries should always be distributed as separate plug-ins. Do not embed these libraries into plug-ins that also contain your own code.
  • When using third party libraries, look at repositories like Orbit to see if there is already a version packaged as a plug-in.
  • Move third party plug-ins out of your workspace and into your development and build targets.

Activators

  • Activators should be used strictly for lifecycle management. Do not let them become a dumping ground for factory methods.

Plug-in dependencies

  • Visualize plug-in dependencies as a stream, not as a hierarchy.
  • Use Require Bundle to declare dependencies when you want to hard code a dependency to a specific plug-in.
  • Use Import Package to declare dependencies when you want to allow multiple plug-ins to provide an implementation.
  • Minimize the coupling between plug-ins, just as you do with classes.
  • Use extension points and OSGi services to help minimize coupling.
  • Avoid reexporting dependencies unless the exporting plug-in represents a coherent API. Unnecessary reexporting leads to dependency leaks and makes issues like circular dependencies hard to track down.

RCP-related

  • Always create development and build targets for your application. Version those targets.
  • Place RCP product definitions (Application, advisors and branding) in separate plug-ins, Do not mix products into your other code.
  • Use features to wrap your plug-ins and simplify your product configurations.
  • Place unit tests in a separate plug-in or, better yet, a plug-in fragment.

Responses

  1. vainqueur says:

    January 17th, 2008 at 4:10 am (#)

    In my Activators, I usually start service trackers & also register OSGi services (& place these services into singletons). What is your position on the use of singletons in an eclipse RCP ?

  2. Patrick says:

    January 17th, 2008 at 3:58 pm (#)

    I do have singletons in my RCP applications, and find them useful. There may be situations where singletons cause problems, particularly if you’d like to reuse your plug-ins in a Rich Ajax Platform application or in a server-side OSGi application.

    If there are any specific concerns or problems you’ve had with singletons in RCP application, I’d be interested in hearing them.

  3. Lex Robin says:

    December 16th, 2008 at 1:27 pm (#)

    IMHO singletons are a no-go. Our projects used them a long time because it was so easy to add functionality anywhere. After I had to refactor our (non-RCP) code and introduce a constructor parameter for singletons, the only problems were singletons. Some could be removed easily, others really hard. My conclusion: avoid singletons where possible. Always try to find another way, e.g. by creating an instance at application startup. First, you see what code requires the instance – second, you avoid such major problems we had with the refactoring our singletons.

    Now to RCP (I’m a RCP beginner):
    Unfortunately, I did not found a way how to pass a instance reference from my IApplication to my views. The latter are simply created using “magic”, there is no way to pass needed references in the constructor.

  4. Patrick says:

    December 16th, 2008 at 9:54 pm (#)

    Hi Lex,

    Yeah, singletons are now something of an anti-pattern and I agree that their use should be limited. But as you say, eliminating singletons can cause problems when you’d like to access a “global” instance deep down in the framework.

    There are a few solutions to this.

    * Make the instance available via a factory class or something like a singleton registry (which itself would need to be a singleton). This solves many of the problems associated with singletons, but isn’t the cleanest approach.

    * A better solution may be to simply create OSGi services for these classes. This provides you a lot of flexibility in how and where your instances are created. It’s true that the view has to reach out and pick up the service, but in a modular framework like the RCP this is hard to get away from.

    * There is also a way to add proprietary (non-OSGi) services. Check out the documentation for the org.eclipse.ui.services extension point for more info. Services added through this extension point would be available globally via the PlatformUI.getWorkbench().getService() method.

    There have been rumblings about adding dependency injection to the RCP framework as part of the e4 project, but I’m not sure what the exact plan is. Check out this page for more info:

    http://wiki.eclipse.org/E4/Architectural_Foundations

    Hope this helps,

    — Patrick

  5. Geejay says:

    March 9th, 2010 at 4:16 am (#)

    Hi

    Thanks for the best practices! I hope I can use them down the track…

    I am only starting with RCP/OSGi/Java actually. I come from a .NET Windows Forms /ASP.NET world.

    The first hurdle I have encountered is authentication with a Login screen. I noticed I can’t access services until the workbench has been started, so I’m not sure what the normal “practice” is here. How do you do authentication with RCP?

  6. Patrick says:

    March 9th, 2010 at 9:55 am (#)

    Hi Geejay,

    A common approach is to use a splash handler to manage login. Splash handlers execute after the workbench has been started.

    Login logic can also be tied to JAAS, if you’re interested in that. Check out this link for more details:

    http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/login_extensions.html

    Hope this helps,

    — Patrick

  7. S says:

    March 18th, 2010 at 10:27 am (#)

    Patrick, This is a wonderful guidelines for plug-in design. Where can I find more details about each recommendation? For example, I don’t know why you say “Do not mix public and privtae class”? . Can you please post more details. That will really help the developers like me. Thanks.

  8. Patrick says:

    March 18th, 2010 at 10:38 am (#)

    While I don’t have any more detailed info on this blog, I’d be happy to answer any questions you have.

    When I say “Do not mix public and private classes”, I mean that each package in a bundle should contain only public or only private classes. When you export a package using OSGi, this package should only contain classes you want to make visible to other bundles. If it contains classes you want to stay hidden, then you’re “leaking” implementation details.

    Hope this helps,

    — Patrick

Leave a Response