You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 10 Members of 9199 |
| Forum: Weld Users |
01. May 2009, 00:51 America/New_York | Link |
One of the problems I'm running into early on with Web Beans (perhaps conceptually) is how to remove or replace a contextual bean. Consider that I have the following producer bean:
public
@Stateless
class AccountProducerBean implements AccountProducer
{
@PersistenceContext EntityManager em;
@Current Identity identity;
public
@Produces
@Registered
@SessionScoped
User getCurrentUser()
{
User user = em.find(User.class, identity.getUsername());
return user != null ? user : new User();
}
}
The first time I access currentUser
the bean is created. However, unless I end the session, there is no way for me to get rid of that object from the session (because it's not really in the HttpSession, like it would have been with Seam, but is rather in Web Bean's session bean store. I want to be able to get rid of that object from the session scope and create a new one, perhaps when the user logs out. Yes, I could kill the session, but that doesn't address situations when I am producing some other session-scoped object that I need to eventually get rid of.
If this isn't possible in the spec (which it appears it isn't) can we get an extension for this?
Also, why can't producer methods return null? Is that not a valid use case? Or at least allow them to resolve to null when accessed through an EL resolver (where null can mean it just doesn't exist and that part of the page shouldn't be displayed).
16 Replies: | |||
|---|---|---|---|
The remove would be handy, yes. In Seam I sometimes just clear the instance from the context to get a fresh instance from a factory. Explicit set would be handy for outjection-like stuff but it was probably considered a no-no to have session scoped beans end up in application and request scopes.
The spec mentions If a man speaks in the forest and there is no woman around to hear him, is he still wrong? |
|||
I just can't seem to wrap my head around this. I figured out one way to remove a bean (as opposed to a producer method result): Set<Bean<User>> candidates = manager.resolveByType(HotelSearch.class); assert candidates.size() == 1; candidates.iterator().next().destroy(manager.getInstanceByType(HotelSearch.class)); However, that is just downright ugly and I don't even think it is allowed. Now producer methods can have a corresponding dispose method, which would be called by destroy if the type is the result of a @Producer method. The problem there is that the dispose method just receives the instance it is disposing...so you can act on it (such as close a connection if it's an EntityManager) but you can remove it from the context. So I'm having a tremendously difficult time with sticky state. Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
Just add a remove method in AbstractMapContext, noone will notice ;-) If a man speaks in the forest and there is no woman around to hear him, is he still wrong? |
|||
Dan Allen wrote on May 02, 2009 07:32: That sounds foreboding, coming from the SiA author... Sounds like something potentially simple/basic was overlooked in the spec/RI??? required reading: Scala and more Scala... www.artima.com |
|||
I won't say that. Likely just me just being think-headed. I like to say that may head holds stuff in good, but sometimes it takes a while for it to seep through the membrane ;) Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
I don't think the spec actually forbids removing stuff from context. And even if it would, it's not final yet ;-) If a man speaks in the forest and there is no woman around to hear him, is he still wrong? |
|||
I'm pretty sure that the spec is discouraging the explicit removal of a bean from the contexts. I'm personally having a hard time with this. I really don't see what the problem is. Once you remove it, then the next time you request it, the bean is simply resolved/instantiated again. Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
So what I am saying is that there is a distinct difference between destroy and remove. Destroy let's you terminate the state of a bean. Remove gets it out of the context to make room for a new instance to move in. Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
I want to emphasize that where this becomes a problem is on a JSF postback. Let's say you produce a value into the request scope. If JSF happens to retrieve the value while walking the tree before the Invoke Application phase, and your action changes the value that backs the producer, then when you render, you see the old value rather than the new value (a stale value). This was a case in Seam where outjection proved useful because it could If I introduce the Web Beans API, I can achieve this functionality using the following call:
Context requestContext = manager.getContext(RequestScoped.class);
((AbstractThreadLocalMapContext) requestContext).getBeanStore().remove(manager.resolveByName("results").iterator().next());
Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
Actually, BeanStore.remove() isn't really used anywhere and should, as such, be removed ;-) If a man speaks in the forest and there is no woman around to hear him, is he still wrong? |
|||
You are making these scopes like Hotel California. I don't agree that just because I want to remove an object from a context that I have chosen the wrong scope. Then longer term scopes, especially, can grow without bounds. There are plenty of cases when you need to get an object out of a scope without killing the whole scope. And it greatly hinders the feasibility of using first-level context objects, which was a pattern Seam really espoused. I want to emphasize two cases here so that we have an architectural problem to discuss.
As you know, JSF walks the hell out of the tree on a postback, enough that it's very likely it is going to resolve your bean before the Invoke Application phase. Now, if that bean is created by a request-scoped producer, then you are stuck with that value until the page finishes rendering, even if the intent of the action was to change that value. Let's say the current user is managed by a session-scoped bean, but assigned as a first-level context object by a request-scoped producer. At first, you are a guest. Then you login. Now even request scope is Another case is a conversation-scoped search. The results are produced into conversation-scope. To update them, you have to clear the list and use addAll() to repopulate the result list. That seems like a workaround to me for not being about to clear and output a new result list.
Frankly, if you can't remove values from contexts, I anticipate that people are going to fear using these contexts because of their Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
As I try to play Devil's advocate on myself, I guess the answer is that you always use manager components...and the manager components can dump their state and reestablish as needed. Then, you never produce anything into a long-term scope...otherwise it is out there in the open unmanaged and no way to clear it. I just happen to not like the idea of having to bid farewell to that approach. Dan Allen | mojavelinux.com | Author of Seam in Action |
|||
Along the same lines, what about I'm not sure that's currently possible with Seam 2.x... required reading: Scala and more Scala... www.artima.com |
|||
The producer fields in the Web Beans RI are not currently working correctly, so it makes it hard for me to evaluate them in practice. If I get the opportunity, I will dig into to the problem, but suffice to say they are not producing new values even after the scope has been reset (such as between two requests). There is a reference that is not being released somewhere. I'll try to do a formal issue report with a concrete example. Dan Allen | mojavelinux.com | Author of Seam in Action |
Dan Allen | mojavelinux.com | Author of Seam in Action