Help

Controls

PermLinkWikiLink

Built with Seam

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.

Forum: Weld Users Forum ListTopic List
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).

 

Dan Allen | mojavelinux.com | Author of Seam in Action

16 Replies:
01. May 2009, 20:37 America/New_York | Link

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 This restriction allows the container to use a client proxy regarding the null producer methods products...

 

If a man speaks in the forest and there is no woman around to hear him, is he still wrong?

02. May 2009, 07:32 America/New_York | Link

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

03. May 2009, 22:12 America/New_York | Link

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?

05. May 2009, 22:46 America/New_York | Link
Dan Allen wrote on May 02, 2009 07:32:
So I'm having a tremendously difficult time with sticky state.

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

05. May 2009, 23:21 America/New_York | Link

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

06. May 2009, 09:07 America/New_York | Link

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?

08. May 2009, 21:57 America/New_York | Link

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

08. May 2009, 22:12 America/New_York | Link

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

08. May 2009, 22:35 America/New_York | Link

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 update the variable with the new value. Not that we need outjection, but just so you understand what it was doing in this case. There is something more fine-grained than request scope.

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

08. May 2009, 22:58 America/New_York | Link

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?

12. May 2009, 09:28 America/New_York | Link

If you want to remove something from a context before the context ends, then the scope you defined was obviously incorrect :-)

Make it an attribute of an object, not a first-level contextal object.

 

Learn more about Weld...

15. May 2009, 18:44 America/New_York | Link

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 the incorrect scope. The alternative is a dependent-scoped producer, but then the method gets abused by JSF. You could also do #{currentUser.user} but we've been spoiled into just having #{currentUser}. I just want to stick currentUser in the session and clear it when I want a different one in the session.

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 stickiness and go with a more stateless approach.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

15. May 2009, 19:06 America/New_York | Link

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

15. May 2009, 20:51 America/New_York | Link

Along the same lines, what about promoting or demoting context variables into different scopes (e.g. conversation-scoped variable promoted to session-scope, etc.)?

I'm not sure that's currently possible with Seam 2.x...

 

required reading: Scala and more Scala... www.artima.com

15. May 2009, 21:36 America/New_York | Link

All these problems are things that I believe can be addressed (with some caveats) by producer methods/fields.

 

Learn more about Weld...

15. May 2009, 22:14 America/New_York | Link

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