Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "RAP/FAQ"

< RAP
(How do I use a RWT standalone application in Tomcat)
(How do I use a RWT standalone application without a server)
Line 905: Line 905:
  
 
=== How do I use a RWT standalone application without a server ===
 
=== How do I use a RWT standalone application without a server ===
 +
 +
In order to demonstrate the usage of RAP without the integration of the application in an existing server environment a RAP standalone application can be created as follows. 
 +
# Add the following plugins to the RAP target runtime or create a new target runtime including the two plugins and your "old" RAP target runtime
 +
## org.eclipse.equinox.launcher
 +
## org.eclipse.equinox.launcher.(win/linux/...) depending on your operating system.
 +
# Rebuild your project with this new target runtime
 +
# Create a new "product configuration" file (i.e. standalone.product) and open it with the procut configuration file editor.
 +
# On the "Overview" page enter the following values
 +
## Name: StandAlone
 +
## Product: Select the plugin project containing the product definition with the "New..." Button.
 +
## Application: org.eclipse.ui.workbench
 +
# On the "Dependency" page enter the plugins and fragments required. Don't forget the jetty server and the rap plugins.
 +
# On the "Configuration" page set the start level and the auto-start behaviour. This takes its time.
 +
# On the "Launching" you can name the launcher (i.e. StandAlone)
 +
# Save the file and go back to the Overview page.
 +
# Use the "Eclipse Product export wizard" in order to create a RCP/RAP launcher in a dedicated directory.
  
 
=== Why are there encoding issues after deploying my RAP application as a WAR?  ===
 
=== Why are there encoding issues after deploying my RAP application as a WAR?  ===

Revision as of 08:49, 27 November 2009

| RAP wiki home | RAP project home |

This FAQ is still developing. Please also scan the RAP newsgroup archives for answers.

Contents

Getting Started

I found a bug in RAP. Where should I report it?

The best way to report a problem or request a new feature in RAP is to use the Bugzilla system. Please follow the instructions in RAP Bug Reporting Howto when submitting a bug report. More details are provided on the RAP Project Bugs page.

Writing RAP Applications

How to create a fullscreen application

  • use the style-bit SWT.NO_TRIM before creating the Shell. This will remove the title-bar, the minimize/maximize/close buttons and the ability for manually resizing the window.
  • overwrite the WorkbenchWindowAdvisor.postWindowCreate() method. Here we set the state of the Shell to maximized.
  • optional: depending on the requirements and complexity of our application it may be desirable to hide the menu bar by calling getWindowConfigurer().setShowMenuBar( false ). This is usually a good choice for small applications where the menu bar may not be needed.
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
 
  // ...
 
 public void preWindowOpen() {
   // ...
   getWindowConfigurer().setShellStyle( SWT.NO_TRIM );
   getWindowConfigurer().setShowMenuBar( false );
 }
 
 public void postWindowCreate() {
   Shell shell = getWindowConfigurer().getWindow().getShell();
   shell.setMaximized( true );
 }
}

Take a look here for a more detailed discussion of the topic.

How do I add an applet / flash / an existing Javascript libary

  • A very simplistic approach is to create a html page (or a servlet) containing your applet / flash / JS. You can simply use the browser widget to load that page within your application.
  • A tighter integration can be achieved by developing a custom widget as explained here (integrating GMap): custom widget tutorial

How to access the request parameters?

Let's suppose that the request URI looks like the following:

 http://www.example.com:8080/rap?startup=foo&var1=value1&var2=value2

To snippet below will retrieve the values of request parameters var1 and var2.

   HttpServletRequest request = RWT.getRequest();
   String var1 = request.getParameter( "var1" );
   String var2 = request.getParameter( "var2" );

How to access the HTTP session / session store?

In RAP, the sessoin store is the preferred way to store information in the session context. However it also provides access to the HTTP session (see the code below). For working with session singletons, please use the SessionSingletonBase class.

Access the HTTP session / session store from the UI thread: HttpSession session = RWT.getSessionStore().getHttpSession();

Access the HTTP session / session store from a background thread:

  final Display display = new Display();
  final Runnable bgRunnable = new Runnable() {
    public void run() {
      UICallBack.runNonUIThreadWithFakeContext( display, new Runnable() {
        public void run() {
          Object someValue = RWT.getSessionStore().getAttribute( "myAtt" );
          System.out.println( someValue );
          // access the HTTP session
          RWT.getSessionStore().getHttpSession();
        }
      } );
    }
  };
  Shell shell = new Shell( display );
  Button button = new Button( shell, SWT.PUSH );
  button.setText( "Start Background Thread" );
  button.addSelectionListener( new SelectionAdapter() {
    public void widgetSelected( final SelectionEvent evt ) {
      RWT.getSessionStore().setAttribute( "myAtt", "someValue" );
      Thread thread = new Thread( bgRunnable );
      thread.setDaemon( true );
      thread.start();
    }
  } );

No context available outside of the request service lifecycle

Why am I getting the exception java.lang.IllegalStateException: No context available outside of the request service lifecycle.?

Your code tries to access session-information but isn't run from the UI thread (the only thread that has a session context associated by default).

The soltion is to wrap your code in a Runnable and have it executed by UICallBack#runNonUIThreadWithFakeContext().

Please also see this thread: [1]

How to integrate the Eclipse Help System in a RAP application?

Applies to RAP 1.1 and 1.2

An example of how to integrate the Eclipse Help webapplication org.eclipse.help.webapp into a RAP application is provided here File:Org.eclipse.rap.help.integration.zip.

After importing the example project, the following plugins have to be added, since they are not included in the RAP target:

  • javax.servlet.jsp
  • org.apache.commons.el
  • org.apache.jasper
  • org.apache.lucene.analysis
  • org.apache.lucene
  • org.eclipse.equinox.jsp.jasper.registry
  • org.eclipse.equinox.jsp.jasper
  • org.eclipse.help.appserver
  • org.eclipse.help.base
  • org.eclipse.help.webapp
  • org.eclipse.help

The plug-ins mentioned above should be taken from a "suitable" Eclipse installation. Currently (RAP 1.2) this is version 3.4.

Please note that the included launch configuration must be used. It contains the -Dorg.eclipse.equinox.http.jetty.other.info=org.eclipse.help VM argument. Furthermore, the launch config assumes that the "RAP plug-ins" (...workbench etc.) are in your workspace. The target only contains the "Base plug-ins" (...equinox, ..core.runtime). In case your setup differs, you will need to adjust it.

Applies to RAP 1.3

As RAP 1.3 (starting from M2) delivers the infrastructure for the Help system, some of the facts above need to be adjusted. RAP itself only provides the core infrastructure for (like org.eclipse.help) but without the concrete implementation. This means you still need the plug-ins mentioned above (except org.eclipse.help). In case you don't need a sophisticed help solution (no dynamic help, no interaction with cheatsheets, no context help) the solution above is still sufficient. If you need better help integration (which is normally handled by org.eclipse.help.ui) you need to provide your own help ui contributions. This can be achieved by extending the org.eclipse.ui.helpSupport extension point.

An example of contributing a new helpSupport extension can be found in in this project: File:RapHelpSupport.zip.

How to integrate BIRT?

Please read Integrating BIRT into RAP applications to get started.

How to use expression-based activities for role-based access control?

The expression-based activities can be used to restrict the access to UI elements based on user roles. The following example defines an action demo.xyz.Action1.

  <extension point="org.eclipse.ui.actionSets">
    <actionSet id="demo.actionSet1" label="Admin tools" visible="true">
      <menu id="demo.AdminMenu" label="Admin Menu" path="additions">
        <groupMarker name="groupMarker1"/>
      </menu>
      <action class="demo.Action1" id="demo.xyz.Action1"
        label="Action 1" menubarPath="demo.AdminMenu/groupMarker1"
        style="push">
      </action>
    </actionSet>
  </extension>

Let's suppose that this action should be available only to users with role admin. We will create an expression-based activity demo.Activity1, which will be enabled when the variable demo.roles contains the string admin. Trough the associated pattern binding, the activity will control the availability of the demo.xyz.Action1 action and the corresponding menu item.

  <extension point="org.eclipse.ui.activities">
    <activity id="demo.Activity1" name="Admin menu access control">
      <enabledWhen>
        <with variable="demo.roles">
          <iterate ifEmpty="true" operator="or">
            <equals value="admin">
            </equals>
          </iterate>
        </with>
      </enabledWhen>
    </activity>
    <activityPatternBinding activityId="demo.Activity1"
      pattern="demo/.*xyz.*">
    </activityPatternBinding>
  </extension>
  <extension point="org.eclipse.ui.services">
    <sourceProvider provider="demo.AuthenticationProvider">
      <variable name="demo.roles" priorityLevel="workbench">
      </variable>
    </sourceProvider>
  </extension>

The value of the demo.roles variable is provided by a subclass of AbstractSourceProvider. A dummy implementation is shown below. The actual implementation should obtain the current user roles from a real authentication provider service.

 public class AuthenticationProvider extends AbstractSourceProvider {
 
  public final static String ROLES_VARIABLE = "demo.roles";
 
  public void dispose() {
    //
  }
 
  public Map getCurrentState() {
    // DUMMY CODE! Get the roles from a real authentication service!
    Map result = new HashMap();
    List foo = new ArrayList();
    foo.add( "user" );
    foo.add( "manager" );
    foo.add( "admin" );
    result.put( ROLES_VARIABLE, foo );
    return result;
  }
 
  public String[] getProvidedSourceNames() {
    return new String[]{
      ROLES_VARIABLE
    };
  }
 
  public void updateRights() {
    fireSourceChanged( 0, getCurrentState() );
  }
 }

A small application, which illustrates the outlined approach, can be found here: File:Activities-roles-demo.zip

What is a Session Singleton and how can I implement one?

A "session singleton" is an RWT-specific singleton, which provides access to a unique instance with session scope. This means that in the context of one user session getInstance(Class) will always return the same object, but for different user sessions the returned instances will be different. To archive it's "magic", session singletons should call SessionSingletonBase#getInstance(), which takes care of the proper scoping of the singleton instances. The following code snippet illustrates this pattern:

public class MySessionSingleton {
  private MySessionSingleton() {
    // prevent instantiation from outside
  }
 
  public static MySessionSingleton getInstance() {
    return ( MySessionSingleton )SessionSingletonBase.getInstance( MySessionSingleton.class );
  }
  // add other methods ...
}

Accessing session singletons is possible only from threads which are associated with a session. The UIThread always has a such an association, therefore any code running in this thread can freely access session singletons. Any non-UI (i.e. "background") thread, trying to access session singletons, will fail and a java.lang.IllegalStateException will be thrown. The solution is to temporarily associate the thread with a session. Use UICallBack#runNonUIThreadWithFakeContext, to fakes a "request context" that allows the runnable code to access those singletons.

The following code snippet throws an exception because the Runnable is executed in a background thread, with no access to the session singleton.

// INCORRECT
// will throw IllegalStateException: No context available outside of the request service lifecycle.
Runnable runnable = new Runnable() {
  public void run() {
    MySessionSingleton sessionSingleton = MySessionSingleton.getInstance();
    // do something with the session singleton
  }
};
new Thread( runnable ).start();

Here the Runnable is executed via UICallBack.runNonUIThreadWithFakeContext which will provide the context, required for accessing the session singleton.

// CORRECT
final Display display = Display.getCurrent();
final Runnable runnable = new Runnable() {
  public void run() {
    UICallBack.runNonUIThreadWithFakeContext( display, new Runnable() {
      public void run() {
        MySessionSingleton sessionSingleton = MySessionSingleton.getInstance();
        // do something with the session singleton
      }
    } );
  }
};
new Thread( runnable ).start();

How to add a Welcome page to a RAP application?

To register a resource that is available at the root URL of the web application, e.g. http://www.example.com/rapdemo/, you can do the following:

  • Register a welcome page resource with an alias:
<extension
      point="org.eclipse.equinox.http.registry.resources">
   <resource
         alias="/welcomepage"
         base-name="/html/index.html">
   </resource>
</extension>
  • Provide a servlet that redirects all GET requests to the welcomepage resource alias:
public class MyRedirectServlet extends HttpServlet {
 
  protected void doGet( HttpServletRequest req, HttpServletResponse resp )
    throws ServletException, IOException
  {
    resp.sendRedirect( resp.encodeRedirectURL( "welcomepage") );
  }
}
  • Register the redirect servlet with the root URL:
<extension
      point="org.eclipse.equinox.http.registry.servlets">
   <servlet
         alias="/"
         class="com.example.rapdemo.MyRedirectServlet">
   </servlet>
</extension>

Note: the redirect servlet is needed here since registering a welcome page resource directly for the "/" alias does not work: a trailing slash would be appended to the resource URL.

I do ... in my bundle activator. Does not work as expected in RAP.

RAP differs from RCP in a way that RCP applications don't have to deal with session scopes but RAP applications have to. In RCP for example you can get access the one and only UI representation instance (your workbench) from every part of the code since application scope and session scope are implicitly the same.

Since you have a multi user environment in RAP (=> multiple Sessions at a time) but only one application wide equinox instance running which is shared between those sessions (application scope) things getting a little bit more complicated. Each session has its own workbench instance since the state of the UIs differ between sessions. So in principle you can easily access the core from the UI, but the other way round isn't possible without additional code.

So what's happening in your code is that you try to access your GUI layer (session scope) from the bundle activator (application scope), which isn't possible as was just explained. Most of the time it is easy to move the code from the activator to the IEntryPoint#createUI or IStartup#earlyStartup. Both methods are executed in session scope context, so there won't be any IllegalStateExceptions thrown.

How to provide download link?

To provide download functionality in a RAP (or pure RWT) application, you need two components:

  • a custom service handler (implementation of IServiceHandler) to handle the download request outside the standard RWT request lifecycle;
  • an instance of the Browser containing an HTML Anchor tag, on which the user shall click to start the download.

The service handler

Below is an example of a very basic downloads service handler. The request has a parameter "filename" which indicates which content (either static or dynamically generated) should be sent to the client. The MyDataStore will known how to find the required content. In our example the content is retrieved as byte[] but InputStreams and Readers can be easily accommodated as well.

 public class DownloadServiceHandler implements IServiceHandler {
 
  public void service() throws IOException, ServletException {
    // Which file to download?
    String filename = RWT.getRequest().getParameter( "filename" );
    // Get the file content 
    byte[] download = MyDataStore.getByteArrayData( filename );
    // Send the file in the response.
    HttpServletResponse response = RWT.getResponse();
    response.setContentType( "application/octet-stream" );
    response.setContentLength( download.length );
    response.setHeader( "Content-Disposition", "attachment; filename=\""
                                               + filename
                                               + "\"" );
    try {
      response.getOutputStream().write( download );
    } catch( IOException e1 ) {
      e1.printStackTrace();
    }
  }
 }

The service handler has to be registered:

 RWT.getServiceManager()
      .registerServiceHandler( "downloadServiceHandler",
                               new DownloadServiceHandler() );

The Browser with the anchor tag

To start the actual download, we shall provide the user with a hyperlink to click on. It can be attached either to text or image, depending of the UI design requirements. An appropriate CSS style definition can be used to blend the hyperlink with the rest of the UI.

  private void createDownloadLink( Composite parent ) {
    Browser browser = new Browser( parent, SWT.NONE );
    browser.setText( createDownloadHtml( "foo.txt", "Download file" ) );
  }
 
  private String createDownloadHtml( String filename, String text ) {
    StringBuilder html = new StringBuilder();
    html.append( "<a href=\"" );
    html.append( createDownloadUrl( filename ) );
    html.append( "\">" );
    html.append( text );
    html.append( "</a>" );
    return html.toString();
  }
 
  private String createDownloadUrl( String filename ) {
    StringBuilder url = new StringBuilder();
    url.append( RWT.getRequest().getContextPath() );
    url.append( RWT.getRequest().getServletPath() );
    url.append( "?" );
    url.append( IServiceHandler.REQUEST_PARAM );
    url.append( "=downloadServiceHandler" );
    url.append( "&filename=" );
    url.append( filename );
    String encodedURL = RWT.getResponse().encodeURL( url.toString() );
    return encodedURL;
  }

How to switch language on user action?

Switching the language in a running session isn't supported out of the box. So currently you'll have to restart the session to be able to switch the language of a running RWT application.

To restart the session, we shall send some Javascript code, which changes the parent.window.location.href DOM attribute of the current page. The new parent.window.location.href value is the URL of the current page plus a new parameter which contains the selected language code.

Restarting the session and passing the new locale as a parameter

The changeLocale method is invoked when the user requests a language change (e.g. from a selection listener attached to some UI widget). In order to add page-reloading Javascript code to the HTTP response, we register a life-cycle PhaseListener:

  protected void changeLocale( String locale ) {
    final String url = createUrl( locale  );
    final Display display = Display.getCurrent();
    RWT.getLifeCycle().addPhaseListener( new PhaseListener() {
 
      private static final long serialVersionUID = 1L;
 
      public void afterPhase( PhaseEvent event ) {
        if( display == Display.getCurrent() ) {
          try {
            // Uses a non-public API, but currently this is the only solution.
            HtmlResponseWriter writer = ContextProvider.getStateInfo()
              .getResponseWriter();
            writer.write( "parent.window.location.href=\"" + url + "\";" );
          } catch( IOException e ) {
            e.printStackTrace();
          }
          RWT.getLifeCycle().removePhaseListener( this );
        }
      }
 
      public PhaseId getPhaseId() {
        return PhaseId.RENDER;
      }
      ...
    } );
  }
 
  private String createUrl( String locale ) {
    StringBuffer url = new StringBuffer();
    url.append( RWT.getRequest().getContextPath() );
    url.append( RWT.getRequest().getServletPath() );  
    url.append( "?locale=" );
    url.append( locale );
    return RWT.getResponse().encodeURL( url.toString() );
 }

Getting the locale from the URL parameter

Before creating the UI, set the locale to the value, retrieved from the URL parameter:

  public int createUI() {
    String locale = RWT.getRequest().getParameter( "locale" );
    if( locale != null ) {
      RWT.setLocale( new Locale( locale ) );
    }
    // Create the UI
    ...
  }

How to display dynamically created images?

  • Create an instance of Browser widget to place the image in the UI
  • Create an image, e.g. using java.awt.Graphics2D
  • Use a custom service handler to deliver the image.

Create a Browser widget to render the image

To place the image in the application UI, we use a Browser widget with a single HTML img tag. The URL in the src attribute contains a key, used to identify the generated image.

 
  private final static String SERVICE_HANDLER = "imageServiceHandler";
  private final static String IMAGE_KEY = "imageKey";
 
    ...
    // register the service handler
    RWT.getServiceManager().registerServiceHandler( SERVICE_HANDLER,
                                                    new ImageServiceHandler() );
    // create a Browser to display the image
    Browser browser = new Browser( shell, SWT.NONE );;
    // create the image
    BufferedImage image = createImage();
    // store the image in the SessionStore for the service handler
    RWT.getSessionStore().setAttribute( IMAGE_KEY, image );
    // create the HTML with a single <img> tag.
    browser.setText( createHtml( IMAGE_KEY ) );
    //
    ...
 
  private String createHtml( String key ) {
    StringBuffer html = new StringBuffer();
    html.append( "<img src=\"" );
    html.append( createImageUrl( key ) );
    html.append( "\"/>" );
    return html.toString();
  }
 
  private String createImageUrl( String string ) {
    StringBuffer url = new StringBuffer();
    url.append( RWT.getRequest().getContextPath() );
    url.append( RWT.getRequest().getServletPath() );
    url.append( "?" );
    url.append( IServiceHandler.REQUEST_PARAM );
    url.append( "=" );
    url.append( SERVICE_HANDLER );
    url.append( "&imageId=" );
    url.append( string );
    url.append( "&nocache=" );
    url.append( System.currentTimeMillis() );
    String encodedURL = RWT.getResponse().encodeURL( url.toString() );
    return encodedURL;
  }
}

Create the image

Use java.awt.Graphics2D as a canvas on which to draw the image. The server, where the application will be deployed, most probably has no graphics UI system installed. Therefore we need to run AWT in "headless mode" by setting the system property java.awt.headless to true:

 -Djava.awt.headless=true

In the example below, the produced BufferedImage is placed in the SessionStore and the key is used to generate the new <img> tag for the Browser.

  private BufferedImage createImage() {
    BufferedImage image = new BufferedImage( 200, 200, BufferedImage.TYPE_INT_ARGB );
    Graphics2D gr2d = image.createGraphics();
    // draw the image
    gr2d.setColor( new Color( 0, 0, 255 ) );
    gr2d.drawRect( 0, 0, widht - 1, height - 1 );
    ...
    return image;
  }

Service Handler

The service handler has to be registered with RWT.getServiceManager().registerServiceHandler() - see the first code snippet above. The handler receives the image key as a request parameter, and uses it to retrieve the image from the SessionStore.

    public class ImageServiceHandler implements IServiceHandler {
 
      public void service() throws IOException, ServletException {
        String id = RWT.getRequest().getParameter( "key" );
        BufferedImage image = ( BufferedImage )RWT.getSessionStore()
          .getAttribute( id );
        HttpServletResponse response = RWT.getResponse();
        response.setContentType( "image/png" );
        try {
          ServletOutputStream out = response.getOutputStream();
          ImageIO.write( image, "png", out );
        } catch( IOException e ) {
          e.printStackTrace();
        }
       }
    }

How to deliver session-scoped resources

Often a RWT application UI includes session specific resources (e.g. images) - either because they are dynamically created or specific credentials are required to access them. This use case can be handled by a custom service handler and a Browser widget (or a custom widget). Please see the FAQ article #How to display dynamically created images? for the implementation details.

How to specify context path when using the RAP launcher?

For the embedded Jetty servlet container, used by the RAP launcher, the context path can be specified as a VM parameter in the launch configuration:

 -Dorg.eclipse.equinox.http.jetty.context.path=<context path>

In the launch configuration dialog, you should also change the Servlet name if the Open application in ... is checked.

Here is a complete example:

  • RAP launcher configuiration

 VM argument: -Dorg.eclipse.equinox.http.jetty.context.path=/mycontext 
 Servlet name: mycontext/rap
 Entry point: myentry

  • Application URL

 http://<host>:<port>/mycontext/rap?startup=myentry

How to access a RAP application without specifying a servlet name?

Let's suppose that we want to simplify the URL of our RAP application and be able to access it with http://www.example.org/webapp instead of http://www.example.org/webapp/servlet_name.

The recommended solution is to use a redirection servlet:

  • Write a servlet which redirects requests for the web application root to the servlet name defined in the org.eclipse.rap.branding extension:
  public class RedirectServlet extends HttpServlet {
 
  protected void doGet( HttpServletRequest request,
                        HttpServletResponse response )
    throws ServletException, IOException
  {
    redirect( request, response );
  }
 
  protected void doPost( HttpServletRequest request,
                         HttpServletResponse response )
    throws ServletException, IOException
  {
    redirect( request, response );
  }
 
  static void redirect( HttpServletRequest request, 
                        HttpServletResponse response )
    throws IOException
  {
    if( request.getPathInfo().equals( "/" ) ) {
      response.sendRedirect( response.encodeRedirectURL( "servlet_name" ) );
    } else {
      response.sendError( HttpServletResponse.SC_NOT_FOUND );
    }
  }
}
  • Register the redirect servlet with alias "/":
<extension
      point="org.eclipse.equinox.http.registry.servlets">
   <servlet
         alias="/"
         class="org.example.RedirectServlet">
   </servlet>
</extension>

Note: Make sure that the servlet redirects only requests for "/" and returns 404 for all others. Failing to do so might create redirect loops.

How can I use Jetty basic authentication in my application?

Assuming you are running your RAP application with Jetty, it is possible to setup the basic authentication mechanism that will cause the browser to ask the user for a username and password:

  • First create a class that extends JettyCustomizer. This will allow us to customize the Jetty context to setup the basic authentication mechanism. Here is a sample class:
public class BasicAuthCustomizer extends JettyCustomizer { 
 
  public Object customizeContext(Object o, Dictionary dictionary) {
    final Constraint constraint = new Constraint();
    constraint.setName(Constraint.__BASIC_AUTH);
    constraint.setRoles(new String[]{ "admin" });
    constraint.setAuthenticate(true);
 
    final ConstraintMapping cm = new ConstraintMapping();
    cm.setConstraint(constraint);
    cm.setPathSpec("/*");
 
    final HashUserRealm realm = new HashUserRealm("MyRealm");
    .. // fill username, password and roles if needed
 
    final SecurityHandler sh = new SecurityHandler();
    sh.setUserRealm(realm);
    sh.setConstraintMappings(new ConstraintMapping[]{cm});
 
    final Context c = (Context) o;
    c.setSecurityHandler(sh);
 
    return o;
  }
 
}
  • Specify the fully qualified name of this class in your start script. For example:
-Dorg.eclipse.equinox.http.jetty.customizer.class=com.mycompany.console.jetty.BasicAuthCustomizer
  • In order for this class to be loaded correctly by the Eclipse code that customizes Jetty, you will need to put this class into a fragment that attaches to the "org.eclipse.equinox.http.jetty" bundle.


Deployment

Problems using Import-Package header

Since RAP 1.1 the workbench introduced a concept of so-called "split packages". This is a way of OSGi to have virtual packages which are physically splitted across several bundles. See this post and the OSGi 4.1 specification (§3.13.3) for more informations about split packages.

A common problem with them is that a split-package is only resolved when there is at least one additional split part available during runtime. As the RAP infrastrcuture only contains the workbench bundle at the moment this constrain is not met. In RCP world you often have the org.eclipse.ui.ide bundle available which contributes to these split packages and let Equinox resolve the constrains.

In order to work around this problem you are able to import only a certain part of the package (the part of the workbench in our example). You just need to extend your Import-Package declaration with the split attribute as shown in the following MANIFEST.MF fragment:

Manifest-Version: 1.0
...
Import-Package: org.eclipse.ui; ui.workbench="split",
org.eclipse.ui.part; ui.workbench="split"

The ui.workbench="split" directive tells Equinox to use only the "ui.workbench" part of this split package.

Exported WAR file does not work

The application is working at development time, but when after exporting it, the web application does not work. Check the following:

  • Check your build.properties
    • are you exporting the plugin.xml?
    • are all libraries you are using listed on the plug-ins class path?
    • Tip: As PDE build sometimes swallows error messages try exporting your feature with "Deployable feature" export, this may turn up error messages
  • Enable the OSGi console by adding this init-param to the web.xml:
<init-param>
  <param-name>commandline</param-name>
  <param-value>-console</param-value> 
</init-param>
    • you may want to add a port after -console in unix environments, you can then telnet to the OSGi console
    • type ss in the console and see if all bundles are started. If not try starting them with "start <bundle-id>". The stack traces may hint to what is missing
  • Make sure that the WAR does not contain the javax.servlet bundle. In the plug-in maniferst the javax.servlet must be listed in the Import-Package section, not in Require-Bundle.
  • Make sure that the WAR does not contain the org.eclipse.update.configurator bundle.
  • The WAR contains compile errors. You will probably find a zip archive somewhere in your output folder. It contains log files with the compiler output.
  • Start with a working example: rapdemo.war and integrate your plug-ins.
  • Use the product export to validate your feature:
    • Create a product configuration with an arbitrary name (File > New > Other > Product Configuration)
    • Select "The product configuration is based on features" on the "Overview" page
    • Add your feature to the list of features on the "Dependencies" page
    • Press the Validate' button in the top-left corner of the editor. Ignore complaints about missing javax.servlet packages
  • Ifyou are re-deploying, make sure to delete the work directory of your servlet engine (e.g. <tomcat_install>/work/Catalina/localhost/work/<webapp_name> in Tomcat)

How do I make remote calls to EJB's deployed on Jboss 4.x AS

This is not a solution for calling local interface EJB's (I wasn't able to do it :( ), neither for EJB3 specification (didn't tried yet)

Nevertheless is more useful to make remote calls as the RAP application and the JBoss AS could be on separate machines (or will be sometime in the application life-cycle)

  • prepare a jar with EJB's interfaces which you are about to call from RAP (I think here you may use it wrapped as a bundle if you want to separate it from your application bundle)
  • put the jar in the application runtime classpath or add it as a dependency plugin if you use it as a bundle
  • add the following jar's from the jboss installation folder in the application runtime classpath : jboss.jar, jboss-remoting.jar, jboss-serialization.jar, jbosssx.jar, jboss-transaction.jar, jnpserver.jar

Here's an example code for calling the EJB's remote interface :

Hashtable<String, String> props = new Hashtable<String, String>();
props.put( Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" );
props.put( Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" );
props.put( Context.PROVIDER_URL, "jnp://localhost:1099" ); // here you put your JBoss AS server's address
Context ctx = null;
try {
  ctx = new InitialContext( props );
} catch( NamingException e ) {
  throw new RuntimeException( "fail to get initial context", e );
}
Object obj = null;
try {
  obj = ctx.lookup( "Test" ); //The jndi ejbs name is Test
} catch( NamingException e ) {
  throw new RuntimeException( "could not obtain test home interface", e );
}
TestHome home = ( TestHome )PortableRemoteObject.narrow( obj, TestHome.class );
try {
  testService = home.create();
} catch( CreateException e ) {
  throw new RuntimeException( "could not create test remote interface", e );			
} catch( RemoteException e ) {
  throw new RuntimeException( "remote exception when creating test remote interface", e );
}
try {
  testService.callSomeBusinessMethod(...);
} catch( RemoteException e ) {
  throw new RuntimeException( "remote exception when calling business method", e );
}

How do I use a RWT standalone application in Tomcat

To use the RWT standalone application in Tomcat follow the steps below:

  • Create a new Java project.
  • In the project create the folders:
    • "WEB-INF"
    • "WEB-INF/lib"
    • "WEB-INF/classes"
    • "WEB-INF/conf"
  • In "WEB-INF" create a file web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">
 
  <display-name>Welcome to RWT</display-name>
  <description>Welcome to RWT</description>
 
  <context-param>
    <param-name>org.eclipse.rwt.entryPoints</param-name>
    <param-value>org.eclipse.rap.helloworld.HelloWorld</param-value>
  </context-param>
 
  <listener>
    <listener-class>org.eclipse.rwt.internal.engine.RWTServletContextListener</listener-class>
  </listener>
 
  <servlet>
    <servlet-name>rapServlet</servlet-name>
    <servlet-class>org.eclipse.rwt.internal.engine.RWTDelegate</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>rapServlet</servlet-name>
    <url-pattern>/main</url-pattern>
  </servlet-mapping>
</web-app>
  • You can use several features (e.g. branding, theming) that are usually specified with extension points by using context parameters.
This is optional:
<context-param>
  <param-name>org.eclipse.rwt.themes</param-name>
  <param-value>useradmin#theme/theme.properties</param-value>
</context-param>
 
<context-param>
  <param-name>org.eclipse.rwt.brandings</param-name>
  <param-value>rap.RAPUseradminBranding</param-value>
</context-param>
  • In the WEB-INF\conf folder create a file w4t.xml:
<?xml version="1.0" encoding="UTF-8"?>
<w4t:application xmlns:w4t="http://w4toolkit.com/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://w4toolkit.com/ w4t.xsd ">
  <initialisation>
    <lifecycle>org.eclipse.rwt.internal.lifecycle.RWTLifeCycle</lifecycle>
  </initialisation>
</w4t:application>
  • Copy the folloing jars from RAP in the WEB-INF/lib folder:
    • org.eclipse.rap.rwt
    • org.eclipse.rap.q07
  • In case you want to make use of JFace, you also need to add these jars
    • org.eclipse.core.commands
    • org.eclipse.equinox.common
    • org.eclipse.rap.jface
  • Add these jars to the project build path as external jars.
  • Change the projects' output folder to WEB-INF/classes.
  • Use a normal implementation of IEntryPoint#createUI() - HelloWorld.java:
package org.eclipse.rap.helloworld;
 
import org.eclipse.rwt.lifecycle.IEntryPoint;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
 
public class HelloWorld implements IEntryPoint {
  public int createUI() {       
    Display display = new Display();
    Shell shell = new Shell( display );
    Label label = new Label( shell, SWT.NONE );
    label.setText( "Hello RAP World" );
    label.setSize( 80, 20 );
    shell.setSize( 500, 400 );        
    shell.open();
    while( !shell.isDisposed() ) {
      if( !display.readAndDispatch() )
        display.sleep();
    }
    return 0;
  }
}
  • ZIP the the WEB-INF folder (including the folder itself) as RWT_Standalone.war.
  • Deploy the RWT_Standalone.war<code> in Tomcat.
  • Start the standalone RWT application from:
http://<host>:<port>/RWT_Standalone/main
  • If you get an <code>IllegalArgumentException or a ClassNotFoundException after deploying your application, please check first the contents of your WAR file. Maybe it doesn't contain all class files.

How do I use a RWT standalone application without a server

In order to demonstrate the usage of RAP without the integration of the application in an existing server environment a RAP standalone application can be created as follows.

  1. Add the following plugins to the RAP target runtime or create a new target runtime including the two plugins and your "old" RAP target runtime
    1. org.eclipse.equinox.launcher
    2. org.eclipse.equinox.launcher.(win/linux/...) depending on your operating system.
  2. Rebuild your project with this new target runtime
  3. Create a new "product configuration" file (i.e. standalone.product) and open it with the procut configuration file editor.
  4. On the "Overview" page enter the following values
    1. Name: StandAlone
    2. Product: Select the plugin project containing the product definition with the "New..." Button.
    3. Application: org.eclipse.ui.workbench
  5. On the "Dependency" page enter the plugins and fragments required. Don't forget the jetty server and the rap plugins.
  6. On the "Configuration" page set the start level and the auto-start behaviour. This takes its time.
  7. On the "Launching" you can name the launcher (i.e. StandAlone)
  8. Save the file and go back to the Overview page.
  9. Use the "Eclipse Product export wizard" in order to create a RCP/RAP launcher in a dedicated directory.

Why are there encoding issues after deploying my RAP application as a WAR?

The pde.exportFeatures Ant task uses the encoding specified in file.encoding system property, which might not match the encoding of your source files. You can change this behaviour by explicitly defining the encoding used in pde.exportFeatures task. Just identify the plugin, which contains the strings with non-ASCII characters, and add javacDefaultEncoding property to his build.properties file.

The following example sets the encoding to utf-8, but you should specify whatever encoding your source files are using:

  javacDefaultEncoding.. = UTF-8

Reference: Feature and Plug-in Build Configuration Properties in the Plug-in Development Environment Guide.

I cannot access resource/image after deploying as a WAR

The image/resource is visible when running from within the IDE but is missing after deploying.

All resources must be explicitly listed in the bin.includes variable or they will not be included in the binary distribution of your plug-in. Please verify your build.properties files to ensure that your plug-ins are not missing any entries for images and other resource files.

How do I stress test or load test my RAP application

See the article Load testing / stress testing of RAP applications

How can I test my application with HTTPS?

When running a RAP application from the IDE, the Jetty servlet container is used. Jetty can simply be put into HTTPS mode:

  • First you need to create a certificate using the keytool from the Java SDK:
# keytool -keystore keystore -alias jetty -genkey -keyalg RSA
Enter keystore password:  password
Re-enter new password:  password
What is your first and last name?
  [Unknown]:  RAP Example
What is the name of your organizational unit?
  [Unknown]:  RAP Team
What is the name of your organization?
  [Unknown]:  Eclipse
What is the name of your City or Locality?
  [Unknown]:  
What is the name of your State or Province?
  [Unknown]:  
What is the two-letter country code for this unit?
  [Unknown]:  
Is CN=RAP Example, OU=RAP Team, O=Eclipse, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  yes

Enter key password for <jetty>
        (RETURN if same as keystore password):  

This creates a file named keystore in the current working directory.

  • Now add the following vm parameters to your launch config:
-Dorg.eclipse.equinox.http.jetty.https.enabled=true
-Dorg.eclipse.equinox.http.jetty.https.port=<YourHttpsPort>
-Dorg.eclipse.equinox.http.jetty.ssl.keystore=/path/to/the/created/keystore
-Dorg.eclipse.equinox.http.jetty.ssl.keypassword=password
-Dorg.eclipse.equinox.http.jetty.ssl.password=password

See also:

Branding and Theming

How can I use an image in the branding body?

Using a user-defined resource inside of a RAP application requires registering it in some way. In case of images used inside the branding body, this can be done declaratively using the org.eclipse.equinox.http.registry.resources extension.

Assume you have a folder branding in the root of your plugin, containing an image called loading.gif. Add the following code to your plugin.xml:

<extension point="org.eclipse.equinox.http.registry.resources">
    <resource
        alias="/loading.gif"
        base-name="branding/loading.gif">
    </resource>
</extension>

This maps the provided resource base name to the given alias name and makes it available for use.

Access the image in your branding body by referring to the alias name:

...
    <img src="./loading.gif" border="0" />
...

Why doesn't RAP simply use CSS for styling, such as e.g. GWT?

In GWT for example, every widget has a configurable style name that is rendered as class attribute. Styling is done by adding a CSS file to the target HTML document. Although this is a simple technique, it does not work out for RAP for a number of reasons:

1. One of the main objectives of RAP is to prevent vendor lock-in by allowing for exchangeable client implementations. Although our current client-side technique is based on JavaScript, there are completely different technologies out there that might be interesting candidates for RAP clients (GWT, Flex, Silverlight ...). Not all of those technologies can necessarily deal with CSS.

2. In RAP, all layouts are computed on the server side, thus the server also needs to know about any variable dimensions like paddings and borders. This is not possible if a style sheet is applied only on the client side.

3. Due to browser bugs and differences, writing cross-browser CSS code is a complex task. Client technologies may work around those browser issues. In fact, the qooxdoo library does so.

How can I change the favicon / title of my RAP app?

With the help of RAPs branding features you're able to define several (visual) aspects of your RAP application. This includes for example the page title which is shown in the browser, the favicon or the theme to be used for the application. See the Branding section of the RAP Developer guide for details.


Single Sourcing

Why does Display#getDefault() work different than in SWT

One notable difference between SWT and RWT is the way the UI thread is determined. In SWT, calling new Display() marks the thread that executes the code as the UI thread. This means that the programmer is free to choose which thread should become the UI thread.

RWT, on the contrary, already provides the one and only UI thread before createUI is called (the equivalent to the main method). As a consequence, getDefault() can only creae a Display instance if it is called from the user-interface thread.

Back to the top