Jump to: navigation, search

Using Spring with XWT

Contents

Introduction

Spring is a popular and widely deployed open source framework that helps developers build high quality enterprise applications faster. Spring provides a consistent programming and configuration model that is well understood and used by millions of developers worldwide.

The Spring Dynamic Modules for OSGi(tm) Service Platforms project makes it easy to build Spring applications that run in an OSGi framework. A Spring application written in this way provides better separation of modules, the ability to dynamically add, remove, and update modules in a running system, the ability to deploy multiple versions of a module simultaneously (and have clients automatically bind to the appropriate one), and a dynamic service model. OSGi is a registered trademark of the OSGi Alliance. In late 2009, it has been contributed to the Eclipse Foundation as the Gemini Blueprint project.

This integration opens the door for XWT to work in the OSGi context and client/server architecture.

Work is underway to integrate XWT with Spring and Spring Dynamic Module to declare with Spring bean, the CLR class used into XWT file with XML Spring file.

This support comes from the Bug 320405. You will find from XWT-Spring-CVS several projects :

  • org.eclipse.e4.xwt.springframework: bundle of Spring support for XWT.
  • org.eclipse.e4.xwt.springframework.tests : Tests (Main/JUnit) of Spring support for XWT.

And from XWT-Spring-Examples-CVS examples with NO OSGi context :

and examples with OSGi context :

Spring JAR :

CLR Class

Before explaining Spring support for XWT, it's interesting to understand how CLR Java class are managed with x:Class and x:ClassFactory.

CLR with x:Class

The Event Handling sample show you how XWT file can be linked to a Java CLR (Common Language Runtime) class to manage for instance event handler of the UI with Java code by using x:Class attribute :

<Shell xmlns="http://www.eclipse.org/xwt/presentation"
    xmlns:x="http://www.eclipse.org/xwt"
    x:Class="ui.EventHandler">
    <Shell.layout>
       <GridLayout/>
    </Shell.layout>
    <Button text="Click Me!" SelectionEvent="clickButton">
    </Button>
</Shell>

The declaration x:Class="ui.EventHandler" means that the UI is linked to the Java class ui.EventHandler :

package ui;
 
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Button;
 
public class EventHandler {
 
    protected void clickButton(Event event) {
        Button button = (Button )event.widget;
        button.setText("Hello, world!");
    }
}

When the button gets selected, the method clickButton is invoked to change the Button text to "Hello, world!":

Xwt-event-handler.png

CLR with x:ClassFactory

You can do the same thing (link a CLR class with XWT) with CLR factory :

<Shell xmlns="http://www.eclipse.org/xwt/presentation"
    xmlns:x="http://www.eclipse.org/xwt"
    x:ClassFactory="ui.EventHandlerFactory">
    <Shell.layout>
       <GridLayout/>
    </Shell.layout>
    <Button text="Click Me!" SelectionEvent="clickButton">
    </Button>
</Shell>

The x:ClassFactory="ui.EventHandlerFactory" declaration means that the UI is linked to the Java class which is created by the CLR factory ui.EventHandlerFactory :

package ui;
 
import org.eclipse.e4.xwt.ICLRFactory;
 
public class EventHandlerFactory implements ICLRFactory {
    public Object createCLR(String args) {
        return new ui.EventHandler();
    }
}

This CLR factory implements org.eclipse.e4.xwt.ICLRFactory which returns an instance of ui.EventHandler which is the CLR class described below.

Overview - Spring support for XWT

The bundle org.eclipse.e4.xwt.springframework is the Spring support for XWT which implements org.eclipse.e4.xwt.ICLRFactory to declare CLR Class with bean Spring. It's possible to use this Spring support :

Spring support for XWT is very easy to use if you know Spring and Spring DM (for OSGi). Next sections will explain more how configure/use Spring/Spring DM than Spring support for XWT. This support will be explained by using provided samples.

Application Java context

x:ClassFactory

Into application Java context, x:ClassFactory follow this syntax :

x:ClassFactory="<MySpringCLRFactory> bean=<myBean>"

where :

  • <MySpringCLRFactory> is the Spring CLR factory which load and use Spring XML file ApplicationContext to create an instance of the CLR bean.
  • <myBean> : is the bean ID of the CLR bean declared into the Spring XML file ApplicationContext.

Please see Using Spring with XWT section for more information.

Lifecycle

Here a sheme which explain how Spring CLR Factory works into Java application context :

SpringCLRFactory lifecycle javaappctxt.png

ui.MySpringCLRFactory is a custom class which implements org.eclipse.e4.xwt.springframework.AbstractSpringCLRFactory to load the Spring ApplicationContext which declare CLR as bean.

OSGi context

x:ClassFactory

Into OSGi context, x:ClassFactory follow this syntax :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=<myBean> bundle=<myBundle>"

where :

  • <myBean> is the bean ID of the CLR bean declared into the Spring ApplicationContext.
  • <myBundle> is the symbolic name of the bundle which contains the Spring XML file ApplicationContext which declare the CLR bean.

But if you configure SpringCLRFactory, you can simply use this syntax :

x:ClassFactory="+ bean=<myBean>"

Please see Using Spring Dynamic Module (OSGi) with XWT section for more information.

Lifecycle

Here a sheme which explain how Spring CLR Factory works into OSGi application context with Spring DM :

SpringCLRFactory lifecycle osgictxt.png

Into OSGi context, you need not implement your Spring CLR Factory because Spring ApplicationContext are loaded with Spring DM Extender and registered it into OSGi registry services. org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE retrieve the Spring ApplicationContext by using the parameter bundle.

How test Spring support for XWT?

Before explaining Spring support for XWT, please follow the explained steps to try the samples of this Spring support. Samples are using Spring 3.0.3 and Spring DM 1.2 but it was tested too with Spring old version (2.5).

Download Eclipse E4

XWT belongs to Eclipse E4 project. To use XWT, download it.

Get XWT bundles from CVS

  • Today (08/19/2010) Eclipse E4 doesn't contains the ICLRFactory from XWT. Get org.eclipse.e4.xwt from the CVS :
    • Host: dev.eclipse.org
    • Repository Path: /cvsroot/eclipse
    • Module: e4/org.eclipse.e4.xwt/bundles/org.eclipse.e4.xwt
  • Get Spring support for XWT org.eclipse.e4.xwt.springframework from the CVS :
    • Host: dev.eclipse.org
    • Repository Path: /cvsroot/eclipse
    • Module: e4/org.eclipse.e4.xwt/bundles/org.eclipse.e4.xwt.springframework

SpringCLRFactory CVS bundles.png

Get XWT samples (bundles) from CVS

You can find the whole projects (named org.eclipse.e4.xwt.springframework.*) of Spring support for XWT on CVS :

  • Host: dev.eclipse.org
  • Repository Path: /cvsroot/eclipse
  • Module: e4/org.eclipse.e4.xwt/examples

On other words :

  • Get from CVS the whole project named org.eclipse.e4.xwt.springframework.*.
  • Get from CVS the spring-target-platform project which contains Spring Target Platform and some launches.

SpringCLRFactory CVS examples.png

Once you will get the Spring support bundles+examples project, your workspace look like this :

SpringCLRFactory workspace step1.png

Your workspace contains a lot of Compilation error because Spring (and Spring DM) is not included to the Default Target Platform.

Set Spring Target Platform

Copy/Paste Spring JAR into spring-target-platform

The spring-target-platform doesn't contains Spring JAR lib required. You must copy/paste Spring 3.0.3 and Spring DM 1.2 JAR into this project. To do that :

  • unzip spring-lib1.zip and spring-lib2.zip and copy paste the whole JAR into spring-target-platform.
  • OR use the a maven spring-target-platform/pom.xml.

Set As Target Platform

To resolve compilation problems, open the file spring-target-platform/Spring Target Platform.target with Target editor and click on "Set As Target Platform" :

SpringCLRFactory workspace step2.png

Your workspace should be recompiled and errors should disappear.

For your information spring-target-platform contains :

  • the Spring 3.0.3 and Spring DM 1.2.1 bundles required.
  • a maven pom.xml which was used to download thoses bundles.
  • spring-target-platform\launch-mvn\Install Spring Target Platform.launch is a m2eclipse launch that you can use to get the Spring JARs. Once you have launched it, refresh the project and spring-target-platform\target\targetPlatform\plugins folder must appears with the JARs downloaded.
  • several OSGi launch for each samples.

OSGi Launch samples

For each explained samples you have a launch (sample1.launch, sample2.launch....) into spring-target-platform project. Before trying to launch it, please edit it with Run-Run Configurations and :

  • click on "Validate Bundles" button to check if there are no errors (whole required bundles are present?)
  • if you have errors, click on "Add Required Bundles" button and "Validate Bundles" button.

SpringCLRFactory validate launch.png

Using Spring with XWT

org.eclipse.e4.xwt.springframework.sample1

org.eclipse.e4.xwt.springframework.sample1 is a basic sample which show you how declare CLR class with bean Spring (no OSGi context) :

SpringCLRFactory workspace sample1.png

Here steps that it was done to create this project:

Add JAR/Dependencies

XWT Dependencies :

  • org.eclipse.swt;bundle-version="3.6.0",
  • org.eclipse.e4.xwt;bundle-version="0.9.1",
  • org.eclipse.e4.xwt.springframework;bundle-version="0.9.1",
  • com.ibm.icu;bundle-version="4.2.1"


Spring JAR :

  • com.springsource.org.apache.commons.logging-1.1.1.jar
  • com.springsource.org.apache.log4j-1.2.16.jar
  • org.springframework.asm-3.0.3.RELEASE.jar
  • org.springframework.beans-3.0.3.RELEASE.jar
  • org.springframework.context-3.0.3.RELEASE.jar
  • org.springframework.core-3.0.3.RELEASE.jar
  • org.springframework.expression-3.0.3.RELEASE.jar

Here Commons Logging (not SLF4J) was used to configure logs for Spring. But Spring recommend to use SLF4J. Please read Spring Logging section.

Configure Log4j

Create log4j.properties into src folder :

log4j.rootLogger=info, con
log4j.appender.con=org.apache.log4j.ConsoleAppender
log4j.appender.con.layout=org.apache.log4j.PatternLayout
log4j.appender.con.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

Declare Spring bean CLR

Declare CLR class with bean into XML file Spring. To do that create a XML Spring file ui-context.xml into ui package like this :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
  <bean name="myUI" class="ui.EventHandler" scope="prototype">
  </bean>
 
</beans>

You will notice that:

Implements Spring CLRFactory

Spring CLR factory is implemented with ui.MySpringCLRFactory class which extends org.eclipse.e4.xwt.springframework.AbstractSpringCLRFactory. This abstract class require to implement the abstract method :

protected abstract ApplicationContext createApplicationContext(IArguments arguments)

which must returns an instance of Spring ApplicationContext which contains CLR bean declared :

package ui;
 
import org.eclipse.e4.xwt.ICLRFactory;
import org.eclipse.e4.xwt.springframework.AbstractSpringCLRFactory;
import org.eclipse.e4.xwt.springframework.CLRFactoryParameters;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class MySpringCLRFactory extends AbstractSpringCLRFactory {
 
  public static final ICLRFactory INSTANCE = new MySpringCLRFactory();
 
  @Override
  protected ApplicationContext createApplicationContext(IArguments arguments) {
    return new ClassPathXmlApplicationContext("ui/ui-context.xml");
  }
}

To avoid loading XML Spring file ui-context.xml each time that XWT need to create CLR, MySpringCLRFactory define a singleton (INSTANCE) which it must use into x:ClassFactory.

Set the x:ClassFactory

XWT file UI.xwt stored into ui package declare the Spring CLR factory like this :

<Shell xmlns="http://www.eclipse.org/xwt/presentation"
    xmlns:x="http://www.eclipse.org/xwt"
    x:ClassFactory="ui.MySpringCLRFactory.INSTANCE bean=myUI">
    <Shell.layout>
       <GridLayout/>
    </Shell.layout>
    <Button text="Click Me!" SelectionEvent="clickButton">
    </Button>
</Shell>

You can notice that x:ClassFactory is used to define the Spring Factory :

x:ClassFactory="ui.MySpringCLRFactory.INSTANCE bean=myUI"
  • ui.MySpringCLRFactory.INSTANCE define the CLR Spring factory singleton to use.
  • bean=myUI define the bean of the CLR.

Test and run it

Create UI Java Class test which open the ui.xwt file :

package ui;
 
import java.net.URL;
 
import org.eclipse.e4.xwt.IConstants;
import org.eclipse.e4.xwt.XWT;
 
public class UI {
 
  public static void main(String[] args) {
 
  URL url = UI.class.getResource(UI.class.getSimpleName() + IConstants.XWT_EXTENSION_SUFFIX);
    try {
      XWT.open(url);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Run Java Application on this Main class org.eclipse.e4.xwt.springframework.sample1/ui/UI. UI opens and if you click on button, it call the EventHandler#clickButton(Event event) from the EventHandler instance created by Spring:

Xwt-event-handler.png

Using Spring with XWT - Spring DI

At this step, we have seen how declare CLR Class as bean Spring. It's not very interesting compare to use CLR class with x:Class. But Spring is very powerful and it give you for instance Dependency Injection capability. In this section we will use Spring Dependency Injection to use a service into the CLR.

org.eclipse.e4.xwt.springframework.sample2

This section will explain the Java project org.eclipse.e4.xwt.springframework.sample2 :

SpringCLRFactory workspace sample2.png

At this step we change the label button when user click on it :

public class EventHandler {
 
  protected void clickButton(Event event) {
    Button button = (Button) event.widget;
    button.setText("Hello, world!");
  }
}

In real application CLR class use generally service. Here we will call an HelloService to get the message "Hello, world!".

Define HelloService

Create an interface ui.IHelloService like this :

package services;
 
public interface IHelloService {
 
  String hello();	
}

Create the IHelloService implementation like this :

package services.impl;
 
import services.IHelloService;
 
public class HelloService implements IHelloService {
 
  public String hello() {
    return "Hello, world!";
  }
}

Use HelloService into CLR

EventHandler is modified to consume the IHelloService :

package ui;
 
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
 
import services.IHelloService;
 
public class EventHandler {
 
  private IHelloService helloService;
 
  public void setHelloService(IHelloService helloService) {
    this.helloService = helloService;
  }
 
  protected void clickButton(Event event) {
    Button button = (Button) event.widget;
    button.setText(helloService.hello());
  }
}

The service will be filled with Spring Depency Injection.

Declare and use bean service

The ui-context.xml file declare the helloService :

  <bean name="myService" class="services.impl.HelloService" >
  </bean>

Here the declaration don't use scope="prototype", because the service is a singleton.

The service is filled to the CLR bean with Spring Dependency Injection :

  <bean name="myUI" class="ui.EventHandler" scope="prototype">
    <property name="helloService" ref="myService" />
  </bean>

Here the ui-context.xml modified :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
  <bean name="myUI" class="ui.EventHandler" scope="prototype">
    <property name="helloService" ref="myService" />
  </bean>
 
  <bean name="myService" class="services.impl.HelloService" >
  </bean>
 
</beans>

You can launch the Java UI test org.eclipse.e4.xwt.springframework.sample2/ui/UI to check that IHelloService is consumed by clicking on the button.

Using Spring with XWT - Spring DI - @Inject

It's interesting to use Spring 3.x because it provides the using of the @Inject(JSR-330) annotation to inject your service. (you can do the same thing with @Autowired).

org.eclipse.e4.xwt.springframework.sample3

In this section the org.eclipse.e4.xwt.springframework.sample3 is explained. It's a sample which inject the IHelloService with @Inject :

Use @Inject

package ui;
 
import javax.inject.Inject;
 
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
 
import services.IHelloService;
 
public class EventHandler {
 
	@Inject
	private IHelloService helloService;
 
	protected void clickButton(Event event) {
		Button button = (Button) event.widget;
		// Use the hello service
		button.setText(helloService.hello());
	}
}

You can notice that EventHandler#setHelloService(IHelloService helloService) doesn't exists. XML Spring file is modified like this:

Declare <context:annotation-config/>

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
  <bean name="myUI" class="ui.EventHandler" scope="prototype">  	
  </bean>
 
  <bean name="myService" class="services.impl.HelloService" >
  </bean>
 
  <context:annotation-config/>
 
</beans>

You can notice that :

  • <property name="helloService" ref="myService" /> doens't exist more.
  • <context:annotation-config/> is declared to use @Inject (or @Autowired).

You can launch the Java UI test org.eclipse.e4.xwt.springframework.sample3/ui/UI to check that IHelloService is consumed by clicking on the button.

Using Spring with XWT - Default factory

It's possible to omit the Spring CLR factory declaration into XWT file.

org.eclipse.e4.xwt.springframework.sample4

In this section the org.eclipse.e4.xwt.springframework.sample4 is explained.

x:ClassFactory="+ bean=myUI"

x:ClassFactory="ui.MySpringCLRFactory.INSTANCE bean=myUI">

But you can omit the factory declaration by using '+' character like this :

x:ClassFactory="+ bean=myUI">

XWT.setCLRFactory(MySpringCLRFactory.INSTANCE)

You must after set the factory which must be used by default by calling :

XWT.setCLRFactory(MySpringCLRFactory.INSTANCE);

Here the UI Java file modified :

package ui;
 
import java.net.URL;
 
import org.eclipse.e4.xwt.IConstants;
import org.eclipse.e4.xwt.XWT;
 
public class UI {
 
  public static void main(String[] args) {
 
    XWT.setCLRFactory(MySpringCLRFactory.INSTANCE);
 
    URL url = UI.class.getResource(UI.class.getSimpleName() + IConstants.XWT_EXTENSION_SUFFIX);
    try {
      XWT.open(url);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

You can launch the Java UI test org.eclipse.e4.xwt.springframework.sample4/ui/UI to check that IHelloService is consumed by clicking on the button.

Using Spring with XWT - bean as XWT file name

It's possible to omit the Spring bean declaration in the x:ClassFactory and use the XWT file name as bean.

org.eclipse.e4.xwt.springframework.sample5

In this section the org.eclipse.e4.xwt.springframework.sample5 is explained.

UI.xwt

The UI.xwt from the org.eclipse.e4.xwt.springframework.sample5 project doesn't contains teh bean declaration :

x:ClassFactory="+"

You can notice there are '+' because it means that it use default Spring CLR factory MySpringCLRFactory.

Spring ui-context.xml

The Spring CLR bean declaration use the "UI" namewich is the UI.xwt file name :

<bean name="UI" class="ui.EventHandler" scope="prototype">  	
</bean>

MySpringCLRFactory

To use teh XWT file name as the bean name, Spring CLRFactory must be configured to manage that. If you see MySpringCLRFactory from the org.eclipse.e4.xwt.springframework.sample5 project you will see that the constructor do that :

protected MySpringCLRFactory() {
  super.setBeanNameProvider(DefaultBeanNameProvider.INSTANCE);
}

It fill an instance of IBeanNameProvider which use URL from XWT file to retrieve the bean name  :

package org.eclipse.e4.xwt.springframework;
 
import java.net.URL;
 
/**
 * Provider to retrieve Spring bean name from the XWT file {@link URL}.
 * 
 */
public interface IBeanNameProvider {
 
	/**
	 * Returns the Spring bean name from the XWT file {@link URL}.
	 * 
	 * @param url
	 *            XWT file {@link URL}.
	 * @return Spring bean name.
	 */
	String getBeanName(URL url);
 
}

You can launch the Java UI test org.eclipse.e4.xwt.springframework.sample5/ui/UI to check that IHelloService is consumed by clicking on the button.

Using Spring Dynamic Module (OSGi) with XWT

org.eclipse.e4.xwt.springframework.osgi.sample1

org.eclipse.e4.xwt.springframework.osgi.sample1 is an OSGi bundle which show you how declare CLR class with bean Spring and Spring DM :

SpringCLRFactory workspace osgi sample1.png

You can notice that there are no dependencies with Spring in the OSGi context.

Activator#start

This bundle have a Bundle Activator which open a XWT file on start bundle :

public void start(BundleContext bundleContext) throws Exception {
 
  // Open XWT file (into a Thread to avoid blocking OSGi bundles start process)
  new Thread() {
    public void run() {
      URL url = EventHandler.class.getResource("UI" + IConstants.XWT_EXTENSION_SUFFIX);
      try {
        XWT.open(url);
      } catch (Exception e) {
        e.printStackTrace();
      }
    };
  }.start();
}

UI.xwt

The XWT file UI.xwt is the same than no OSGi context, except bundle parameter used to retrieve Spring ApplicationContext from the OSGi services registry, which was registered by Spring Extender bundle.

  x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=myUI bundle=org.eclipse.e4.xwt.springframework.osgi.sample1"

Here the complete file :

<Shell xmlns="http://www.eclipse.org/xwt/presentation"
    xmlns:x="http://www.eclipse.org/xwt"
    x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=myUI bundle=org.eclipse.e4.xwt.springframework.osgi.sample1">
    <Shell.layout>
       <GridLayout/>
    </Shell.layout>
    <Button text="Click Me!" SelectionEvent="clickButton">
    </Button>
</Shell>

spring/ui-context.xml

With Spring DM, XML spring file must be stored into MANIFEST-MF/spring folder (default configuration of Spring Extender). The ui-context.xml is the same than no OSGi context :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
  <bean name="myUI" class="ui.EventHandler" scope="prototype">
  </bean>
 
</beans>

Launch sample1

To test this bundle, you can find spring-target-platform/sample1.launch.

Launch sample1_no_auto_start

You can find spring-target-platform/sample1_no_auto_start.launch This launch set Auto start to false. You must set start to true for the bundles :

  • org.eclipse.e4.xwt.springframework
  • org.eclipse.e4.xwt.springframework.osgi.sample1
  • org.springframework.osgi.extender

Using Spring Dynamic Module (OSGi) with XWT - Spring DI

org.eclipse.e4.xwt.springframework.osgi.sample2 is an OSGi bundle which consume the IHelloService into the CLR. The service is getted from teh OSGi services registry.

API services - org.eclipse.e4.xwt.springframework.osgi.services

This bundle define the HelloService API with the services.IHelloService.

Implementation services - org.eclipse.e4.xwt.springframework.osgi.services.impl

This bundle is the services implementation which register as OSGI services the HelloService implementation. To do that,Spring DM is used.

services-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
  <bean name="myService" class="services.impl.HelloService" >
  </bean>
 
</beans>

services-osgi-context.xml

<?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-1.0.xsd
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
  <osgi:service ref="myService" interface="services.IHelloService" />
</beans>

Bundle org.eclipse.e4.xwt.springframework.osgi.sample2

SpringCLRFactory workspace osgi sample2.png

spring/ui-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
	<bean name="myUI" class="ui.EventHandler" scope="prototype">
		<property name="helloService" ref="myService" />
  	</bean>
 
</beans>

spring/ui-osgi-context.xml

The ui-osgi-context.xml retrieve the IHelloService from the OSGi services registry :

<?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-1.0.xsd
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
	<osgi:reference id="myService" interface="services.IHelloService"
		timeout="1000"
                cardinality="0..1" />
</beans>

cardinality="0..1" is very important. Indeed by default it's cardinality="1..1" which means that service is required. If you use cardinality="1..1", the UI will display only if service is available otherwise you will have an error and the UI will never displayed.

Launch sample2

To test this bundle, you can find spring-target-platform/sample2.launch

Launch sample2_no_auto_start

You can find spring-target-platform/sample2_no_auto_start.launch This launch set Auto start to false. You must set start to true for the bundles :

  • org.eclipse.e4.xwt.springframework
  • org.eclipse.e4.xwt.springframework.osgi.sample2
  • org.springframework.osgi.extender

and

  • org.eclipse.e4.xwt.springframework.osgi.services.impl

Using Spring Dynamic Module (OSGi) with XWT - Spring DI - @Inject

org.eclipse.e4.xwt.springframework.osgi.sample3

org.eclipse.e4.xwt.springframework.osgi.sample3 is an OSGi bundle which use @Inject into the CLR bean.

To use @Inject, you must Import package javax.inject and do like sample3 from Java Application context.

Launch sample3

To test this bundle, you can find spring-target-platform/sample3.launch

Launch sample3_no_auto_start

You can find spring-target-platform/sample3_no_auto_start.launch This launch set Auto start to false. You must set start to true for the bundles :

  • org.eclipse.e4.xwt.springframework
  • org.eclipse.e4.xwt.springframework.osgi.sample3
  • org.springframework.osgi.extender

and

  • org.eclipse.e4.xwt.springframework.osgi.services.impl

Using OSGi Fragment to configure SpringCLRFactory

org.eclipse.e4.xwt.springframework.osgi.sample4

It's possible to omit bundle parameter like this :

    x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=myUI">

org.eclipse.e4.xwt.springframework.osgi.sample4.config.springclrfactory

To do that you must configure SpringCLRFactory by creating an OSGi fragment linked to the bundle rg.eclipse.e4.xwt.springframework and create springclrfactory .properties into src folder like this :

org.eclipse.e4.xwt.springclrfactory.bundle = org.eclipse.e4.xwt.springframework.osgi.sample4

The fragment org.eclipse.e4.xwt.springframework.osgi.sample4.config.springclrfactory configure that.

Launch sample4

To test this bundle, you can find spring-target-platform/sample4.launch

Launch sample4_no_auto_start

You can find spring-target-platform/sampl42_no_auto_start.launch This launch set Auto start to false. You must set start to true for the bundles :

  • org.eclipse.e4.xwt.springframework
  • org.eclipse.e4.xwt.springframework.osgi.sample4
  • org.springframework.osgi.extender

and

  • org.eclipse.e4.xwt.springframework.osgi.services.impl

Using Spring Dynamic Module (OSGi) with XWT - bean as XWT file name

It's possible to omit the bean declaration in OSGi env, by configuring the SpringCLRFactory.

org.eclipse.e4.xwt.springframework.sample5

This sample use omit the bean declaration (and the CLR factory too) in the UI.xwt file :

x:ClassFactory="+"

The CLR bean declaration in Spring file use the XWT file name (UI) :

<bean name="UI" class="ui.EventHandler" scope="prototype">  	
</bean>

org.eclipse.e4.xwt.springframework.osgi.sample5.config.springclrfactory

The OSGi fragment org.eclipse.e4.xwt.springframework.osgi.sample5.config.springclrfactory configre with springclrfactory.properties this property :

org.eclipse.e4.xwt.springclrfactory.lazy_bean = true

Which means that bean declaration is not required and it use XWT file name.

Launch sample5

To test this bundle, you can find spring-target-platform/sample5_debug.launch.

Advanced features

org.eclipse.e4.xwt.springframework.tests JUnit project test the several features that you can use with Spring support for XWT.

ICLRFactoryAware

If you wish get args or CLRFactory instance from the CLR class, your CLR class can implements the org.eclipse.e4.xwt.springframework.ICLRFactoryAware interface :

package org.eclipse.e4.xwt.springframework;
 
import org.eclipse.e4.xwt.ICLRFactory;
 
public interface ICLRFactoryAware {
 
  void setCLRFactory(ICLRFactory factory, IArguments args);
}

Where IArguments is the args parsed :

package org.eclipse.e4.xwt.springframework;
 
import org.eclipse.e4.xwt.ICLRFactory;
 
public interface IArguments {
 
	String getSource();
 
	String getValue(String name);
}

Example :

public class CLR implements ICLRFactoryAware {
 
	private ICLRFactory factory;
 
	private IArguments args;
 
	public void setCLRFactory(ICLRFactory factory, IArguments args) {
		this.factory = factory;
		this.args = args;
	}

If you have:

x:ClassFactory="org.eclipse.e4.xwt.tests.clrfactory.CLRFactory bean=myCLR"
  • args.getSource() will return "bean=myCLR".
  • args.getValue("bean") will return "myCLR"

Configuration

Properties

configure timeout

SpringCLRFactory must retrieve Spring ApplicationContext from the OSGi registry services by using an OSGi ServiceTracker. By default timeout of this tracker is setted to 5000(ms), but it's possible to customize it with the property :

org.eclipse.e4.xwt.springclrfactory.timeout = 4000

To do that you can do With JVM parameters or With OSGi Fragment.

configure default bundle

Into OSGi context, to avoid setting the bundle parameter into x:ClassFactory for each XWT file like this :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=<myBean> bundle=<myBundle>"

It's possible to set a default bundle value with the property :

org.eclipse.e4.xwt.springclrfactory.bundle = org.eclipse.e4.xwt.springframework.osgi.sample1

So after you can write :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=<myBean>"
configure default SpringCLRFactory

Into OSGi context, to avoid setting the SpringCLRFactory into x:ClassFactory for each XWT file like this :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=<myBean> bundle=<myBundle>"

It's possible to set lazy mode like this :

org.eclipse.e4.xwt.springclrfactory.lazy = true

So after you can write :

x:ClassFactory="+ bean=<myBean> bundle=<myBundle>"

character '+' means that you wish use the default CLR Factory (in this case, SpringCLRFactory.INSTANCE will be used)

bean optionnal - use XWT file name

Into OSGi context, to avoid setting the beanparameter into x:ClassFactory for each XWT file like this :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bean=<myBean> bundle=<myBundle>"

It's possible to use XWT file name as a Spring bean mode like this :

org.eclipse.e4.xwt.springclrfactory.lazy_bean = true

So after you can write :

x:ClassFactory="org.eclipse.e4.xwt.springframework.SpringCLRFactory.INSTANCE bundle=<myBundle>"

and Spring bean declaration must declare a Spring bean CLR with the XWT file name.

Ex : for the UI.xwt file name, bean name "UI" must be declared :

<bean name="UI" class="ui.EventHandler" scope="prototype">
</bean>

With JVM parameters

Example :

-Dorg.eclipse.e4.xwt.springclrfactory.lazy = true
-Dorg.eclipse.e4.xwt.springclrfactory.timeout = 4000
-Dorg.eclipse.e4.xwt.springclrfactory.bundle = org.eclipse.e4.xwt.springframework.osgi.sample4

With OSGi Fragment

To customize SpringCLRFactory with OSGi fragment, you can create an OSGi Fragment linked to org.eclipse.e4.xwt.springframework and create springclrfactory.properties file into src folder with the configuration . Example :

org.eclipse.e4.xwt.springclrfactory.lazy = true
org.eclipse.e4.xwt.springclrfactory.timeout = 4000
org.eclipse.e4.xwt.springclrfactory.bundle = org.eclipse.e4.xwt.springframework.osgi.sample4

You can find fragment sample which configure SpringCLRFactory into the org.eclipse.e4.xwt.springframework.osgi.sample4.config.springclrfactory fragment . With this configuration, XWT file can use this syntax :

x:ClassFactory="+ bean=myUI"

Debug

You can debug the org.eclipse.e4.xwt.springframework bundle with standard OSGi Trace.

SpringCLRFactory tracing.png

You will find sample4_debug.launch which launch the sample4 with debug mode. Launch this sample4_debug.launch and OSGi console will display on start of the bundle org.eclipse.e4.xwt.springframework teh configuration (here timeout and bundle properties was configured with springclrfactory.properties) :

[SpringCLRFactory] BEGIN Activator#start
	[SpringCLRFactory] Property <org.eclipse.e4.xwt.springclrfactory.timeout>=4000 [from springclrfactory.properties].
	[SpringCLRFactory] Property <org.eclipse.e4.xwt.springclrfactory.bundle>=org.eclipse.e4.xwt.springframework.osgi.sample4 [from springclrfactory.properties].
	[SpringCLRFactory] Property <org.eclipse.e4.xwt.springclrfactory.lazy>=true [from springclrfactory.properties].
	[SpringCLRFactory] Use SpringCLRFactory.INSTANCE as default XWT x:ClassFactory. XWT file can use syntax x:ClassFactory="+ bean=<myBean> bundle=<myBundle>"
[SpringCLRFactory] END Activator#start

When SpringCLRFactory#createCLR is called, this trace will be displayed :

[SpringCLRFactory] BEGIN SpringCLRFactory#createCLR("bean=myUI")
	[SpringCLRFactory] bean parameter=myUI (from Arguments) [OK].
	[SpringCLRFactory] bundle parameter=org.eclipse.e4.xwt.springframework.osgi.sample4 (from Default) [OK].
	[SpringCLRFactory] OSGi Bundle <org.eclipse.e4.xwt.springframework.osgi.sample4> founded [OK].
	[SpringCLRFactory] OSGi Bundle <org.eclipse.e4.xwt.springframework.osgi.sample4> started [OK].
	[SpringCLRFactory] Searching Spring ApplicationContext from the OSGi Bundle=<org.eclipse.e4.xwt.springframework.osgi.sample4> with timeout=<4000(ms)>...
	[SpringCLRFactory] Spring ApplicationContext founded [OK].
[SpringCLRFactory] END SpringCLRFactory#createCLR("bean=myUI") [OK].