Sunday, August 31, 2008

Tutorial: Sample RCP application using Spring, Spring Dynamic Modules for OSGi Service Platforms and AgileRCP (1/3)

In this article you will learn how to create an RCP application that makes use of Spring, Spring-DM and AgileRCP. You will create a simple user manager that returns a list of names and an action that uses this user manager. The tutorial will show you how to use the ApplicationContextTracker of AgileRCP.
  1. Install Eclipse IDE, Spring IDE and AgileRCP as described in this post.

  2. Create a new plug-in project for the RCP application:
    • Switch to the Plug-in Development perspective.
    • New -> Other... -> Plug-in Development / Plug-in Project
    • Choose a proper project name, e.g. "org.digitalcure.hellospring.app"
    • Generate an activator: yes, This plug-in will make contributions to the UI: yes, Would you like to create a rich client application? yes
    • Create a plug-in using one of the templates: yes, select: RCP application with a view

  3. Create a second plug-in project for the service interface definition:
    • New -> Other... -> Plug-in Development / Plug-in Project
    • Choose a proper project name, e.g. "org.digitalcure.hellospring.common"
    • Generate an activator: yes, This plug-in will make contributions to the UI: no, Would you like to create a rich client application? no
    • Create a plug-in using one of the templates: no

  4. Create a new interface inside the package "org.digitalcure.hellospring.common":
    • New -> Interface
    • Choose an interface name: IUserManager
    • Add a single method:
    /**
    * Returns the names of all users.
    * @return list of user names, never null
    */
    List<String> getUserNames();

  5. Edit the MANIFEST.MF file and add the package "org.digitalcure.hellospring.common" to the list of exported packages (Runtime tab).

  6. Switch back to the first project (the "app" project). Edit the MANIFEST.MF file and import the package "org.digitalcure.hellospring.common" (Dependencies tab).

  7. Create a default implementation of a user manager. Create a new class inside the "org.digitalcure.hellospring.app" package:
    • New -> Class
    • Choose a class name: DefaultUserManager
    • Interfaces: org.digitalcure.hellospring.common.IUserManager

  8. Implement the getUserNames() method, so that it returns two names, e.g.:
    public List<String> getUserNames() {
    final List<String> list = new ArrayList<String>(2);
    list.add("Adam");
    list.add("Berti");
    return list;
    }

  9. Create an action that lists all user names of a user manager. Create a new class inside the "org.digitalcure.hellospring.app" package:
    • Choose a class name: ListUserAction
    • Superclass: org.eclipse.jface.action.Action

  10. Add a default constructor to the class that calls the super-constructor with a single string argument:
    public ListUserAction() {
    super("List Users");
    }

  11. Add a member that holds a user manager plus a setter method:
    private IUserManager userManager;

    public void setUserManager(final IUserManager usrManager) {
    userManager = usrManager;
    }

  12. Implement the run() method, so that all users are printed in the console:
    @Override
    public void run() {
    if (userManager == null) {
    System.out.println("User manager unset!");
    } else {
    System.out.println("All user names:");
    final List<String> names = userManager.getUserNames();
    for (final String name : names) {
    System.out.println("name = " + name);
    }
    }
    }

  13. The action has to provide a valid ID:
    private static final String ID = "org.digitalcure.hellospring.app.listalluser";

    @Override
    public String getId() {
    return ID;
    }

  14. Now you are ready to create the Spring configuration files. Create a folder named "spring" inside the META-INF folder.

  15. Create two XML files inside the "spring" folder:
    • bundle-context.xml
    • bundle-context-osgi.xml

  16. bundle-context.xml: Create a Spring bean for the user manager:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:osgi="http://www.springframework.org/schema/osgi"
    xsi:schemaLocation="http://www.springframework.org/schema/osgi
    http://www.springframework.org/schema/osgi/spring-osgi.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="defaultUserManager" class="org.digitalcure.hellospring.app.DefaultUserManager" />
    </beans>

  17. bundle-context-osgi.xml: No service definitions:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans
    xmlns="http://www.springframework.org/schema/osgi"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/osgi
    http://www.springframework.org/schema/osgi/spring-osgi.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans:beans>

  18. Now you are ready to define the action for listing all users as a Spring bean. This bean uses the default user manager:
    <bean id="listUserAction" class="org.digitalcure.hellospring.app.ListUserAction" >
    <property name="userManager" ref="defaultUserManager" />
    </bean>

  19. Add Spring support to the "app" project: Open the context menu for the project and select "Spring Tools" -> "Add Spring Project Nature". The project itself will be marked with a "S" in the upper right corner of the project icon.

  20. Open the Properties dialog of the project. Go to "Spring" -> "Beans Support" and add the two XML files of the "spring" folder. After closing the dialog, both XML files will be marked with an "S", plus the Java files "DefaultUserManager.java" and "ListUserAction.java".

  21. Now you have to create an instance of the action and add it to the File menu:
    • Edit the class ApplicationActionBarAdvisor
    • Add a member for the action that lists all users and add it to the menu inside the method fillMenuBar(...).
      private IAction listUserAction;

      @Override
      protected void fillMenuBar(final IMenuManager menuBar) {
      final MenuManager fileMenu = new MenuManager(
      "&File", IWorkbenchActionConstants.M_FILE);
      menuBar.add(fileMenu);

      if (listUserAction != null) {
      fileMenu.add(listUserAction);
      }
      fileMenu.add(exitAction);
      }

    • Inside the makeActions(...), get the ApplicationContext from an ApplicationContextTracker. Then an instance of the Spring bean for the action that lists the user is created.
      @Override
      protected void makeActions(final IWorkbenchWindow window) {
      try {
      final Bundle bundle = Activator.getDefault().getBundle();
      final ApplicationContextTracker applicationContextTracker =
      new ApplicationContextTracker(bundle, bundle.getBundleContext());

      ApplicationContext applicationContext = null;
      try {
      applicationContext =
      applicationContextTracker.getApplicationContext();
      } catch (final Throwable t2) {
      t2.printStackTrace();
      } finally {
      applicationContextTracker.close();
      }

      if (applicationContext == null) {
      System.out.println("NO APPLICATION CONTEXT!");
      } else {
      listUserAction = (IAction) applicationContext.getBean("listUserAction");
      register(listUserAction);
      }
      } catch (final Throwable t) {
      t.printStackTrace();
      }

      exitAction = ActionFactory.QUIT.create(window);
      register(exitAction);
      }

  22. The source code is not compile clean, because some packages are missing. Add the following packages to the list of imported packages (MANIFEST.MF, Dependencies tab):
    • "org.eclipse.springframework.util"
    • "org.springframework.beans.factory
    • "org.springframework.context"

  23. Now a product configuration has to be created:
    • New -> Product Configuration
    • Enter or select the parent folder: org.digitalcure.hellospring.app
    • File name: HelloSpringApp.product
    • Create a configuration file with basic settings: yes
    • Press "Finish". The wizard will be closed and the product editor will be opened.
    • Name: Hello Spring Application
    • ID: New...
    • A dialog for the product definition will be displayed. Just press "Finish".
    • Version: 1.0.0
    • Application: org.digitalcure.hellospring.app.application
    • The product configuration is based on: plug-ins
    • Switch to the Configuration tab.
    • Include optional dependencies when computing required plug-ins: no
    • Add the two plug-ins of the workspace: "org.digitalcure.hellospring.app" and "org.digitalcure.hellospring.common".
    • Press "Add Required Plug-ins".
    • Save the editor.

  24. Edit the plugins.xml file:
    • Go to the Extensions tab and select "org.eclipse.core.runtime.products".
    • ID: HelloSpringApp.product

  25. Now you are ready to run the application:
    • Open the Run Configurations dialog using the menu item "Run" -> "Run Configurations...".
    • Create a new launch configuration under OSGi Framework.
    • Name: HelloSpringApp
    • Framework: Equinox, Default Start Level: 4, Default Auto-Start: true
    • Select the two plug-ins inside the workspace.
    • Remove the selection from all plug-ins of the target platform.
    • Include optional dependencies when computing required bundles: no
    • Add new workspace bundles to this launch configuration automatically: no
    • Validate bundles automatically prior to launch: yes
    • Press the button "Add Required Bundles".
    • Press "Apply" and change to the Arguments tab.
    • Add the following program arguments right after the existing arguments: -consoleLog -product HelloSpringApp.product
    • Remove any existing VM arguments.
    • Change to the Settings tab and select "Clear the configuration area before launching".
    • Press "Run".

  26. The application will run. Take care of the logger messages in the Console view. When the application frame appears, select the menu item "File" -> "List Users". You should see the two user names in the Console view.

You may download the source code of the tutorial from here.

5 comments:

stefan222 said...

Published part 2 and part 3 of the tutorial. Enjoy!

stefan222 said...

Added a new tutorial article about the export of this sample application here. Enjoy it!

Erik Vande Velde said...

I'm trying to follow the instructions in this article, but in step 21 my eclipse doesn't find the ApplicationContextTracker class. I gather that this class is 'hidden' somewhere in the AgileRCP libraries, but where exactly can I find them?

stefan222 said...

Hi Erik,

the tutorial was written in 2008 using Eclipse 3.4, Spring 2.1 and Spring-DM 1.1. If you're using newer versions the APIs may have changed - no wonder in more than 4 years...). I think the ApplicationContextTracker was part of Spring or Spring-DM.

Erik Vande Velde said...

Hello Stefan. Thanks for your answer! I was really looking for a RCP 4 sample program with spring remoting (RMI or HTTP). But all I could find on the internet is your blog from long time ago. If you know a more recent blog, or a book, describing what I really want, that would be great !