-
1. Re: Remote EJB invocations and Seam's Session Context
pgmjsd Jun 15, 2009 2:08 AM (in response to mgbowman)The second example might be working by accident. If Seam is not injecting 'identity' from the Session (how could it when there is no Session), then it might be working because you are just lucking out and getting the same instance of the SFSB every time.
Is there some reason you are not using the security features of Seam (i.e. <security:identity authenticate-method="#{authenticator.authenticate}"
security-rules="#{securityRules}"
remember-me="true"/> in components.xml)? -
2. Re: Remote EJB invocations and Seam's Session Context
mgbowman Jun 15, 2009 7:41 AM (in response to mgbowman)Internally (from within the EJB) I am using the seam security features, however this problem goes much deeper than I originally thought.
The issue stems from the fact that the container (in my case JBoss AS 5) is solely responsible for the remote EJB functionality - it has nothing to do with Seam. Internally, JBoss has some notion of a client
session
(I mean it isn't stateless/statefulsession
bean for nothing). The problem is in the SeamInterceptor - it doesn't integrate with the container's state management in order to be able to save/restore the Session context across multiple invocations of the remote EJB.Here's the relevant code from org.jboss.seam.intercept.RootInterceptor (the root parent class of org.jboss.seam.ejb.SeamInterceptor)
protected Object invoke(InvocationContext invocation, EventType invocationType) throws Exception { if ( !isSeamComponent || !Lifecycle.isApplicationInitialized()) { //not a Seam component return invocation.proceed(); } else if ( Contexts.isEventContextActive() || Contexts.isApplicationContextActive() ) //not sure about the second bit (only needed at init time!) { // a Seam component, and Seam contexts exist return createInvocationContext(invocation, invocationType).proceed(); } else { //if invoked outside of a set of Seam contexts, //set up temporary Seam EVENT and APPLICATION //contexts just for this call Lifecycle.beginCall(); try { return createInvocationContext(invocation, invocationType).proceed(); } finally { Lifecycle.endCall(); } } }
Notice the 3 logical cases in the above invoke method:
- Not a Seam component
- Seam component inside of a Seam context
- Seam component outside of a Seam context <-- this is the case for Remote EJB invocations
Basically it's creating the Session for the lifetime of the invocation. After which, the context is destroyed and the next invocation will be in a context all it's own
Personally I would love to Seam integrate this functionality, although I'm not quite sure how feasible since I believe it would be container specific. If I have the time later on down the road, I might revisit this topic but until then, I'm settling for a REST approach since the new Seam 2.1.2.GA has much improved support for RESTeasy.
Hope this helps anyone else out there who has encountered this problem and doesn't understand. If anyone has any pointers about how this could be integrated, I would love to look into it / help with it.
Thanks,
--mgbowman
-
3. Re: Remote EJB invocations and Seam's Session Context
swd847 Jun 15, 2009 8:45 AM (in response to mgbowman)You could probably accomplish this by adding your own interceptor to manage session state. Try something like this, and make sure it runs outside of all the other interceptors:
public class SessionInterceptor{ MyMockHttpRequest session = new MyMockHttpRequest(); @AroundInvoke public Object doStuff(InvocationContext invocation) throws Exception { ServletLifecycle.beginRequest(session); Object result = invocation.proceed(); ServletLifecycle.endRequest(session); return result; } }
You can use any implementation of a MockHttpRequest you like, as long as it maintains the session state. Because the interceptor is stateful it should maintain the session scope for the life of the bean. If you were to actually create a patch to add this sort of funcationally to seam I would add a method to LifeCycle that allows you to pass in a session map when starting up the contexts.
If you want more info let me know. Depending on the lengths I go to to aviod studying tomorrow I may do up a patch.
-
4. Re: Remote EJB invocations and Seam's Session Context
swd847 Jun 15, 2009 8:58 AM (in response to mgbowman)You probably also want to check to make sure that the application context is not active before doing the LifeCycle stuff, otherwise it will not work in normal seam calls.
Also this will only maintain the session for a single bean, if you want to share the session it becomes considerably more complicated.
-
5. Re: Remote EJB invocations and Seam's Session Context
mgbowman Jun 16, 2009 7:15 AM (in response to mgbowman)In response to:
Also this will only maintain the session for a single bean, if you want to share the session it becomes considerably more complicated.Wouldn't one expect remote EJB invocations (on seam-managed components) to react the exact same way as local EJB invocations from JSF? (i.e. share the session context)
For example:
@Name("foo") @Scope(ScopeType.STATELESS) @Stateless @Local(FooLocal.class) @Remote(Foo.class) public class FooBean implements FooLocal, Foo { @In private Identity identity; ... } @Name("bar") @Scope(ScopeType.STATELESS) @Stateless @Local(BarLocal.class) @Remote(Bar.class) public class BarBean implements BarLocal, Bar { @In private Identity identity; ... }
If these two EJBs were accessed from JSF, then the Identity component which gets injected by Seam would reflect the same component. However with remote EJB invocations, they are not.
You're saying the solution of intercepting the invocation and managing the session state would fail in this example?
If so, how
considerably more complicated
would this be? Is there not enough information in the remote EJB invocations for this to be possible? Can we not somehow hook-into / intercept the lifecycle of a SLSB or SFSB in acontainer-independent
fashion?Any thoughts?
--mgbowman
-
6. Re: Remote EJB invocations and Seam's Session Context
swd847 Jun 16, 2009 8:03 AM (in response to mgbowman)The only workable solution that I can come up with is to use some kind of a session handle that gets passed around as a parameter in remote EJB calls.
As I see it you probably need to do something like this:- Create an application scoped session store component that associates a session handle with a Map of some kind. This probably needs some kind of session timeout support to prevent memory leaks.
- Create a EJB with a remote interface to create and destory sessions.
- Apply an intercetor that looks for a SessionHandle parameter in the arguments of the method it is intercepting, if it finds one it gets the session from the session store and associates it with the current LifeCycle.
This would have the unfortunate side effect that you need to pass in a SessionHandle as a parameter to all you remote methods, but I can't really see any other way of doing things, especially not for stateless session beans which may need a different session for every call. For stateful beans you could make them remeber the session they are attached to, so you just have to call a method when they are created to initally attach the session.
Also you need to call ServletLifecycle.beginSession when the session is created to initilise any @statup session scoped components.
Please note that this is all just speculation, I have not actually tried to do any of this stuff.
Stuart