You are on page 1of 29

Patterns for Single-Sourcing RCP and RAP applications

Benjamin Muskalla (EclipseSource)

Version: 1.1.4

Abstract
Developing fully single-sourced bundles for Eclipse RCP and RAP requires following certain practices. This paper describes different patterns and refactorings to achieve single sourcing of applications for both runtime platforms. These patterns have been gleaned from our experiences single sourcing various applications in the Eclipse.org runtime space and tooling space.

2

. . . . . . . . . . . . . . . . .3 Split packages . . . . . . . . . . . . . . . . 4 Missing API 4. . . . . . . . . . . . . . . . . . . . . . . . 4. . . . . . . . . . . . . . . . . . 2. 12 Internationalization and localization 12. . . . . . . . . . . . . . . . . . . . . 6. . . .3 Move the instance creation to the fragments . . . . . . . . . . 10. . 5 6 6 6 7 8 8 8 8 8 8 10 10 10 10 12 12 12 13 13 13 14 14 14 16 16 16 18 18 18 20 20 20 20 22 22 22 24 24 24 best for managing dependencies . . . . . . . . . . . . . . . . . . . . . . . . 11 Jobs and background threads 11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Reduce the frequency of validation checks . . . . . . .2 Make translatable strings non-static . . . . . . . . . . . . . 3. . . . . . . . . . . . . . . . . . 5. . . . . . . . . . . . .1 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . 9 SWT Resources 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Extract a compatibility plug-in . .1 The problem . . . . . . . . . . . . .2 Favor Require-Bundle . . 5 Missing extension points 5. . . . . . . . . . . . . .1 Bundle dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Application startup and Activator scope 6. . . . . . . . . . . . . . . . . .2 Use higher-level API . . . . .3 Develop principally on the RAP Target Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. . . . . . . . . . . . . . . . . . . . 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Encapsulate the problem . . . . . .1 The problem . . . .What strategy is 3. . . . . . . . .1 The problem . . . . . . . . . .2 Move extensions to fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . 3. . .1. . . . . . . . . . .1 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Target platforms . . . . . .2 Use session singletons . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. . . . . . . . .2 Package dependencies . . . . . . . . . . . . .2 Use a facade . . . . . . . . . . . .1. . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . 3. . . . . . . . . . . .2 Building fragments . . . . . . . . . . . . . . . . . . . . . . . 7. . . . . . . . . . . . . . . . . . . . . . .Contents Contents 1 Introduction 2 Workspace organization 2. . . . . . . . . . . .1. . . . . . . . . . . . .1 The problem . . . . 12. . . . . . . . . 10 Singletons and Scopes 10. . . . .2 Separate session-specific code from Activator . . 8 Field validation 8. . . . . . .1 The problem . . . .2 Using separate workspaces . . . . . . 7 API Differences 7.1 The problem . . . . . . . . . . . . . 3 Dependencies 3. . . . . . . . . . . . . . 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 The Problem . . . . . . . . .

. . . . . . . . 24 25 26 26 4 . . . . . . . . . Create an NLSHelper and implementations Fix your message references . . . . . . . . . . . . . . . .3 12. . . . . . . . . . . . . . . . . . . . . . . . .5 12. . . . . . Localize the plug-in manifest . . . . . . . . . . . . . . . . . . . . . . . . . . .Contents 12. .4 12. . . . . . . . . . . . . . . . . . . .6 Remove static initializer and supertype . . . . . . . .

org umbrella. this may be achievable through normal refactorings [FBB+ 99].1 Introduction 1 Introduction The purpose of the Eclipse RT top-level project at Eclipse is to bring together various runtime related efforts and technologies and to foster. It is part of a larger Equinox Community drive to implement Equinox-based technology across a broad range of computing environments and problem domains. The refactorings are not onerous and generally lead to better quality bundles irrespective of the single-sourcing requirement. There is no need for the user to install any further add-ons or plugins. Depending on the specific case. Write once.org 2 http://www. But as technology evolves the Eclipse Foundations strives to bring this slogan to a new level.org/rap 3 http://www. For example let us assume we have a ready to launch application based on RCP. run everywhere is the main objective of the JavaTM programming language [AHL+ 05]. promote and house runtime efforts at Eclipse1 .eclipse. provide an alternative runtime environment for RCP applications. 1 http://www. This means that the application . By switching the runtime from RCP to RAP. namely RAP2 and eRCP3 . Two technology projects. many concepts implemented in SWT [NW04] need to be adapted to other runtimes.normally running as a desktop application on a personal computer .0 centric interface on a browser. housed under the Eclipse. Developing fully single-sourced bundles for Eclipse RCP and RAP requires following certain practices. it becomes possible to launch the application on an application server where clients ccan use the application with a Web 2. The Equinox framework and OSGi [All03] form the basis of this infrastructure.eclipse.org/ercp 5 . This holds true most of the time for running the same program on different operating systems.can now be deployed to other runtime environments. In order to achieve full compatibility between the platforms. It may also be possible to change the structure of the application code to fit the current runtime environment.eclipse. Underlying all these efforts is the common goal of providing a uniform component model across a wide variety of computing environments. These are hidden behind the public API which remains synchronous across all runtime projects.

By default Eclipse uses its own installation directory as the Target Platform. which may inadvertently be pulled in as dependencies of the application. which is suitable for developing SDK plug-ins but is less suitable for developing RCP or RAP bundles. An automated build should be used to perform a full build against both Target Platforms at regular intervals. RAP itself delivers its own target platform so developers can easily switch between the RCP plugins and the RAP counterparts. switching the target is very time-consuming as the whole workspace needs to be recompiled.2 Workspace organization 2 Workspace organization 2. and in addition it doesn’t contain all the RAP-specific API bundles. The best way to achieve this is to create all projects in the same folder and import them into your workspaces. we create two separate workspaces. A reasonable solution which has been become apparent is to use different workspaces for the different runtime environments. it is important to frequently check the code for compliance with the alternative runtime environments. First. an entrypoint implementation). be sure not to check the “Copy projects into workspace” option. The target platform is the directory containing the pre-built binary bundles that the workspace bundles depend on. A regular layout of workspaces is the following: 1. For RAP the default is unsuitable for the same reason. By utilizing separate workspaces for each platform we can import all common projects into both workspaces and have the projects unique for one platform in the corresponding workspace. Secondly. However. For RCP. Managing two separate target platforms is currently one of the key challenges when single-sourcing applications for RAP and RCP.2 Using separate workspaces In order to manage the two target platforms. Generally within a given workspace we have two types of projects. When you import the projects. this default Target Platform is unsuitable because it contains many superfluous bundles relating to the IDE functionality. RAP Workspace • Common projects • RAP-specific projects • RAP target platform As the common projects should be shared across both workspaces you need to ensure that they share the same files on the file system. Unfortunately PDE only allows one Target Platform at a time. 2. RCP Workspace • Common projects • RCP-specific projects • RCP target platform 2. File system • Common projects 6 . Secondly. It is used to compile the workspace and is also used when the user launches an application by clicking Run or Debug from the workbench. First. projects that are common for both platforms which can be reused without any modification. we need to close all related projects which do not match the target platform in order to have a clean workspace. we have projects that are platform-specific and thus contain only code that runs on one of the platforms (eg.1 Target platforms Eclipse PDE uses the concept of a ”Target Platform” to manage the set of third-party bundles available for development. There are two disadvantages to this limit.

Figure 1: The RCP and RAP APIs 7 . as shown in Figure 1. As we need to choose one or the other it is recommended to develop on RAP. Unfortunately.2 Workspace organization • RCP-specific projects • RAP-specific projects 2. Also it tends to be more obvious when one is using a RAP-specific API. The reason is that the set of APIs offered by RAP is smaller than the set of APIs offered by RCP.3 Develop principally on the RAP Target Platform For effective single-sourcing we should only use API elements that are available in both RCP and RAP. there is no collection of bundles available that contains a pure subset of both.

u i .compatibility) which has (optional) dependencies on both runtime bundles. which in Eclipse 3.0 R e q u i r e −Bundle : o r g . 3.0 Import −Package : o r g . p a r t . v i s i b i l i t y := r e e x p o r t Listing 2: Optional bundle requirements 8 . u i .1 Bundle dependencies Require-Bundle (Require-Bundle ) was introduced in OSGi Release 4.ui. you need to extend the Import-Package declaration with the split attribute as shown in the following MANIFEST. o r g .3) for more informations about split packages. In addtion. These packages are then resolved at runtime by the OSGi framework (i. r e s o l u t i o n := o p t i o n a l .1.swing.w3c. and dependencies were specified based on the ID of another plug-in.workbench” part of this split package. 3.bar. In order to avoid hving to manage the dependencies in every bundle.0 became OSGi bundles. Otherwise the dependencies would not be resolved. r a p . It is very simple: a bundle lists all of the Java packages that it imports from other bundles. u i .3 Dependencies 3 Dependencies 3. u i . 3. e c l i p s e . r a p .2 Package dependencies Import-Package is the original mechanism used in OSGi.x Eclipse module system did not have any concept similar to Import-Package.workbench=”split” directive tells Equinox to use only the ”ui. e c l i p s e . This enables OSGi to have virtual packages which are physically split across several bundles.MF fragment: 1 2 3 4 M a n i f e s t −V e r s i o n : 1. The pre-3. o r g . e c l i p s e .3 Split packages The eclipse workbench uses the OSGi concept of ”split packages”. com. Require-Bundle still tends to be favored by many Eclipse plug-in developers both for historical reasons and because PDE makes it significantly easier to use in development than Import-Package. workbench=” s p l i t ” Listing 1: Importing a split package The ui. 1 2 3 4 5 6 M a n i f e s t −V e r s i o n : 1. In order to import only a specified part of the package.1. principally to support legacy Eclipse plug-ins. including packages supplied by the JRE such as javax. Equinox) against a corresponding exported package from another bundle. workbench=” s p l i t ” .1.. org. which provides dependencies on the Java package-level. Require-Bundle works by importing all of the packages exported from a particular named bundle. and until Release 4 it was the only one. Therefore in OSGi R4.foo.What strategy is best for managing dependencies OSGi (and therefore Eclipse RCP and RAP) offers two separate mechanisms for declaring dependencies between bundles: Import-Package. v i s i b i l i t y := r e e x p o r t . you should create a new bundle (eg. r e s o l u t i o n := o p t i o n a l . the tooling support in PDE is much better for Require-Bundle. See the OSGi 4. u i . e c l i p s e .2 Favor Require-Bundle Even though Import-Package is recommended by OSGi developers it has the drawback of split packages.dom etc.e. which provides for dependencies based on whole bundles.1 The problem . 3. and Require-Bundle.13.1 specification (§3.

3 Dependencies Now all the application’s UI bundles can use the compatibility bundle as their main dependency for getting “wired” to the correct bundle at runtime. 9 .

10 .rcp com. 4. With our approach. in some cases it is useful to separate UI code from ”core” or non-UI code.bar. By making separate fragments for the RCP-only or RAP-only code. so that the non-UI code can be reused elsewhere. or develop presentation or ”theming” code for the RAP edition. The compatibility bundle can be reused in future development. including generic code that might otherwise have worked in both environments. If RCP-specific code exists in a bundle then that whole bundle will not be resolved in RAP. 4.1 The problem Inevitably some parts of an application cannot be single-sourced. In general. Fragments are incomplete bundles (hence the name) which attach themselves to other bundles and extend them in some way. We use the term compatibility plugin to refer to this bundle.rap Description UI (both RCP and RAP) functionality RCP-only functionality (fragment) RAP-only functionality (fragment) Which parts of the application will live in the host bundle and what is platform specific will be discussed in the rest of this paper.foo.bar. there will be up to one bundle and one fragment for each such grouping. It has the same fragment structure as discussed above.2 Building fragments It is important to sort the runtime-specific code into separate ”fragments”.ui.ui.foo. The naming should follow a standard scheme as shown: Table 1: Bundle Naming Scheme Bundle/Fragment Name com.foo.4 Missing API 4 Missing API 4. we can maximise single-sourcing. See also Figure 2 for an overview of this approach. a bundle should contain a logical grouping of business functionality. For example we may decide to offer convenience features in the RCP edition that are not available under RAP. In each case this leads to code that will compile under RCP but not RAP and vice versa. it may be appropriate to extract a bundle which contains platformspecific differences which are not bound to the current application.ui com.bar. Furthermore.3 Extract a compatibility plug-in Depending on the requirements.

4 Missing API Figure 2: Extended single sourcing 11 .

This way the extensions are only contributed to the runtime when the fragment is available and thus only when we have the right runtime.5 Missing extension points 5 Missing extension points 5. 1 2 3 4 5 6 7 8 9 10 11 12 13 <? xml version=” 1 . For example to the org. e n t r y p o i n t ” p a r a m e t e r=”maildemo ”> </ e n t r y p o i n t> </ e x t e n s i o n> </ f r a g m e n t> Listing 3: Sample fragment.xml of the corresponding fragment projects.xml for the RAP-specific fragment. E n t r y P o i n t ” i d=”maildemo . 0 ” e n c o d i n g=”UTF−8”?> <? e c l i p s e version=” 3 . 2 ”?> < f r a g m e n t> <e x t e n s i o n p o i n t=” o r g . 5.1 The problem Some of the extension points used in regular RCP applications are not available in RAP. On the other hand there are contributions which are specific to RAP such as themes. brandings or the entrypoint extensions.ui. For an example of a fragment. u i . r a p .bindings extension point is not available. e n t r y p o i n t ”> <e n t r y p o i n t c l a s s=”maildemo .eclipse.2 Move extensions to fragments Since we already have defined fragments we can move the platform-specific extensions to the fragment. see the following snippet. e c l i p s e .xml 12 . r a p .

This means that the Activator of a bundle has two semantic differences: 1. These IStartup implementations are registered trough the extension point mechanism as shown in the following snippet: 1 2 3 < e x t e n s i o n p o i n t=” o r g .6 Application startup and Activator scope 6 Application startup and Activator scope 6. return P l a t f o r m U I . new A p p l i c a t i o n W o r k b e n c h A d v i s o r ( ) ) . not per user 2. s t a r t u p ”> < s t a r t u p c l a s s=” o r g . While initializing the needed artifacts during bundle start is a good approach in RCP .startup extension point to contribute new runnables into the startup process of the workbench.3. It is called in application scope. 1 2 3 4 5 6 7 8 public c l a s s A c t i v a t o r extends A b s t r a c t U I P l u g i n { public void s t a r t ( BundleContext c o n t e x t ) throws E x c e p t i o n { super . e c l i p s e . Not every user of the application has its own set of bundles . See the OSGi 4. 13 . not in session scope 6. example . } } Listing 5: Examplary entrypoint Another possibility is to use the org.xml This is optimal for situations such as when the workbench has a session-scope and the IStartup implementations are to be called when the session starts.2 Separate session-specific code from Activator As there can be no active session when a bundle starts we need to separate all session and user related code from the Activator so it can be executed when the session starts. S t a r t u p C l a s s ”/> </ e x t e n s i o n> Listing 6: plugin. c r e a t e D i s p l a y ( ) .it can lead to serious problems in a multi-user environment like RAP. The Activator is called once per application. 1 2 3 4 5 6 7 8 9 10 public c l a s s E n t r y P o i n t implements I E n t r y P o i n t { public i n t c r e a t e U I ( ) { // s e s s i o n s p e c i f i c code | Display d i s p l a y = PlatformUI .eclipse. One of the key RAP behaviours during runtime is that all OSGi bundles are started only once.1 The problem A widely used approach to initialize an RCP application is the use of Activators that are called while starting an OSGi bundle. s t a r t ( c o n t e x t ) .ui.1 specification (§4. // s e s s i o n s p e c i f i c code } } Listing 4: Examplary Activator One solution is to move the related code into the createUI method of the entrypoint as this will be executed in the current session context. e c l i p s e .instead all bundle instances are shared across all users (and sessions). u i . createAndRunWorkbench ( d i s p l a y .6) for more information about Activators.

} public s t a t i c IWorkbenchAction c r e a t e A b o u t A c t i o n ( f i n a l IWorkbenchWindow window ) { return IMPL . One of these actions .ABOUT is not available we need to replace it with a facade.7 API Differences 7 API Differences 7. 7. 1 2 a b o u t A c t i o n = A c t i o n F a c t o r y . c r e a t e A b o u t A c t i o n I n t e r n a l ( window ) .a common problem when single sourcing an application. r e g i s t e r ( aboutAction ) . Using the ABOUT in RCP applications is not unusual. RAP provides a strict subset of all available SWT and RCP APIs.ABOUT implementation. belongs to the same package and behaves the same way as the corresponding RCP API. Listing 7: About Action As ActionFactory. 14 . This facades delegates the actual request during the runtime to the corresponding fragment project. Some examples for missing API are: • GC • FileDialog • MouseMove Events However. c r e a t e ( window ) . It could be a simple object. RAP itself provides a minimal set of APIs which are not part of RCP. class ) . But this means that API which is not available in RAP needs to be wrapped somehow in order to be able to use it in the common codebase. If the API is available it has the same name. Providing an alternative action for the web is done by returning another action implementation by the RAP fragment.2 Encapsulate the problem The first step to get around these obstacles is to provide a common interface to access the required artifact. We replace the real API with a call to our new facade which follows in the next paragraph. static { IMPL = ( A c t i o n F a c t o r y F a c a d e ) I m p l e m e n t a t i o n L o a d e r . The following is a snippet taken from an ActionBarAdvisor of an RCP application. an action or even whole dialogs. What the artifact really is depends on the API usage of the application.is not available in RAP. In the case of RCP we can use the real ActionFactory. } abstract IWorkbenchAction c r e a t e A b o u t A c t i o n I n t e r n a l ( IWorkbenchWindow window ) .the ABOUT action . createAboutAction ( window ) . These were introduced in order to meet several web specific requirements. The following describes how to use these APIs without breaking the RCP implementation. n e w I n s t a n c e ( ActionFactoryFacade . To have a common accessor to those artifacts we need to create an abstract type in the host bundle that will provide us later with the concrete implementation. Listing 8: Replace the call with the facade Then we create the facade we have introduced.ABOUT. 1 2 3 4 5 6 7 8 9 10 11 public abstract c l a s s A c t i o n F a c t o r y F a c a d e { private f i n a l s t a t i c A c t i o n F a c t o r y F a c a d e IMPL . As a concrete example we take the ActionFactory of the workbench. It defines several preconfigured actions to be integrated into the application. r e g i s t e r ( aboutAction ) . 1 2 a b o u t A c t i o n = ActionFactoryFacade .1 The problem Inevitably there are some differences between the two runtimes .

public c l a s s A c t i o n F a c t o r y F a c a d e Impl extends A c t i o n F a c t o r y F a c a d e { private c l a s s AboutAction extends A c t i o n implements IWorkbenchAction { private IWorkbenchWindow window .ABOUT. S t r i n g msg = MessageFormat . g e t S h e l l ( ) . M e s s a g e D i a l o g . } } Listing 11: Concrete type for RCP fragment For RAP we need to provide our own implementation of the ABOUT action here. org . . a c t i o n s . getName ( ) . throw new RuntimeException ( msg . o p e n I n f o r m a t i o n ( window . } public void run ( ) { S t r i n g t i t l e = ”About Message ” . org . window = window . Our final step is to create two different implementations of the behavior for the different runtimes. } catch ( Throwable t h r o w a b l e ) { S t r i n g t x t = ”Could n o t l o a d i m p l e m e n t a t i o n f o r { 0 } ” . s e t T e x t ( ”About RAP MailDemo ” ) . . j f a c e . u i . IWorkbenchAction . u i . new O b j e c t [ ] { name } ) . public AboutAction ( IWorkbenchWindow window ) { t h i s . } } Listing 12: Concrete type for RAP fragment 15 . l o a d C l a s s ( name + ”Impl ” ) . eclipse eclipse eclipse eclipse . . msg ) . } } IWorkbenchAction c r e a t e A b o u t A c t i o n I n t e r n a l ( IWorkbenchWindow window ) { return new AboutAction ( window ) . n e w I n s t a n c e ( ) . j f a c e . It should be implemented as the following snippet shows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public c l a s s I m p l e m e n t a t i o n L o a d e r { public s t a t i c O b j e c t n e w I n s t a n c e ( f i n a l C l a s s t y p e ) { S t r i n g name = t y p e . IWorkbenchWindow . } return r e s u l t . d i a l o g s . a c t i o n . c r e a t e ( window ) . t h r o w a b l e ) . MessageDialog . f o r m a t ( t x t . s e t I d ( ”about ” ) . S t r i n g msg = ”T h i s i s t h e about Message o f t h e RAP Mail Demo” . org . s e t T o o l T i p T e x t ( ”About RAP MailDemo ” ) . } } Listing 10: ImplementationLoader We now have a facade that encapsulates the required functionality and the ImplementationLoader. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import import import import org . try { r e s u l t = t y p e . g e t C l a s s L o a d e r ( ) .7 API Differences 12 } Listing 9: Abstract type in host bundle The purpose of the facade is to load the correct implementation of the ActionFactoryFacade and call their internal methods to create the requested objects. Action . A c t i o n F a c t o r y . The ImplementationLoader is therefore needed to load the implementation of the abstract type from the fragment. t i t l e . As mentioned above the implementation for the ABOUT action can simply be delegated to the original RCP equivalent. } public void d i s p o s e ( ) { window = n u l l . Object r e s u l t = null . 1 2 3 4 5 6 7 public c l a s s A c t i o n F a c t o r y F a c a d e Impl extends A c t i o n F a c t o r y F a c a d e { IWorkbenchAction c r e a t e A b o u t A c t i o n I n t e r n a l ( IWorkbenchWindow window ) { return A c t i o n F a c t o r y .

1 2 3 4 5 f i n a l Text t = new Text ( s h e l l . 8. setText ( ”here i s some text ” ) . } } }) . Running the same snippet with RWT you need to be careful as the events are merged into bigger chunks. The Eclipse Databinding framework is. RWT generally reduces the number of requests sent to the server and decreases server load by merging multiple events into one HTTP request.and VerifyListener of RWT do not behave exactly as their correspoinding parts in SWT. The following code snippet shows an example of this technique: 1 2 3 4 5 6 7 8 9 10 11 Text t x t D a t e = new Text ( p a r e n t . addFocusListener ( new FocusAdapter ( ) { S W T. based on VerifyListener s and thus is subject to the same restrictions. Over a high-latency network connection the SWT behavior can introduce significant performance degradation to the UI. setErrorMessage ( null ) . This can lead to a problem when you type more than 5 characters into the textfield. This can lead to semantic differences as the following example illustrates. public void focusLost ( FocusEvent event ) { 16 . in most situations.MULTI ) . 1 2 3 4 5 6 7 8 9 10 f i n a l Text t = new Text ( s h e l l . Imagine that we have a VerifyLister that restricts the length of a text field. public void verifyText ( VerifyEvent event ) { i f ( t . This has the advantage of producing more immediate feedback for the user regarding the data they are entering.BORDER t . d oi t = f a l s e . length ( ) > 5 ) { event . getText ( ) .not only for the events after the fifth character.BORDER t . for example. by focus events. } catch ( P a r s e E x c e p t i o n e ) { setErrorMessage ( ” I n v a l i d date ”) . SWT. addVerifyListener ( new VerifyListener ( ) { S W T. SWT.MULTI ) . Depending on the timing it could happen that the doit flag will be set to false for the whole chunk . t x t D a t e . This is especially interesting when utilizing the doit flag of the incoming event as this may match to several keystrokes instead of a single keystroke. getText ( ) ) . } } }) . t .BORDER) . Listing 13: Usage of ModifyListener Unfortunately the Modify . SWT.8 Field validation 8 Field validation 8. In the case of a high-latency network connection you should be careful when integrating the Databinding framework. This can be achieved by using listeners which instead of being triggered by keystrokes are triggered. This can be traced back to the distributed nature of RAP. Listing 14: Example of semantic differences With SWT this snippet works as expected.1 The problem A common pattern for form validation in RCP and SWT applications is to use the ModifyListener interface to implement keystroke-level validation of field data. a d d M o d i f y L i s t e n e r ( new M o d i f y L i s t e n e r ( ) { public void modifyText ( ModifyEvent e ) { try { date = f or matter . parse ( txtDate .2 Reduce the frequency of validation checks Depending on the latency of the network it may be a better approach to reduce the frequency of validations.

8 Field validation 6 7 8 9 10 11 12 13 i f ( t . setBackground ( Graphics . 17 . setBackground ( n u l l ) . getText ( ) . 0 . length ( ) = = 0 ) { t . getColor ( 255 . } } }) . } else { t . Listing 15: FocusListener for field validation With this approach the events only get fired on focus events no matter what happens inside the text field. 0 ) ) .

Listing 17: Creating a new color (JFace) There may be situations when it is not possible to use the JFace registries. new RGB( 2 5 5 . Color redColor = Graphics . 0 ) . Therefor RAP banned constructors from all SWT resources while providing factory methods for the following resource classes.2 Use higher-level API A pattern that frequently occurs is the use of use an abstraction layer above these APIs. swt . import o r g . 0 . g r a p h i c s . e c l i p s e . e c l i p s e . • org. Thus the concepts of SWT for acquiring system resources like colors or fonts cannot be carried over in exactly the same fashion.eclipse. g r a p h i c s .not recommended 18 . import o r g . G r a p h i c s . Starting with a simple SWT snippet which acquires a new color object. C o l o r R e g i s t r y . rwt . The big advantage is that this approach can be used in RCP and RAP so there is no need to have a different implementations.Image • org. g r a p h i c s . 0 ) . Under normal circumstances this is done by calling dispose on the resource object.swt. 1 2 3 4 5 6 7 import o r g .swt. 9. The above mentioned resources can also be obtained directly through the factory methods of RAP. 1 2 3 import o r g .RGB.we manage the lifetime of these objects with registries that JFace provides. we will implement the same behavior with the use of a ColorRegistry.eclipse. C o l o r . C o l o r r e d C o l o r = new C o l o r ( d i s p l a y . C o l o r R e g i s t r y r e g i s t r y = new C o l o r R e g i s t r y ( D i s p l a y . Neither the instantiation nor the recycling of resources needs to be done manually. C o l o r . swt .swt. swt . 0 ) ) . C o l o r . 0 .Font • org. swt . Listing 16: Creating a new color (SWT) Instead of initiating the color object directly. j f a c e . e c l i p s e . get ( ‘ ‘ redColor ’ ’ ) .eclipse. e c l i p s e . e c l i p s e . Instead of managing the resources yourself you let the registry do the work.9 SWT Resources 9 SWT Resources 9. Listing 18: Creating a new color (RWT) . 2 5 5 . In the case of resources you can use the *Registry classes that JFace already provides. e c l i p s e . These are available on the Graphics class introduced by RAP.Cursor When writing SWT code you are responsible for disposing all resources created in your code. r e g i s t r y .graphics. 1 2 3 4 5 import o r g . getColor ( 255 .Color • org.eclipse. g r a p h i c s . As this would invalidate the resources across all sessions. g r a p h i c s .1 The problem As RAP lives in a server environment the logic is only run on the server side while the client is responsible for showing the UI. RAP does not provide the dispose mechanism at all. import o r g .graphics.swt.graphics. RAP also lowers memory consumption on the server-side by reusing existing resources. Color redColor = r e g i s t r y . put ( ‘ ‘ r e d C o l o r ’ ’ . g e t C u r r e n t ( ) ) . 0 . r e s o u r c e .graphics.

19 . This results in an empty implementation for the RAP fragment. For the RCP implementation constructor would be used. An important item to note is that the resources in RCP need to be disposed manually.9 SWT Resources As the Graphics class is only available in RAP. the corresponding source artifact needs to be added to the RAP specific fragments.

A common implementation of an application-scoped singleton in RCP is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public c l a s s M y S i n g l e t o n { private s t a t i c M y S i n g l e t o n i n s t a n c e . Both the singleton and the provider interface should be created in the host bundle. The class is called SessionSingletonBase and is used as follows: 1 2 3 4 5 6 7 8 9 10 11 public c l a s s M y S i n g l e t o n { public s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { return ( M y S i n g l e t o n . [GHJV95] This pattern allows only one unique object instance of a class. One of the most common problems is the usage of the Singleton design pattern. } private M y S i n g l e t o n ( ) { // p r e v e n t i n s t a n c e c r e a t i o n } } Listing 19: Singleton (Application scope) To reduce the scope of the object instance to a specific session we use the concept of ’session singletons ’. c l a s s ) S e s s i o n S i n g l e t o n B a s e .10 Singletons and Scopes 10 Singletons and Scopes 10. As the fragments need to have the same interface for creating the instance we use an interface called ISingletonProvider. g e t I n s t a n c e ( M y S i n g l e t o n . c l a s s ) . 1 2 3 4 5 6 public c l a s s M y S i n g l e t o n { private s t a t i c f i n a l I S i n g l e t o n P r o v i d e r PROVIDER. } private M y S i n g l e t o n ( ) { // p r e v e n t i n s t a n c e c r e a t i o n } } Listing 20: Singleton (Session scope) Doing this behind a facade we can reuse the same concept as we used in chapter 7. c l a s s ) . } return i n s t a n c e . public s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { i f ( i n s t a n c e == n u l l ) { i n s t a n c e = new M y S i n g l e t o n ( ) . As RAP needs to serve several users at the same time this may not be the needed approach. } 20 .3 Move the instance creation to the fragments The instance creation is delegated to one of the fragment implementations by a common accessor. Most singletons should be unique per user. 10. 10. static { PROVIDER = ( I S i n g l e t o n P r o v i d e r ) I m p l e m e n t a t i o n L o a d e r . n e w I n s t a n c e ( M y S i n g l e t o n . with RAP we have not only one but an unlimited number of users.1 The problem As RAP is a multi-user and distributed runtime we need to make sure that everything which originally runs in a single-user mode will have the same semantics in the multi-user environment. In contrast to RCP. RAP already provides a helper class to create objects like this within the session scope.2 Use session singletons To make singletons aware of the user scope we need to restrict the singletons to a specific user session instead of one application-wide object.

} } Listing 24: Singleton Provider (RAP) With this architecture we are able to reuse the same code in RAP and RCP. public synchronized O b j e c t g e t I n s t a n c e I n t e r n a l ( ) { i f ( i n s t a n c e == n u l l ) { i n s t a n c e = new M y S i n g l e t o n ( ) . 21 . 1 2 3 4 5 6 7 public c l a s s M y S i n g l e t o n I m p l { public O b j e c t g e t I n s t a n c e I n t e r n a l ( ) { return S e s s i o n S i n g l e t o n B a s e . The singleton implementation lives in the host bundle and only the way it is initiated is platform-specific. 1 2 3 4 5 6 7 8 9 10 11 public c l a s s M y S i n g l e t o n I m p l { private s t a t i c M y S i n g l e t o n i n s t a n c e .10 Singletons and Scopes 7 8 9 10 11 12 13 14 15 16 public s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { return ( M y S i n g l e t o n ) PROVIDER. This implementation belongs to the RCP-fragment. we want to create a session-scoped singleton. } private M y S i n g l e t o n ( ) { // p r e v e n t i n s t a n c e c r e a t i o n } } Listing 21: Singleton (delegating stub) 1 2 3 public i n t e r f a c e I S i n g l e t o n P r o v i d e r { Object g e t I n s t a n c e I n t e r n a l ( ) . } } Listing 23: Singleton Provider (RCP) When running the application with multiple users. For RCP we implement the ISingletonProvider interface as a regular singleton. g e t I n s t a n c e ( M y S i n g l e t o n . c l a s s ) . This implementation belongs to the RAP-fragment. } Listing 22: Singleton Provider Interface As the singleton provider differs between the platform-specific fragments (singleton for RCP. g e t I n s t a n c e I n t e r n a l ( ) . sessionsingleton for RAP) we need to provide two different implementations of the interface. } return i n s t a n c e .

} } f i n a l JobRunnable Listing 27: Job Factory Implementation (RCP) 4 http://www. Listing 25: Abstract Job Factory To encapsulate the code that will be run in a job we introduced a JobRunnable. f i n a l S t r i n g name .org/articles/Article-Concurrency/jobs-api. c o r e . IProgressMonitor .11 Jobs and background threads 11 Jobs and background threads 11. However. public i n t e r f a c e JobRunnable { I S t a t u s run ( I P r o g r e s s M o n i t o r m o n i t o r ) . . r u n t i m e . c r e a t e J o b I n t e r n a l ( d i s p l a y . import o r g . run ( m o n i t o r ) . to access something session-specific like a session singleton you need to be careful. r u n t i m e . } }. Job . e c l i p s e . runnable ) { return IMPL . f i n a l S t r i n g name . r u n n a b l e ) .1 The Problem Utilizing jobs4 in RCP and RAP applications is a common pattern to process asynchronous work in the background. As background jobs run in the application scope and not in the session scope we need to provide the correct context for accessing session-specific objects. c l a s s ) . I S t a t u s . } abstract Job c r e a t e J o b I n t e r n a l ( D i s p l a y d i s p l a y . swt . swt . w i d g e t s . 1 2 3 4 5 6 import o r g . c o r e . } f i n a l JobRunnable S t r i n g name . runtime . D i s p l a y . e c l i p s e . D i s p l a y . e c l i p s e . c o r e .Runnable but has the ability to transfer the status of the job (see IStatus ). n e w I n s t a n c e ( J o b F a c t o r y . This has the same semantics as a regular java. public abstract c l a s s J o b F a c t o r y { private f i n a l s t a t i c J o b F a c t o r y IMPL . c o r e . Job . r u n t i m e . org . We work against an abstract facade in our host bundle and provide different implementations in each fragment. eclipse eclipse eclipse eclipse . The implementation for the RCP fragment is shown below. . j o b s . static { IMPL = ( J o b F a c t o r y ) I m p l e m e n t a t i o n L o a d e r . import o r g . . j o b s . runnable ) { return new Job ( name ) { protected I S t a t u s run ( I P r o g r e s s M o n i t o r m o n i t o r ) { return r u n n a b l e . org . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import o r g . r u n t i m e .eclipse.html 22 .lang. e c l i p s e . The facade is just a factory to return a new Job instance. runtime . org . public c l a s s J o b F a c t o r y I m p l extends J o b F a c t o r y { Job c r e a t e J o b I n t e r n a l ( f i n a l D i s p l a y d i s p l a y . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import import import import org . w i d g e t s . I P r o g r e s s M o n i t o r . c o r e . } public s t a t i c Job c r e a t e J o b ( f i n a l D i s p l a y d i s p l a y . } Listing 26: JobRunnable As RCP assumes only one user (session) we can execute the runnable in a regular job. JobRunnable r u n n a b l e ) .2 Use a facade The approach is the same as in chapter 7. 11. c o r e . name . I S t a t u s .

D i s p l a y . org . return j o b . l i f e c y c l e . IProgressMonitor . f i n a l S t r i n g name . c o r e . f i n a l JobRunnable runnable ) { Job j o b = new Job ( name ) { protected I S t a t u s run ( f i n a l I P r o g r e s s M o n i t o r m o n i t o r ) { f i n a l I S t a t u s [ ] r e s u l t = new I S t a t u s [ 1 ] . org .11 Jobs and background threads In the case of RAP we need to process the runnable inside an environment with a context. org . . c o r e . runtime . j o b s . eclipse eclipse eclipse eclipse eclipse . . UICallBack . c o r e . swt . Job . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package f a c a d e s . run ( m o n i t o r ) . . } }) . runtime . new Runnable ( ) { public void run ( ) { r e s u l t [ 0 ] = r u n n a b l e . org . runNonUIThreadWithFakeContext ( d i s p l a y . To do this RWT provides the method runNonUIThreadWithFakeContext. import import import import import org . public c l a s s J o b F a c t o r y I m p l extends J o b F a c t o r y { Job c r e a t e J o b I n t e r n a l ( f i n a l D i s p l a y d i s p l a y . . w i d g e t s . r u n t i m e . } }. I S t a t u s . UICallBack . rwt . } } Listing 28: Job Factory Implementation (RAP) 23 . return r e s u l t [ 0 ] .

c l a s s ) . This will just delegate the real work to a helper (eg. we cannot store language related information statically in Message Bundle classes as it is stored in RCP. Instead. c l a s s ) . we have to use a different instance of the Message class for every language. g e t M e s s a g e s ( M e s s a g e s . In order to use our own NLS mechanism we also need to ensure that the message class does not extend the NLS class of OSGi.3 Remove static initializer and supertype As with the static keyword for all message fields. } Listing 30: Accessor for Message classes 5 http://help.eclipse.user/concepts/concept-string-externalization. NLS . 3. NLSHelper ) which in turn gives us an instance of the class with all fields initialized with the corresponding strings. } private M e s s a g e s ( ) { } } Listing 29: Sample RCP Message class 12.org/ganymede/topic/org. u t i l .2 Make translatable strings non-static The first thing we need to do is remove the static modifier from all translatable messages. m e s s a g e s ” . public c l a s s M e s s a g e s extends NLS { private s t a t i c f i n a l S t r i n g BUNDLE NAME = ”maildemo . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import o r g . Therefore. 12. An example of such a message class can be found in the following. M e s s a g e s .1 specification (see §4.1 The problem In RAP we have to deal with different languages for different user sessions. 1 2 3 public s t a t i c M e s s a g e s g e t ( ) { return NLSHelper . i n i t i a l i z e M e s s a g e s (BUNDLE NAME.doc.3. The NLS class is part of the regular RCP internationalization mechanism 5 and follows the usage conventions of the OSGi 4.htm 24 . the language can also change between requests within the same session.6). //$NON −NLS−1 $ public public public public static static static static String String String String OpenViewAction OpenViewAction OpenViewAction OpenViewAction 0. 1. In our initial example we need to remove the static keyword from all OpenViewAction fields.12 Internationalization and localization 12 Internationalization and localization 12.jdt. In fact. We also have to provide an accessor to get an instance of our message class which is localized during runtime. we remove the static initializer from all translatable messages to avoid initializing the contents of the message fields when the class is loaded.eclipse. Otherwise the static messages would be shared across all sessions and we could not provide an internationlized application for each user. o s g i . e c l i p s e . static { // i n i t i a l i z e r e s o u r c e b u n d l e NLS . 2.

4 Create an NLSHelper and implementations The concept is the same as in chapter 7. . 1 2 3 4 5 6 7 8 9 import o r g . g e t M o d i f i e r s ( ) . } public s t a t i c M e s s a g e s g e t M e s s a g e s ( C l a s s c l a z z ) { return ( M e s s a g e s ) IMPL . Locale . getDefault () . } private O b j e c t i n t e r n a l G e t ( R e s o u r c e B u n d l e bundle . r e f l e c t . c o n s t r u c t o r . r e f l e c t . . c l a s s . ResourceBundle . getClassLoader () . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import import import import import import java java java java java java . Constructor . l e n g t h . } catch ( f i n a l E x c e p t i o n ex ) { throw new I l l e g a l S t a t e E x c e p t i o n ( ex . static { IMPL = ( NLSHelper ) I m p l e m e n t a t i o n L o a d e r . i f ( S t r i n g . } protected abstract O b j e c t i n t e r n a l G e t M e s s a g e s ( C l a s s c l a z z ) . i s A s s i g n a b l e F r o m ( f i e l d A r r a y [ i ] . c l a z z ) . . try { Constructor c o n s t r u c t o r = c l a z z . . . c l a s s ) . newInstance ( null ) . R e s o u r c e B u n d l e b u n d l e = R e s o u r c e B u n d l e . On our host bundle we have the abstract class which loads to platform-specific implementation from one of the fragments. n e w I n s t a n c e ( NLSHelper . c l a s s ) . C l a s s c l a z z ) { Object r e s u l t . This class helps to load the translated . i < f i e l d A r r a y . s e t A c c e s s i b l e ( true ) . r e s u l t = c o n s t r u c t o r .properties files into the class fields. One of these classes is RWT. . m e s s a g e s ” . getType ( ) ) 25 . MissingResourceException . rwt .rwt package. getDeclaredConstructor ( null ) . NLS . e c l i p s e . Listing 31: NLS Helper Facade RAP itself provides some helper classes in order to fully support multi-language applications. . The following snippet shows how to implement the NLSHelper. public c l a s s NLSHelperImpl extends NLSHelper { protected O b j e c t i n t e r n a l G e t M e s s a g e s ( C l a s s c l a z z ) { ClassLoader loader = c l a z z . M e s s a g e s .eclipse. i ++) { try { int m o d i f i e r s = f i e l d A r r a y [ i ] . . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public abstract c l a s s NLSHelper { protected s t a t i c f i n a l S t r i n g BUNDLE NAME = ”sample . g e t I S O 8 8 5 9 1 E n c o d e d (BUNDLE NAME. L o c a l e . loader ) . public c l a s s NLSHelperImpl extends NLSHelper { protected O b j e c t i n t e r n a l G e t M e s s a g e s ( C l a s s c l a z z ) { return RWT. g e t B u n d l e (BUNDLE NAME. } } Listing 32: RAP implementation for NLSHelper As RCP was never designed to support multiple languages during runtime we cannot reuse the NLS implementation of OSGi. We work against an abstract facade in our host bundle and provide different implementations in each fragment. g e t M e s s a g e ( ) ) . r e f l e c t . Therefore we need to provide our own solution as the following snippet shows. Modifier . getDeclaredFields () .RWT. lang lang lang util util util .NLS which can be found in the org.12 Internationalization and localization 12. Field . return i n t e r n a l G e t ( bundle . i n t e r n a l G e t M e s s a g e s ( c l a z z ) . f o r ( i n t i = 0 . . } final Field [ ] fieldArray = clazz . //$NON −NLS−1 $ private f i n a l s t a t i c NLSHelper IMPL . .

php 26 .registry from the RAP CVS6 2. those strings are replaced by unique keys.equinox. get ( ) . 1 2 3 public O b j e c t [ ] g e t E l e m e n t s ( O b j e c t p a r e n t ) { return new S t r i n g [ ] { M e s s a g e s . i s P u b l i c ( m o d i f i e r s ) && ! M o d i f i e r .rap. get ( ) . u i .org/rap/cvs. } } return r e s u l t . M e s s a g e s . Like in RCP.equinox. mre .5 Fix your message references Instead of accessing the static fields of the message classes we now need to reference the instance fields in our application. s e t A c c e s s i b l e ( true ) . g e t S t r i n g ( f i e l d A r r a y [ i ] . e c l i p s e . HelloWorldView ” name=”%helloWorldView name ”> </ view> </ e x t e n s i o n> <e x t e n s i o n p o i n t=” o r g .registry into your workspace. set ( result . h e l l o W o r l d V i e w ” c l a s s=” o r g . i s S t a t i c ( m o d i f i e r s ) ) { try { S t r i n g value = bundle . h e l l o w o r l d .6 Localize the plug-in manifest Extension definitions in the plug-in manifest file can also contain strings that are subject to internationalization. e c l i p s e .properties file that resides in the root directory of the plug-in. prefixed with a % sign. View 2 . i f ( v a l u e != n u l l ) { f i e l d A r r a y [ i ] . } } } catch ( f i n a l E x c e p t i o n ex ) { ex . u i . } Listing 34: Instance fields instead of static fields With this approach we can serve multi-lingual applications with support for multiple concurrent languages . 1 2 3 4 5 6 7 8 9 10 11 <e x t e n s i o n p o i n t=” o r g . the internationalized version of the HelloWorld plug-in manifest file contains placeholders for the names of the view and the perspective.12 Internationalization and localization 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 && M o d i f i e r . v i e w s ”> <view i d=” o r g . s e t A c c e s s i b l e ( true ) .eclipse. h e l l o w o r l d . get ( ) . f i e l d A r r a y [ i ] . View 1 . p e r s p e c t i v e s ”> 6 http://www.eclipse. The keys are then resolved in a plugin. For example. The plug-in manifest file (plugin. r a p . } } catch ( f i n a l M i s s i n g R e s o u r c e E x c e p t i o n mre ) { f i e l d A r r a y [ i ] . s e t ( r e s u l t . e c l i p s e . getName ( ) ) . value ) . e c l i p s e . check out the fragment org.eclipse. M e s s a g e s . 12. ””) . r a p . In order to get this working there are a few prerequisites: 1. include the plug-in org. View 3 }.xml) may also contain translatable strings. } } Listing 33: RCP implementation of the NLSHelper 12. fieldArray [ i ] .for both RCP and RAP. p r i n t S t a c k T r a c e ( ) . p r i n t S t a c k T r a c e ( ) .

e c l i p s e . To launch the application from Eclipse.xml with placeholders And here’s the plugin. p e r s p e c t i v e ” c l a s s=” o r g .12 Internationalization and localization 12 13 14 15 16 17 18 <p e r s p e c t i v e i d=” o r g . r a p . r a p . To solve this. 27 . RAP requires special treatment to support the internationalization of extensions because of its server-side. However the Equinox extension registry does the translation on startup and caches the results.properties: 1 2 helloWorldView name = H e l l o World View p e r s p e c t i v e n a m e = H e l l o World P e r s p e c t i v e Listing 36: plugin. P e r s p e c t i v e ” i c o n=” i c o n s / i c o n . h e l l o w o r l d . e c l i p s e .MF In summary.equinox. g i f ” name=”%p e r s p e c t i v e n a m e ”> </ p e r s p e c t i v e> </ e x t e n s i o n> Listing 35: Sample plugin. you need to import the plug-in org. not from the target platform).properties To make this work.MF) must contain the following line: 1 Bundle − L o c a l i z a t i o n : plugin Listing 37: MANIFEST. multi-user nature.registry as source plug-in into your workspace. we had to exploit the translation mechanism of the Equinox extension registry.eclipse. In RAP. h e l l o w o r l d . Make sure that this plug-in is also included in the launch configuration (from the workspace. the OSGi manifest file (MANIFEST. different sessions may require translations into different languages.

. . . . Examplary Activator . Concrete type for RCP fragment . . . . . . Singleton Provider (RCP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abstract Job Factory . . . . . . . . . . . . . . . . Sample plugin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Creating a new color (SWT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . RCP implementation of the NLSHelper . . . . . . . . . . . . Instance fields instead of static fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xml with placeholders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example of semantic differences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sample fragment. . . . . . . . . . 7 11 List of Tables 1 Bundle Naming Scheme . . . . . . Job Factory Implementation (RAP) . . . . Extended single sourcing . . . . . . . NLS Helper Facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ImplementationLoader . . . . . . . . . . . Job Factory Implementation (RCP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sample RCP Message class . . . . . . . . . . . . . . . .Listings List of Figures 1 2 The RCP and RAP APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Concrete type for RAP fragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . JobRunnable . . . plugin. .xml . . . Abstract type in host bundle . . . . . . . . . . . . MANIFEST. . . . . . . Singleton Provider (RAP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Accessor for Message classes . . . . . . . . . . . . . . . . . . . . . . . . . . . Singleton Provider Interface . . . . Creating a new color (RWT) . . . . . . . .MF . . . . . . .not recommended Singleton (Application scope) . . . . . . . . . . . . . . FocusListener for field validation . . . . . . . . . . . . . . . . Usage of ModifyListener . . . . . . . . . . . . . . . . . . . . Singleton (delegating stub) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Creating a new color (JFace) . . . plugin. .xml . . . . . . . . . . . . . . . . . . . . . . Examplary entrypoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . RAP implementation for NLSHelper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Replace the call with the facade . . . . . . . . . . . . . . . . . . . . . . . . . . . Singleton (Session scope) . . . . . . . . . . . . Optional bundle requirements . . . . . . . . . . . . . . . . .properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Listings 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Importing a split package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 12 13 13 13 14 14 14 15 15 15 16 16 16 18 18 18 20 20 20 21 21 21 22 22 22 23 24 24 25 25 25 26 26 27 27 28 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 1999. David Holmes. OSGi Service Platform: The OSGi Alliance. [FBB+ 99] Martin Fowler. Addison-Wesley Professional. S. and Don Roberts. 2005. Wilson. January 1995. William Opdyke. Guy Steele. James Gosling. Refactoring: Improving the Design of Existing Code (The Addison-Wesley Object Technology Series). 29 . John Brant. Gilad Bracha. IOS Press. December 2003. Frank Yellin. SWT: the standard widget toolkit. Frank Yellin. [All03] Osgi Alliance. Guy Steele. [GHJV95] Erich Gamma. 2004. The Java Team. Rosanna Lee. Richard Helm. Mary Campione. Volume 1. Ralph Johnson. and John Vlissides. James Gosling. and Gilad Bracha. Kent Beck. Bill Joy. Addison-Wesley Professional. Java language specification. Jonni Kanerva. James Gosling. Bill Joy. Kathy Walrath. [NW04] Design Patterns. Patrick Chan.References References [AHL+ 05] Ken Arnold. Northover and M. James Gosling. third edition. Tim Lindholm. Boston: AddisonWesley.