Saturday, July 12, 2008

Dependency Injection for Extensions, Third Edition

As you might have read from my previous posting I created an example that demonstrates the usage of Equinox Aspects as the load-time weaving engine for Spring Dynamic Modules. Now its time to describe this in more detail. :-)

My first idea behind this combination was to use the @Configurable annotation to use Spring's dependency injection mechanism for arbitrary objects which you typically don't create via the application context of spring. The default examples for this are plain domain objects, extensions are another example (they are typically created by the extension registry of Eclipse). Spring realizes the dependency injection for those objects by weaving an aspect into their classes. This aspect takes care of injecting the dependencies after each object creation. And this is the point where Equinox Aspects comes into play.

Fortunately Spring ships as a set of OSGi bundles. This is also true for "spring-aspects.jar", the JAR archive that contains the aspect that is responsible for making the @Configurable annotation work. And you can use Equinox Aspects to weave this aspect into your bundles wherever you would like to use the @Configurable extension. Sounds good, eh?

Ok, what do you need to do? Let’s go through the example step by step. First you need a target platform that contains the following:
Now you have a class that would like to use @Configurable. In my example it is a view for an RCP application that looks somewhat like this:

@Configurable
public class View extends ViewPart {

private Service service;

public void setService(Service service) {
this.service = service;
}

public void createPartControl(Composite parent) {
...


Then you define in the spring context of the same bundle the view as a spring bean, including the "service" property (the dependency that should be injected):

<bean class="org.eclipse.example.springdm.rcpview.View" scope="prototype">
<property name="service" ref="myservice"/>
</bean>

<bean id="myservice" class="org.eclipse.example.springdm.rcpview.Service"/>


Take care to define the bean for the view as of scope "prototype". This is necessary to tell spring that this bean definition should be used as prototype for various instances.
Now we need to tell your bundle to be woven with the spring aspect. Therefore you just define the aspect bundle as required bundle:

Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.springframework.bundle.spring.aspects


Now Equinox Aspects (if started correctly) weaves the aspect into your bundle wherever the @Configurable annotation is used. The next step is to tell the spring context that it should use load-time weaving and annotation configuration (plain old spring configuration for load-time weaving, nothing special here):

<context:spring-configured>
<context:annotation-config>
<context:load-time-weaver class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">


This also requires some more import package statements within your manifest:

Import-Package: org.aspectj.lang,
org.aspectj.runtime.reflect,
org.springframework.instrument.classloading,
org.springframework.beans.factory.annotation


The first two import statements are necessary because they are needed if an aspect gets woven into one of your classes. A more elegant solution for this would be to reexport those packages from the spring-aspects bundle, but they didn’t define the reexport in their manifest. Therefore you need to import them manually.
The last step is to take care of the startup sequence of your bundle. If the extension is created, your bundle should be activated to get the spring context created. This creation of the spring context should happen synchronously to ensure that the context is created when your extension object is created – otherwise the dependency injection would not work. Therefore I declare in the manifest:

Eclipse-LazyStart: true
Spring-Context: *;create-asynchronously:=false


If you would like to take a look at the complete example that I used, you can download it here:



Feedback and questions are always welcome!

33 comments:

Thomas Darimont said...

Hi Martin,

thanks for this nice wrap up :)
Btw. this looks similar to this approach ;-)
http://www.tutorials.de/forum/java/303535-spring-dynamic-modules-osgi-und-aspectj.html

Best regards,
Tom

Martin Lippert said...

Hi Tom!

Indeed, thanks for the URL.

The difference is that in my load-time weaving setting I don't need to use AJDT inside the IDE or for the projects that use @Configurable. Having the runtime stuff of AspectJ in the target platform is sufficient.

In contrast your setting does not need load-time weaving at system startup. Some matter of taste what way to prefer. But nice to know that you have the choice!

:-)

Thanks again!

Cheers,
-Martin

sebmade said...

Very interesting post, i try to execute the code but the dependency org.springframework.bundle.spring.aspects cannot be found. I use Eclipse 3.4 and Spring IDE 2.0.6. Where i'm wrong ?

Martin Lippert said...

As described in the post you need to set up for target environment carefully. Having Spring-IDE in your target platform is not sufficient. The better way would be you explicitly define a separate target platform where you add spring bundles, spring dynamic modules bundles and spring-aspect bundle.

If you don't want to have a separate target environment (for whatever reason) you can also copy spring-aspects.jar from your spring-distro to your set of bundles.

HTH,
-Martin

jef said...

Hi Martin,

I try to launch your example but it doesn't works... :( I suppose that it's linked to my configuration.


Nothing's happen, the Service is never load...

Here is my configuration :
Eclipse Version: 3.4.0
Build id: I20080617-2000


I've download and had to my Target Platform (not copy in plugin folder of my eclipse) the following bundles:

* com.springsource.org.apache.commons.logging-1.1.1
* org.aspectj.runtime_1.6.0.20080423100000
* org.aspectj.weaver_1.6.0.20080423100000
* org.eclipse.equinox.weaving.aspectj_1.0.0.200807082136
* org.eclipse.equinox.weaving.caching.j9_1.0.0.200807082136
* org.eclipse.equinox.weaving.caching_1.0.0.200807082136
* org.eclipse.equinox.weaving.hook_1.0.0.200807082136
* org.springframework.osgi.core-1.1.0
* org.springframework.osgi.extender-1.1.0
* org.springframework.osgi.io-1.1.0
* org.springframework.osgi.web-1.1.0
* com.springsource.org.aopalliance-1.0.0
* org.springframework.aop-2.5.5.A
* org.springframework.aspects-2.5.5.A
* org.springframework.beans-2.5.5.A
* org.springframework.context.support-2.5.5.A
* org.springframework.context-2.5.5.A
* org.springframework.core-2.5.5.A
* org.springframework.jdbc-2.5.5.A
* org.springframework.jms-2.5.5.A
* org.springframework.orm-2.5.5.A
* org.springframework.transaction-2.5.5.A
* org.springframework.web.servlet-2.5.5.A
* org.springframework.web-2.5.5.A

I've download the source Dependency Injection for RCP-Views using Spring & Equinox Aspects (zip)
I've include org.eclipse.example.springdm.rcp
and org.eclipse.example.springdm.rcpview in my workspace
I've not import your Log4J project


When I launch the eclpise product, I just have the following message in console : [org.aspectj.osgi.service.weaving] info Starting AspectJ weaving service ...

The window is well open and in title of messageView I have : No message service injected, therefore no message found - using defaults!

This means that injection doesn't work...


To fix the problem, I try severals things :
I try to modify the config.ini file with specifing exact path to bundle and
I try to replace in the config.ini all @n:start with @start


Please could you help me to identify the problem

Best regards,

Jean-François Garreau

Martin Lippert said...

Hi Jean-François,

I tested my config.ini with a slightly different version of Eclipse and Spring. What is the status of the spring-osgi-extender bundle when you type "ss" in the console? Is it active?

jef said...

Hello Martin thanks for yours answer

I try three configuration for launching the product :

The first is yours ("Injected Service Mail Example.launch"), spring.osgi.extender isn't include in mandatory plugin list. So I couldn't find it when I type ss.

The Second configuration I've made, has the exact path to bundles (with versions) I've put @start after all bundles where you put @n:start
In this case, I include spring.osgi.core, spring.osgi.extender and spring.osgi.oi to my mandatory plugins.
When I launch the product, severals things are log And an exception is thrown :(
Extender plugin is in ACTIVE state
Here is the content of my console when I launch my configuration :

osgi> [org.aspectj.osgi.service.weaving] info Starting AspectJ weaving service ...
21 juil. 2008 08:56:46 org.springframework.osgi.extender.internal.activator.ContextLoaderListener start
INFO: Starting [org.springframework.osgi.extender] bundle v.[1.1.0]
21 juil. 2008 08:56:46 org.springframework.osgi.extender.internal.support.ExtenderConfiguration init
INFO: No custom extender configuration detected; using defaults...
21 juil. 2008 08:56:46 org.springframework.scheduling.timer.TimerTaskExecutor afterPropertiesSet
INFO: Initializing Timer
21 juil. 2008 08:56:46 org.springframework.osgi.extender.internal.activator.ContextLoaderListener addDefaultPostProcessors
INFO: Disabled automatic Spring-DM annotation processing
21 juil. 2008 08:56:47 org.springframework.osgi.extender.support.DefaultOsgiApplicationContextCreator createApplicationContext
INFO: Discovered configurations {osgibundle:/META-INF/spring/*.xml} in bundle [Rcpview Plug-in (org.eclipse.example.springdm.rcpview;singleton:=true)]
21 juil. 2008 08:56:47 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@114a947: display name [OsgiBundleXmlApplicationContext(bundle=org.eclipse.example.springdm.rcpview, config=osgibundle:/META-INF/spring/*.xml)]; startup date [Mon Jul 21 08:56:47 CEST 2008]; root of context hierarchy
21 juil. 2008 08:56:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [bundleentry://23/META-INF/spring/spring-context.xml]
21 juil. 2008 08:56:48 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@114a947]: org.springframework.beans.factory.support.DefaultListableBeanFactory@18706f6
21 juil. 2008 08:56:48 org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor stageOne
INFO: No outstanding OSGi service dependencies, completing initialization for OsgiBundleXmlApplicationContext(bundle=org.eclipse.example.springdm.rcpview, config=osgibundle:/META-INF/spring/*.xml)
21 juil. 2008 08:56:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@18706f6: defining beans [org.springframework.context.config.internalBeanConfigurerAspect,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,loadTimeWeaver,org.eclipse.example.springdm.rcpview.View#0,myservice]; root of factory hierarchy
21 juil. 2008 08:56:48 org.springframework.osgi.context.support.AbstractOsgiBundleApplicationContext doClose
INFO: Unpublishing application context OSGi service for bundle Rcpview Plug-in (org.eclipse.example.springdm.rcpview;singleton:=true)
21 juil. 2008 08:56:48 org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@114a947: display name [OsgiBundleXmlApplicationContext(bundle=org.eclipse.example.springdm.rcpview, config=osgibundle:/META-INF/spring/*.xml)]; startup date [Mon Jul 21 08:56:47 CEST 2008]; root of context hierarchy
21 juil. 2008 08:56:48 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@18706f6: defining beans [org.springframework.context.config.internalBeanConfigurerAspect,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,loadTimeWeaver,org.eclipse.example.springdm.rcpview.View#0,myservice]; root of factory hierarchy
21 juil. 2008 08:56:48 org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor fail
GRAVE: Unable to create application context for [org.eclipse.example.springdm.rcpview], unsatisfied dependencies: none
java.lang.NoClassDefFoundError: org/aspectj/lang/NoAspectBoundException
...



here is my Config.ini for second configuration :

#Configuration File
#Fri Jul 18 13:38:58 CEST 2008
osgi.install.area=file\:C\:\\temp\\test_OSGI_With_RCP\\eclipse-SDK-3.4-win32\\eclipse
osgi.framework=file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.osgi_3.4.0.v20080605-1900.jar
osgi.bundles=reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/com.ibm.icu_3.8.1.v20080530.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/com.springsource.org.aopalliance-1.0.0.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/com.springsource.org.apache.commons.logging-1.1.1.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/javax.servlet_2.4.0.v200806031604.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/javax.servlet.jsp_2.0.0.v200806031607.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/AJDT/org.aspectj.runtime_1.6.0.20080423100000,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/AJDT/org.aspectj.weaver_1.6.0.20080423100000,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.commands_3.4.0.I20080509-2000.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.databinding_1.1.0.I20080527-2000.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.expressions_3.4.0.v20080603-2000.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.jobs_3.4.0.v20080512.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.runtime_3.4.0.v20080512.jar@start,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.runtime.compatibility.auth_3.2.100.v20070502.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.equinox.app_1.1.0.v20080421-2006.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar@2:start,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.equinox.preferences_3.2.200.v20080421-2006.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/equinoxAspect/org.eclipse.equinox.weaving.aspectj_1.0.0.200807082136.jar@4:start,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/equinoxAspect/org.eclipse.equinox.weaving.hook_1.0.0.200807082136.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/springextensionsviaaspects-20080709/org.eclipse.example.springdm.rcp,reference\:file\:C\:/temp/test_OSGI_With_RCP/springextensionsviaaspects-20080709/org.eclipse.example.springdm.rcpview,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.help_3.3.100.v20080610.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.jface_3.4.0.I20080606-1300.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.jface.databinding_1.2.0.I20080515-2000a.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.osgi.services_3.1.200.v20071203.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.swt_3.4.0.v3448f.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.swt.win32.win32.x86_3.4.0.v3448f.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.ui_3.4.0.I20080610-1200.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.ui.workbench_3.4.0.I20080606-1300.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/eclipse-SDK-3.4-win32/eclipse/plugins/org.eclipse.update.configurator_3.2.200.v20080417.jar@3:start,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.aop-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.aspects-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.beans-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.context-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.core-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.jdbc-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.orm-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringDM-1.1.0/org.springframework.osgi.core-1.1.0.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringDM-1.1.0/org.springframework.osgi.extender-1.1.0.jar@:5start,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringDM-1.1.0/org.springframework.osgi.io-1.1.0.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.transaction-2.5.5.A.jar,reference\:file\:C\:/temp/test_OSGI_With_RCP/AdditionnalBundle/SpringFrameWork-2.5.5/org.springframework.web-2.5.5.A.jar
osgi.configuration.cascaded=false
osgi.splashPath=file\:C\:/temp/test_OSGI_With_RCP/springextensionsviaaspects-20080709/org.eclipse.example.springdm.rcp
osgi.bundles.defaultStartLevel=4



The third Configuration I've try is yours but I include spring.osgi.extender in my mandatory plugin list.
I have the same result as the first configuration.
In this case, bundle extender is in RESOLVED state.
If I try to start the extender bundle, I have the same log and exception as the second configuration... :(

Best regards,

Jean-François

Martin Lippert said...

I can see org.aspectj.runtime in your config.ini but nevertheless the rcpview bundle gets an NoClassDefFoundError on one of its classes. Can you tell me whether you see org.aspectj.runtime in your console? Is it resolved?

Btw: What does Eclipse tells you when pressing "validate bundles" in your launch config? Everything fine?

jef said...

With the three config.ini, I have the same result :

org.aspectj.runtime is in Resolved state

And I have no problem when i Click "validates plugins"


Did you change your default startLevel for bundles ?


I should perhaps restart from the beginning... ?

Could I wrote you a mail with all steps of my attempt ? I could describe you all operations I done, and perhaps you will show my error.... ?


Thanks,

Jean-François

Martin Lippert said...

Sure, feel free to send me an email (lippert@acm.org). I am sure we will solve this.

Cheers,
Martin

jef said...

Problem resolved, due to my bundle configuration... :P

Thanks Martin

kyug said...

Hi Martin,

thanks a lot for this post. This extremely interesting. I'm developing a Eclipse RCP application and just now I started to look for some dependency injection framework.
I'm wondering what you actually prefer more using this AOP approach to inject dependencies to view, editors, actions, ... or use the spring extension factory?

Also do you thing this whole approach is mature enough to be used in production ready application?

Thanks a lot
Filip

Martin Lippert said...

Right now I would use the spring extension factory for a production system. Equinox Aspects is quite stable but its combination with spring dm is very cutting edge and maybe not so proven at the moment.

Just some thoughts at the moment...

Cheers,
-Martin

Frederic Conrotte said...

Thanks for this really useful blog entrw Martin!

Just small changes on my side in the Spring file with Spring 2.5.5 and Spring DM 1.1.2: weaver-class property instead of "class" for context:load-time-weaver

Looking forward to attend your talk in ESE!

Fred

Martin Lippert said...

Thanks, Frederic, for the nice feedback and the hint to the weaver class property name.

Seeing you at ESE!

Cheers,
-Martin

Frederic Conrotte said...
This comment has been removed by the author.
tee said...

Hi Martin,

thanks for this great work. After playing around a while getting the target-platform topic done DI is working now (almost).

I use it to inject a presenter class into my view. The problem ist the instance of the presenter is destroyed in the creation process.

What i've observed is this:

1. setPresenter(presenter) - perfect my instance is now in the view)
2. use spring-confiured init method and proove instance is still available - works
3. use presenter in the createPartControl() method - presenter is NULL now

quite weired, isn't it?

some lines of logging:
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Finished creating instance of bean 'abstimmfensterModel'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Eagerly caching bean 'abstimmfensterPresenter' to allow for resolving potential circular references
DEBUG [org.springframework.beans.CachedIntrospectionResults] - Not strongly caching class [de.breuninger.sop.abstimmfenster.ui.internal.AbstimmfensterPresenter] because it is not cache-safe
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Finished creating instance of bean 'abstimmfensterPresenter'
setPresenter: de.breuninger.sop.abstimmfenster.ui.internal.AbstimmfensterPresenter@1933cc
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Invoking init method 'init' on bean with name 'abstimmfensterView'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Finished creating instance of bean 'abstimmfensterView'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'abstimmfensterPresenter'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'abstimmfensterModel'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'kennzahlenManagerService'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'kennzahlenManagerService'
DEBUG [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Publishing event in context [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@bd4bac]: org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@bd4bac: display name [OsgiBundleXmlApplicationContext(bundle=de.breuninger.sop.abstimmfenster.ui, config=osgibundle:/META-INF/spring/*.xml)]; startup date [Mon Jan 05 17:42:50 CET 2009]; root of context hierarchy]
INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Publishing application context as OSGi service with properties {org.springframework.context.service.name=de.breuninger.sop.abstimmfenster.ui, Bundle-SymbolicName=de.breuninger.sop.abstimmfenster.ui, Bundle-Version=1.0.0}
init: de.breuninger.sop.abstimmfenster.ui.internal.AbstimmfensterPresenter@1933cc
DEBUG [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Publishing service under classes {org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext, org.springframework.osgi.context.ConfigurableOsgiBundleApplicationContext, org.springframework.context.ConfigurableApplicationContext, org.springframework.context.ApplicationContext, org.springframework.context.Lifecycle, org.springframework.beans.factory.ListableBeanFactory, org.springframework.beans.factory.HierarchicalBeanFactory, org.springframework.context.MessageSource, org.springframework.context.ApplicationEventPublisher, org.springframework.core.io.support.ResourcePatternResolver, org.springframework.beans.factory.BeanFactory, org.springframework.core.io.ResourceLoader, org.springframework.beans.factory.DisposableBean}
createPartControl: null
Application Started: 6944

Could you give me a pointer to narrow down this problem?

Cheers from Krefeld,

Thomas E.-E.

tee said...

aaah forgot to say:

there are three marks in the log to search for:

1. setPresenter - instance
2. init - instance
3. createPartControl - NULL

thanks a lot,

Thomas E.-E.

Martin Lippert said...

Hi Thomas!

Sorry for being late on this. Did you solve this issue in the meantime? If so, I would be happy to hear the solution. If I can still help, I would prefer to look at a running example. So it would be great if you could send me a small example to reproduce the problem?

Cheers,
-Martin

Emilio said...

Hi Martin,

First of all, congratulations, this is a great library and also a great blog.

I was trying to use the library but no success. First I've tried your sample, just to make sure the environment is ok. After some adjusts, it is working well.

When I added a new bundle and injected a class into, it looks that everything worked well. I mean, I used your view, your bundle project, your launch config. and replaced your service class for my sample (in a separeted bundle).

So I did the next step: Created a brand new bundle with a view and used that bundle which was created and tested with your sample ViewPart. It does not work. Looks like the service is not being injected. I don't see any errors on log. Probably, there is some configuration you did in your *springdm.rcpview that I didn't. Do you have any ideas about it?

Thank you!

Emilio said...

Ops! Problem solved! I have informed a wrong class name on view bean configuration in file spring-context.xml.

Martin Lippert said...

Hi Emilio! Glad to hear that you solved the problem and got your case to work! :-)

Cheers,
-Martin

Emilio said...

Hi Martin,

As I said, I'm testing some usage scenarios for dependency injection on RCP applications.

Your sample is working well, my custom sample is working also and I think I know how to setup everything to make it work.

Well, now I'm testing a new scenario where a service A injects into another service called B and B is injected into a ViewPart. It is very common pattern, for example, I have a service called CustomerService, which uses a DAOService. In this scenario, DAOService must be injected into CustomerService and CustomerService will be injected into ViewPart.

DAOService -> CustomerService -> ViewPart.

This configuration is not working yet. I tried everything to make it work but no success. I basically replicated every configuration to second and third bundle (DAOService and CustomerService respectively). The strange thing is that CustomerService is being injected to ViewPart but DAOService is not being injected in CustomerService.

Is there any configuration I'm missing?

Thank you,

Emilio said...

Can I have more than one spring-context.xml in my RCP application? I mean, one for each bundle or do I need to consolidate all configuration into just one file?

Martin Lippert said...

Each bundle can have its own spring configuration. Those configurations are isolated from each other. If you would like to inject a bean from bundle A's context into a bean from bundle B's context, you need to export this bean as OSGi service and import it within the consuming bundle to inject it. The Spring-DM documentation tells you more about this.

The annotation based @Configurable way of doing injection works at the moment only for one bundle. There is a bug/feature request against spring-aop to solve this issue, but there is nothing available right now, I think.

HTH,
-Martin

Emilio said...

Martin,

But if I would like to use service injection on ViewPart, I must use @Configurable annotation, right? Because ViewParts are instantiated automatically by Eclipse when needed.

Hmmmm, so... Does it means that I cannot use service injection if I'm developing RCP applications with many inter-module dependencies? At least for now?

Martin Lippert said...

I think you have two options to achieve this:

1. define all your viewparts within the same bundle, use @Configurable for dependency injection, define the beans you would like to inject whereever you want, export them as osgi services, import them in the viewpart bundle and inject them into the viewparts.

2. use spring dependency injection for extensions using the spring extension factory (look for posting in my blog), define your viewparts in different bundles (as you like), define the other beans whereever you like, export them if necessary as osgi services, import them in the viewpart bundles and inject them.

Both ways should solve your problems. Choose whatever you like most... :-)

HTH,
Martin

john said...

Hi Martin,

any idea as to how to config for Aspectj and Spring Webflow?

the "org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" will inevitably throw not serialized errors.

I can't figure out how to use LTW and Webflow,

Regards John.

Martin Lippert said...

Hi John!

Haven't tried WebFlow myself with LTW, but I would take a look at the specialized Spring LTW for Equinox Aspects:

http://martinlippert.blogspot.com/2009/04/load-time-weaving-for-spring-dm.html

HTH,
Martin

Jochen said...

Great article.
I would like to use DI for Extensions, but where are we today? WHat has changed since this blog post?

I see Blueprint is out with a 1.0 relase. Would I still want to use Spring Extension Factory or Equinox Aspects?

I'm a bit lost in all the old docs out there.
Thanks for a pointer to a current sample or a quick update. Much appreciated.

J.

Jochen said...

Today meaning December 2011

Martin Lippert said...

Hey Jochen!

Blueprint is out there and I think it is a great successor of Spring DM. I think your decision depends a bit on what you would like to use/combine. Do you wanna use Spring libs/frameworks and have spring configurations working within your OSGi bundles? Then Blueprint is the way to go. If you, in that case, would like to inject dependencies into Eclipse extensions (like views, editors, etc,), I would recommend the Spring Extension Factory over Equinox Aspects (the aspects version is a bit too heavyweight for most use cases). I haven't tried the Spring Extension Factory with the latest Blueprint implementations, so there might be some adjustments necessary, but the basic idea and the basic mechanism should work.

The source code for the Spring Extension Factory is also easy to understand and contains just a few classes. So if there is anything not working, go to the GitHub repo for the Spring Extension Factory, clone the repo, fix the problem and send me a pull request. Would be very happy to put that into the repo.

If you don't really want to use the Spring framework and instead are looking for dependency injection for OSGi in general, I would take a look at Declarative Services and/or maybe iPojo. If you are looking towards something Eclipse-specific (and integrated with the extension mechanism maybe), I would take a look at the Eclipse e4 DI mechanisms.

HTH,
Martin

Jochen said...

Hi Martin, thanks for your reply. That is very much appreciated. My intention i to use Spring for Di and I do want to use AOP in my plugin design. Have learned to appreciate the spring way of app design from web app development.

Will follow your recommendation and try Spring Extension Factory first. WIll come back with an update hopefully with a success story.