Jump to: navigation, search

E4/position papers/Frank Appel

< E4
Revision as of 07:15, 10 September 2008 by Fappel.innoopract.com (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Bio

Frank Appel is the technical lead on the Eclipse Rich Ajax Platform (RAP) project. At Innoopract, a recognized leader in Eclipse distribution and web application development, Frank led the team that developed the W4Toolkit, the base code donation for the RAP project. Frank was also responsible for developing W4T Eclipse, a visual web application development tool for the W4Toolkit. He has been developing Eclipse extensions since 2002, having joined the Java world in 2000 after a short stopover in Visual Basic and Delphi programming.


RAP Experience Report on E4/Work Area items

Here are some comments on some of the items of the E4/Work Areas /http://wiki.eclipse.org/E4/Work_Areas page. These comments are based on the experince we have made with the RAP project on these topics. Note that the solutions we provide for some of the problems in RAP are only ment as a starting point for discussion.


SWT and RWT

RAP was created to provide RCP developers a possibility to bring (at least parts of) their RCP applications to the web without the need to step deep into the low-level web-technologies. The reason for this is cost reduction by reuse of knowlege and code. Therefore we have chosen the technical approach that provides the highest possible reusability - a thin client with a rich widget set and a stateful serverside on top of OSGi, reusing the eclipse workbench paradigm.

With respect to this goal and the distributed nature of the environment it's clear that RWT can only provide a subset of functionality of SWT. So currently missing functionality leads with RWT to missing API. Transforming SWT code into RWT ends up with compile errors if functionality is used that isn't available in RWT. This helps to identify problems at compile time, which we preferred to the error-prone process of finding out about missing functionality at runtime.

Also there are certain additional APIs for web-specifics, not available in SWT of course (some of them are mentioned in the chapters below).

It is obvious that the more SWT functionality is provided by RWT the more reuse of code based on SWT can be done. So it would be great to achieve a solution where RWT is just the 'web-SWT' - fragment. But still there are some difficulties e.g. regarding missing GC support (how to draw on the webbrowser with javascript? The current available possibilities do not scale) and the different resource management (colors, fonts and images are no system resources on the server, they are shared between sessions and therefore don't provide constructors and dispose methods).

Session Support

As RAP is inherent server centric it has to deal with the three scopes an object can belong to on the server: request-, session- and application scope.

The lifetime of objects in request scope spans at most a certain request lifecycle. Objects in request scope are only visible for the current request. Several internal datastructures of RWT use this scope, e.g. the datastructure that helps to determine the status delta that has to be sent to the client. ServletRequest#setAttribute(String,Object) and ServletRequest#getAttribute(String) are used for storing objects in request scope in servlet environment.

The lifetime of objects in session scope spans at most all the requests that belong to a certain client. Objects that belong to a certain session can not be referenced by another session but they are visible for each request that belongs to the session. HttpSession#setAttribute(String,Object) and HttpSession#getAttribute(String) are used for storing objects in session scope in servlet environment.

Last but not least objects in application scope span at most the lifetime of the whole application and are accessible for each request and each session. Objects in application scope can be stored in class variables.

To handle this scopes RAP maps a context to each request thread using a ThreadLocal. With this context in place it's possible to use request, response and session references at any place in the code, without transfering them all the time in method parameters. At the start of the request's lifecycle the context gets mapped and at the end it get's disposed of:


   try {
     ServiceContext context = new ServiceContext( request, response );
     ContextProvider.setContext( context );
     
     [...]
     // processing of lifecycle
     [...]

   } finally {
     ContextProvider.disposeContext();
   }                                                         

Access to the http session for example can be done using:


   RWT.getRequest().getSession()
 

As RCP applications generally are single user clients using singletons is a quite common practice. Trying to transfer this practice to RAP there arises a problem. Singletons use class variables for storing the singleton instance. But this puts the instance in application scope in RAP. To solve this problem, but providing a similar programming pattern RAP provides a class called SessionSingletonBase which allows to access unique instances of types per session.

SessionSingletonBase provides a convenience method


   public static Object getInstance( final Class type )
   
   

that allows to create singletons that can be used like singletons in RCP:


 static class MySingleton {
   
   private MySingleton() { //prevent instance creation }
   
   public static MySingleton getInstance() {
     return ( MySingleton )getInstance( MySingleton.class );
   }
 }

This works fine as long as the access to the singleton is done in the request thread. Background threads don't have a context mapped, so they will fail accessing the singletons. In RWT there is API to deal with this too:


   UICallBack#runNonUIThreadWithFakeContext(Display,Runnable)
   

Besides that the name isn't very good, this method executes the given runnable in the current thread but mapping a context that allows access to a certain session. The session is determined using the display instance, since in RWT display and session live in a one to one relationship.

Multi Locale Support

In consideration of the things mentioned in the section Session Support it's clear that the multi locale support of RCP doesn't work in server environments as the translated values of the messages classes are stored in class variables.

To keep the advantage of typesafety we moved the class variables of the messages classes in fields. For a certain locale a certain instance of that message class is provided. This instance can be retrieved using a static get method to access the locale aware translation:


   public class WorkbenchMessages {
    private static final String BUNDLE_NAME
       = "org.eclipse.ui.internal.messages";//$NON-NLS-1$
   
     [...]
     
    // --- File Menu ---
    public String NewWizardAction_text;

     [...]
   
     public static WorkbenchMessages get() {
       Class clazz = WorkbenchMessages.class;
       Object result = RWT.NLS.getISO8859_1Encoded( BUNDLE_NAME, clazz );
       return ( WorkbenchMessages )result;
     }
   }

Usage may look like this:


   page.setDescription(WorkbenchMessages.get().NewWizardNewPage_description);
   

RWT looks up the locale either in the session and if none is given there it evaluates the current request. If no request is available it uses the system locale as fallback.

This helps with common translation in code, but it doesn't help with translation of labels in extension-points. To achieve this we had to use a patch fragment for org.eclipse.equinox.registry. The patch fragment prevent the translation of labels in the registry code, since this would be a one-time-per-applicaton translation. The translation now takes place by the time an extension is materialized.