-
1. Re: Externalizing Scope: Resolving EJB References and Endpoints
pmuir Jan 31, 2010 2:03 PM (in response to alrubinger)The motivation for this is to allow Weld to cluster with EJBs in JBoss AS - currently it won't work.
CDI specifies the session and conversations contexts as being passivation capable, both of which are ultimately backed by the HTTP session. The appraoch Weld uses with Managed Beans is to put an object into the HTTP session which references both the Bean (the metadata) and the contextual instance. We take the same approach with EJBs - except that in this case the contextual instance contains not the "real" instance, but a SessionObjectReference which Weld uses to retrieve the underly EJB.
I'm not fussed how we solve this problem, whether by changing the way Weld works, or adding something to EJB 3. I don't have a good idea how to change this in Weld tho ;-)
-
2. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Jan 31, 2010 2:05 PM (in response to pmuir)Other uses for easily-consumable injectors:
- Arquillian; injects @EJBs
- ejb3-mc-int, injects @EJBs into MC Beans
- E-EJB3 or the ejb3-core test suite
S,
ALR
-
3. Re: Externalizing Scope: Resolving EJB References and Endpoints
wolfc Feb 2, 2010 7:12 AM (in response to alrubinger)Again, this problem was already resolved a long time ago. It's called home interfaces. -
4. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 2, 2010 12:27 PM (in response to wolfc)How do Home Interfaces give Weld a hook to the Container/Endpoint which is safely replicable in a cluster?
S,
ALR
-
5. Re: Externalizing Scope: Resolving EJB References and Endpoints
pmuir Feb 2, 2010 12:21 PM (in response to pmuir)BTW the reason we need to hold this reference beyond creation is to allow us to request the EJB is removed at a later date.
CDI can do this because it actively manages the lifecycle of a bean - for example a session scoped bean has a well defined point at which it is destroyed (when the http session ends) - and needs to request that the EJB container removes the EJB.
As the session is a passivating scope, and can be replicated, we also need to hold this reference across passivation.
-
6. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 2, 2010 12:30 PM (in response to alrubinger)I see what you're saying now.
Weld needs to defer SFSB removal. But they don't need a hook to the Container at all. They can do:
EJBHome home = context.lookup("MyEJB/home"); EJBObject object = home.create(); // Do stuff, then later: home.remove(object.getHandle());
Then you don't need Endpoint at all..
S,
ALR.
-
7. Re: Externalizing Scope: Resolving EJB References and Endpoints
wolfc Feb 2, 2010 1:59 PM (in response to alrubinger)Exactly, were it not that EJB 3 beans don't have a home.
So we need to bind an orphanage for Weld to adopt EJB 3 beans.
-
8. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 2, 2010 2:16 PM (in response to wolfc)I've always wondered about this anyway. Because injection of a SFSB makes little sense; it can timeout and become dead. Better to inject an EJB3-compatible "Home"-type thing. So a vendor-specific extension for us is what this sounds like. Confirm we're on the same page now?
The other points about resolving references for injection is another concern entirely; an external resolver w/ minimal dependencies.
S,
ALR
-
9. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 3, 2010 7:39 PM (in response to alrubinger)Some notes from our discussion today:
This cannot work:
//API: /** * All EJB3.x SFSBs will have this bound into JNDI * at default: [appName]/moduleName/beanName/home */ interface StatefulSessionHome { void remove(StatefulSessionHandle) boolean exists(StatefulSessionHandle); <T> T create(T type) throws IllegalArgumentException; } //API: /** * All SFSB proxies may be cast to this type * by the client */ interface StatefulSessionHandle { // Marker only from the client view } //SPI: /** * This is how the container knows the ID of the session to remove; * all SFSB proxies will implement this method */ interface StatefulSessionHandleProvider extends StatefulSessionHandle { Object getId(); } // Usage: StatefulSessionHome home = (StatefulSessionHome)context.lookup("beanName/home"); MyBusiness bean = home.create(MyBusiness.class); home.remove((StatefulSessionHandle)bean); // Traditional JNDI lookup removal: MyBusiness bean = context.lookup("beanName/remote"); home.remove((StatefulSessionHandle)bean);
Again, this is because we can't define *any* methods upon a proxy which is for business interfaces; we could introduce conflicts in method names. In the case above, no user code could have "getId();" for example.
An alternative way is to do something like have a Home per EJB Container. Then the home knows how to go into the internals of the proxy handler to extract the ID. Jaikiran wrote up a nice example:
/***************** client (weld-int) *********************/ // user looks up or injects a SFSB (as usual) UserSFSBInterface proxy = ...//get it as usual // now get a StatefulSessionHandleProvider (this needs discussion, but let's say it's available in JNDI for each SFSB) StatefulSessionHandleProvider handleProvider = ctx.lookup("beanName/handleprovider"); StatefulSessionHandle handle = handleProvider.getHandle(proxy); // do some stuff handle.destroy(); /***************** SPI*********************/ StatefulSessionHandleProvider { StatefulSessionHandle getHandle(Object proxy); } StatefulSessionHandle { destroy(); } /***************** SPI implementation (for nointerface view) *********************/ // Individual handle provider impl JavassistProxyBasedHandleProvider implements StatefulSessionHandleProvider { StatefulSessionHandle getHandle(Object proxy) { // do some checks on proxy // and return a handle new JavassistBasedSFSBHandle(proxy) } } // JavassistBased handle for nointerface view JavassistBasedSFSBHandle implements StatefulSessionHandle { Serializable sessionId; JavassistBasedSFSBHandle(Object proxy) { // this knows the magic to get the session id from proxy this.sessionId = doSomeMagicOnProxy(); } destroy() { // destroy the session using hte session id container.destroy(this.sessionId); } }
Too bad here we'd need a Home handle (HandleProvider in the example above) per container type.
S,
ALR
-
10. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 10, 2010 11:55 AM (in response to alrubinger)Doing today:
- Creation of a "sessionmanager" component to define the SPI
- Digging into what ejb3-proxy needs to bind this
- Making a base impl for business local and business remote views
- Then we need another impl for nointerface
S,
ALR
-
11. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Feb 10, 2010 5:43 PM (in response to alrubinger)https://jira.jboss.org/jira/browse/EJBTHREE-2011
Client usage is shown in the ClientUsageUnitTest:
/** * Simple demonstration of client contracts {@link SessionManager} * to prove / document its use * * @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a> * @version $Revision: $ */ public class ClientUsageUnitTest { /** * A mock {@link SessionManagerFactory} which is represented to the compiler * as type {@link Object} because JNDI lookups will provide no type information */ private static Object jndiEntry = new SessionManagerFactory() { @Override public <T> SessionManager<T> get(Class<T> businessInterface) throws IllegalArgumentException { return new SessionManager<T>() { @Override public T create(Class<T> beanInterface) throws IllegalArgumentException { // TODO Auto-generated method stub return null; } @Override public boolean exists(T proxy) throws IllegalArgumentException { // TODO Auto-generated method stub return false; } @Override public void remove(T proxy) throws NoSuchEJBException { } }; } }; /** * Shows the client usage of {@link SessionManagerFactory} and * {@link SessionManager}; doesn't really test anything (after all this * is an API component). */ @Test public void showClientUsage() { // This step mocks a JNDI lookup to a factory specific to a SFSB final SessionManagerFactory factory = (SessionManagerFactory) jndiEntry; // Get a manager specific to a bean interface for the SFSB final SessionManager<String> manager = factory.get(String.class); /* * Invoke its operations in a typesafe way */ // Create a new session final String created = manager.create(String.class); // Session exists? manager.exists(created); // Remove the session manager.remove(created); } }
Is this the view we'd like to proceed?
S,
ALR
-
12. Re: Externalizing Scope: Resolving EJB References and Endpoints
marius.bogoevici Mar 9, 2010 12:22 PM (in response to alrubinger)Andrew,
I think that the API that you're suggesting would work well with JBossSessionObjectReference - so the next question is how quickly can you make it available to be consumed by weld-int?
Thanks,
Marius
-
13. Re: Externalizing Scope: Resolving EJB References and Endpoints
alrubinger Mar 9, 2010 2:25 PM (in response to marius.bogoevici)Looks like it's time to reschedule this in, then.
The bigger issues are how we integrate it in with other dependent modules like jboss-metadata-ejb, etc. I'll dig back in starting tomorrow AM and see what estimates I can provide.
S,ALR
-
14. Re: Externalizing Scope: Resolving EJB References and Endpoints
st_patriick Nov 25, 2010 5:00 AM (in response to alrubinger)Is this the reason why SFSBs inside a CDI-enabled module are not clusterable?
Currently, I get an exception during deserialization when such SFSB is replicated to another cluster node. I was thinking of creating a separate bug for this, but it seems that it would be a duplicate of https://jira.jboss.org/browse/JBAS-8293 that points to this forum thread.