Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Spring Beans accessable via IEclipseContext(How do I get access to Spring configured beans in an e4 RCP application?)
Spring Beans accessable via IEclipseContext [message #1771158] Tue, 22 August 2017 14:54 Go to next message
Gernot Krause is currently offline Gernot KrauseFriend
Messages: 22
Registered: June 2014
Junior Member
Hello!

I have an e4 RCP application and want to connect to a database.
I have a spring configured datasource, a DAO bean and a service bean like:

MyService --> MyDao --> Datasource

The goal is to get the MyService injected into my e4 UI classes (Parts, Handler etc.)
What is the best way to get this done?

First idea was to make the MyService bean available in OSGi since OSGi services are available through e4 context. What I found was Spring DM but, this is not supported anymore. Next was Gemini Blueprint but seems to be not supported with Spring 4, is it?

Is there another way to declare a spring bean as an OSGi service?

Or can I define an OSGI declarative service in my e4 application and make it available as a bean in my Spring Plugin?

Or is Spring/e4 a bad tandem? How else can I connect to a database from e4 RCP by having the advantages of Spring?

Thanks in advance,
Gernot.
Re: Spring Beans accessable via IEclipseContext [message #1771206 is a reply to message #1771158] Tue, 22 August 2017 22:51 Go to previous messageGo to next message
Dieter Engelhardt is currently offline Dieter EngelhardtFriend
Messages: 23
Registered: June 2016
Junior Member
Hi Gernod,
I had a similiar task and I solved it by using the e4 annotatons @Createable @Singletont for Datasource Service using spring 4 Plugins. I'm not shure if i found the best solution, but it works. I Gemini was one of my firtst resources i've checked, but it seems to be not supported anymore.
Right now i'm on vacation and have no access to resources to help you further more but i'm iterested in an OSGI aproache also.
Dieter
Re: Spring Beans accessable via IEclipseContext [message #1771269 is a reply to message #1771206] Wed, 23 August 2017 15:08 Go to previous messageGo to next message
Eclipse UserFriend
Alternatively you can register an IContextFunction as an OSGi service. We use this approach widely in E4 for providing appropriate service instances based on the current context. Your IContextFunction can do some lookup in the appropriate Spring context, providing you can associate the Spring context with the application's `IEclipseContext`.
Re: Spring Beans accessable via IEclipseContext [message #1771671 is a reply to message #1771269] Tue, 29 August 2017 12:33 Go to previous messageGo to next message
Gernot Krause is currently offline Gernot KrauseFriend
Messages: 22
Registered: June 2014
Junior Member
Hi!

I tried a little the last days, and my idea was like this:

I split the MyService into 2 services: MyClientService and MyRemoteService. The remote services is created as a declarative OSGi service in a separate bundle which is also Spring enabled and manages the Spring context. The bundle has an Activator class that implements BundleActivator. In the start() method the Spring Context is created. Next, I defined a bean SpringContextProvider that implements ApplicationContextAware to get the Spring context injected. From this helper bean I can retrieve the Spring context and/or any bean by static methods getContext() or getBean(). I.e. the remote services uses this.

The client service is defined as an e4 Context Function in the client bundle and should get the remote service injected from the OSGi.

With this approach the intention is to have the client side using e4 Context Functions and get any remote services from the core bundle via OSGi. On the other hand the core bundle is free of e4 but uses Spring. And it provides remote services to OSGi.
So far so good.

However, on the core side I get an error whenever I query a bean from the Spring context. The context is created, but it seems there is no bean at all. Whenever I call getBean() from the context the error message says: "There is no bean ...".
How can this be? Different class loaders? Wrong start order? Etc.
Any ideas?

By the way: If I create a standalone Java application with static void main() and create the Spring context therein everything works fine with the same Spring configuration XMLs.

Thanks in advance.

Best regards,
Gernot.

Re: Spring Beans accessable via IEclipseContext [message #1771738 is a reply to message #1771671] Wed, 30 August 2017 04:56 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
May I ask what you see as advantage of Spring compared to e4 DI or OSGi DS? It somehow feels like you want to mix different DI implementations in one, but as I am not very familiar with Spring I don't understand what you see as benefits for doing this.
Re: Spring Beans accessable via IEclipseContext [message #1771749 is a reply to message #1771738] Wed, 30 August 2017 07:28 Go to previous messageGo to next message
Gernot Krause is currently offline Gernot KrauseFriend
Messages: 22
Registered: June 2014
Junior Member
Hi Dirk,

I have developed an e4 RCP application over the last years. Now I want to connect it to a database.

What I know and understand from Spring is that it helps to manage the whole database backend (data source, DAO, transactions, ...) and to couple the data layer loosely to my RCP application. In my e4 RCP I just want to have a service where I can get my data objects from. In my approach above I had in mind that I maybe later can export the Spring bundle to an application server and let the client service and the remote service communicate on another way than via OSGi but I am not familiar with this yet.

If you consider a pure e4 RCP application how would you implement the data layer? Is there a smart way without any getConnection(), getTransaction(), close(), etc. and catching all the various exceptions that might occur? I definitely want to avoid all this boiler plate code.

Thanks.
Re: Spring Beans accessable via IEclipseContext [message #1771760 is a reply to message #1771749] Wed, 30 August 2017 08:42 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
So it is all about DB access and not about the Spring DI. Well, I used Gemini a few years back, but that project seems to be not maintained anymore. And if you want to avoid boilerplate code, aries or using a JPA implementation directly is not an option for you.

In the end what you are trying to do does not look so bad. Separating the data access layer with Spring to not have any dependency to E4 and make it available as a service. If remote or local should not make a big difference, when running in an OSGi framework it could be simply a DS wrapper around your Spring beans.

The problem might be that there is no Spring context generated anywhere. As said I am not very familiar with Spring, but I would search for a way to make the Spring initialization similar to what you are doing in a plain Java application. Just do this in an immediate component. And then you can make things available as OSGi services.
Re: Spring Beans accessable via IEclipseContext [message #1771766 is a reply to message #1771760] Wed, 30 August 2017 09:08 Go to previous messageGo to next message
Gernot Krause is currently offline Gernot KrauseFriend
Messages: 22
Registered: June 2014
Junior Member
Good to hear that I am not completely on the wrong path.

Meanwhile I found out that the error messages mentioned above have to do with the different class loaders / classpaths. The original error message disappears if I add this.getClass() to the constructor:
springContext = new ClassPathXmlApplicationContext("my-spring-config.xml", this.getClass());


However, now I get an SAX parser error that says that the 'beans' definition (XSD) is not found...
Need to dig deeper into I think...

Re: Spring Beans accessable via IEclipseContext [message #1772168 is a reply to message #1771766] Wed, 06 September 2017 09:19 Go to previous message
Gernot Krause is currently offline Gernot KrauseFriend
Messages: 22
Registered: June 2014
Junior Member
Hi all,

meanwhile I have a running solution for my problem statement above I maybe you are interested what it is? On the other hand I appreciate your comments on weaknesses or further improvements.
So, how does my setup look now:

General setup:
- Eclipse Neon.3 (4.6.3) as IDE and target platform
- Springframework 4.3.0
- external bundle: org.eclipse.equinox.weaving.hook-1.1.200.jar

Client (e4 RCP):
- Registered a DataClientService via IContextFunction. This services requires the DataRemoteService via @Inject

Remote bundles:
- one bundle with domain model --> annotated entities (no dependencies and no Spring)
- one Spring enabled bundle (dependencies to Springframework and domain bundle)

The Spring bundle:
- has an Activator that on bundle start():
1. creates the Spring context
2. fetches the remote services from Spring context
3. registers the remote services in OSGi context
- at bundle stop()
1. remembers the services and unregisters them
2. closes the Spring context
- implementation like this:

public class CoreActivator implements BundleActivator {

	private ApplicationContext springContext;
	private List<ServiceRegistration<?>> serviceRegister = new ArrayList<ServiceRegistration<?>>();

	@Override
	public void start(BundleContext bundleContext) throws Exception {
		// Get data remote service and register to OSGi
		DataRemoteService dataRemoteService = (DataRemoteService) getContext().getBean("dataRemoteService");
		ServiceRegistration<DataRemoteService> registration = bundleContext.registerService(DataRemoteService.class, dataRemoteService, null);
		serviceRegister.add(registration);
	}

	@Override
	public void stop(BundleContext bundleContext) throws Exception {
		// Unregister all services
		serviceRegister.forEach(s -> s.unregister());

		// Close spring context 
		if (springContext instanceof ConfigurableApplicationContext) {
			((ConfigurableApplicationContext) springContext).close();
		}
	}

	private synchronized ApplicationContext getContext() {
		if (springContext == null) {
			Thread currentThread = Thread.currentThread();
			ClassLoader originalClassloader = currentThread.getContextClassLoader();
			try {
				currentThread.setContextClassLoader(this.getClass().getClassLoader());
				springContext = new ClassPathXmlApplicationContext("spring-config.xml");
			} finally {
				currentThread.setContextClassLoader(originalClassloader);
			}
		}
		return springContext;
	}
}


- the spring-config.xml is in /META-INF/spring
- it configures the DataRemoteService as a simple bean and gets the entity manager injected
- additionally, you need to create 2 more files in /META-INF:
1. spring.schemas
2. spring.handlers
- in these 2 files I copied and merged all rows from the respective files that are in the /META-INF folder of each of the org.springframework.xyz_123.jar files that I added as dependency to my bundle (.aop, .core, .beans, ...)

So, whenever my UI client requires the DataClientService it is created via e4 context function. Since this service requires the DataRemoteService the spring bundle is activated, creates the Spring context and registers all remote services to OSGI. These remote services are then inject to my client service.
With this setup I was able to receive and store object from and to the database.

What is still not running now is the load time weaving...
I found a tutorial here: https://angelozerr.wordpress.com/2010/04/30/springweaver_step1

I tried it and meanwhile it runs without errors but my domain class seems not to be weaved, i.e. it is not instanceof org.eclipse.persistence.internal.weaving.PersistenceWeaved.
My entity manager factory configuration in the spring-config.xml looks like this:

	<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="packagesToScan" value="${jpa.entity.packages}" />
		<property name="persistenceUnitName" value="myPU"/>

		<property name="loadTimeWeaver">
			<bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
				<property name="weaverScope" value="APPLICATION" />
			</bean>
		</property>
		<property name="jpaPropertyMap">
			<map>
				<entry key="eclipselink.weaving" value="true"/>
			</map>
		</property>
	</bean>


Any hint regarding load time weaving?

Please let me know what you think.

Thanks and regards,
Gernot.
Previous Topic:Key bindings scheme
Next Topic:Part specific toolbar buttons
Goto Forum:
  


Current Time: Fri Apr 19 22:29:11 GMT 2024

Powered by FUDForum. Page generated in 0.03486 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top