Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Gemini » Scoped/Prototype beans via service registry?
Scoped/Prototype beans via service registry? [message #769678] Thu, 22 December 2011 09:18 Go to next message
Erko Knoll is currently offline Erko Knoll
Messages: 5
Registered: December 2011
Junior Member
Hi,

I'd like to know if it is possible to access the third bundle beans via service registry as scoped or prototype beans. Also I'm using Spring DM 2 instead of Blueprint but I don't think this functionality has been changed. As of now the beans which are published via service registry are singletons, even if you type explicitly scope="prototype" you are still getting a singleton and this was a known bug in Spring DM (is it fixed in Blueprint?). I've also tried to use scope="session" with aop:scope-proxy directive but it won't work as the session is not exposed to the third bundle outside of the the web bundle, at least it says "No Scope registered for scope 'session'". Is it possible to expose spring context to a bundle which is not bootstrapped by the ContextLoaderListener? It would be enough to get prototypes working via services. I'm working on architecture in which plugins (OSGi bundles) extend the web application and it would get messy if they had to extend it through singleton based beans. Workaround which I have found is to get an ApplicationContext and call getBean() method, which also works (only singletons and prototypes, AOP scoped beans are not exposed), but it's discouraged or as the Spring guys say:
Note: the application context is published as a service primarily to facilitate testing, administration, and management. Accessing this context object at runtime and invoking getBean() or similar operations is discouraged. The preferred way to access a bean defined in another application context is to export that bean as an OSGi service from the defining context, and then to import a reference to that service in the context that needs access to the service. Going via the service registry in this way ensures that a bean only sees services with compatible versions of service types, and that OSGi platform dynamics are respected.

[Updated on: Wed, 28 March 2012 13:15]

Report message to a moderator

Re: Scoped/Prototype beans via service registry? [message #770471 is a reply to message #769678] Sat, 24 December 2011 05:42 Go to previous messageGo to next message
Erko Knoll is currently offline Erko Knoll
Messages: 5
Registered: December 2011
Junior Member
Problem solved. Did a little research. Prototypes indeed won't work via service registry, known bug as stated before. By default bundle context is not web aware so it is logical only to have scopes like, singleton, prototype and bundle. As spring passes request data around in static thread bound context, it is accessible in bundles but bundles themselves don't register scopes such as request and session, so you have to do it manually. Also when you get the request scope working, it pretty much supersedes prototype scope in web aware environment (actions invoked by clients, internal services are different matter). Request and session scopes work properly via service registry and also via ApplicationContext.getBean(), you just have to add a 'aop:scoped-proxy' directive to scoped beans.

Bean for registering request and session scope (add to module-context.xml):

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.web.context.request.RequestScope"/>
</entry>
<entry key="session">
<bean class="org.springframework.web.context.request.SessionScope"/>
</entry>
</map>
</property>
</bean>

[Updated on: Wed, 28 March 2012 13:19]

Report message to a moderator

Re: Scoped/Prototype beans via service registry? [message #808364 is a reply to message #770471] Mon, 27 February 2012 12:58 Go to previous messageGo to next message
Eduardo Frazão is currently offline Eduardo Frazão
Messages: 118
Registered: January 2012
Senior Member
Hi Erko. Thankyou by sharing your research. It will be a imense help in a problem that Im having, with Eclipselink EMF + Multitenancy + Session/Prototype Service export.

Any way, I've opened a bug in Virgo, that latter was redirected to Gemini Blueprint:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=372650

Its about the prototype scope.

Att,
Re: Scoped/Prototype beans via service registry? [message #810718 is a reply to message #770471] Thu, 01 March 2012 08:23 Go to previous messageGo to next message
C TRAN-XUAN is currently offline C TRAN-XUAN
Messages: 8
Registered: December 2011
Junior Member
Hi,
@erko.knoll

Does it mean that a session bean is unregistered from the OSGi services when the http session is discarded?

What import do we have to think to add in the MANIFEST.MF? Is there any example we can have a look at?

Thanks in advance!
Re: Scoped/Prototype beans via service registry? [message #824500 is a reply to message #769678] Mon, 19 March 2012 14:47 Go to previous message
Erko Knoll is currently offline Erko Knoll
Messages: 5
Registered: December 2011
Junior Member
One thing I learned is that you cannot directly import OSGi service to a custom scoped (in my case request/session) bean in a non-web aware bundle. But in theory you should be able to do that when you write a wrapper bean which is prototype scoped and imports that service. Then you inject that wrapper bean to a custom scoped bean which you couldn't do directly. Also that limitation could be solved by modifying Spring classes.

One modification you have to do when implementing session scope manually in a non-web aware bundle is to have session scoped beans to be invalidated after redeployment. Because thread local context in which beans are stored for proxying are imported from a web aware bundle and as the web aware bundle won't get redeployed the redeployed bundle beans will live on. The limitation is that spring AOP cannot proxy beans from old lifecycle. It might be caused by having a new classloader when bundle gets redeployed, because a new classloader cannot load the same instance of a class which was loaded by some other classloader.

I modified Spring's SessionScope class to overcome this limitation. The trick is to store bundle startup time along with a bean id. When bundle gets redeployed it won't recognize its old beans.

public class PluginAwareSessionScope extends AbstractRequestAttributesScope implements ApplicationContextAware {
	private final int scope;
	private ApplicationContext applicationContext;

	public PluginAwareSessionScope() {
		this.scope = RequestAttributes.SCOPE_SESSION;
	}

	public PluginAwareSessionScope(boolean globalSession) {
		this.scope = (globalSession ? RequestAttributes.SCOPE_GLOBAL_SESSION : RequestAttributes.SCOPE_SESSION);
	}

	@Override
	protected int getScope() {
		return this.scope;
	}

	public String getConversationId() {
		return RequestContextHolder.currentRequestAttributes().getSessionId();
	}

	@Override
	public Object get(String name, ObjectFactory objectFactory) {
		Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
		synchronized (mutex) {
			return getFromPlugin(name, objectFactory);
		}
	}

	@Override
	public Object remove(String name) {
		Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
		synchronized (mutex) {
			return removeFromPlugin(name);
		}
	}
	
	public Object getFromPlugin(String name, ObjectFactory objectFactory) {
		RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
		Object scopedObject = attributes.getAttribute(name+"-"+applicationContext.getStartupDate(), getScope());
		if (scopedObject == null) {
			scopedObject = objectFactory.getObject();
			Long time = System.currentTimeMillis();
			attributes.setAttribute(name+"-"+applicationContext.getStartupDate(), scopedObject, getScope());
		}
		return scopedObject;
	}
	
	public Object removeFromPlugin(String name) {
		RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
		Object scopedObject = attributes.getAttribute(name, getScope());
		if (scopedObject != null) {
			attributes.removeAttribute(name+"-"+applicationContext.getStartupDate(), getScope());
			return scopedObject;
		} else {
			return null;
		}
	}

	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

}


Another way to solve the classloader issue is to serialize and deserialize the scoped bean when classloaders differ. In theory, solving the classloader issue would allow you to use trans-lifecyle beans outside the web aware bundle. There are other methods available to persist non-web aware bundle data, such as storing the instance reference somewhere in the web aware bundle and acquiring that instance when bundle gets redeployed. When doing so you can use the web aware bundle classloader to avoid the classloader issues (haven't tested that scenario) but in that case you have to import the referenced instance package to a web aware bundle manifest. Another way is to use a non-web aware bundle classloader but in that case you have to do the serialization trick.

[Updated on: Wed, 28 March 2012 13:27]

Report message to a moderator

Previous Topic:Gemini Web 2.0.2.RELEASE
Next Topic:Blueprint broken with alternate DocumentBuilderFactory provider
Goto Forum:
  


Current Time: Fri Aug 01 07:52:35 EDT 2014

Powered by FUDForum. Page generated in 0.01709 seconds