MockRoundtrip:: trip.getActionBean() returns NULL 1st run but OK 2nd+
---------------------------------------------------------------------

                 Key: STS-803
                 URL: http://www.stripesframework.org/jira/browse/STS-803
             Project: Stripes
          Issue Type: Bug
            Reporter: Nikolaos


While the issue outlined below is "Minor" there are 2 reasons why I am flagging 
this as "Major":

(1) as it affects testing it does impede normal testing in that an expected 
non-null return of trip.getActionBean() and subsequent assertion failure test 
can not be made... so test code needs to be padded to expect and treat an error 
case as a normal case... problematic but yes not the end of the world

(2) but the bigger reason is b/c Stripes UrlBinding mechanism determines one 
set of bindings when the Stripes initializes... and then as Stripes runs 
modifies those bindings... which is cause for concern / alarm as this may have 
adverse side effects on non-test / production code... i.e. I would expect 
Stripes to initialize the bindings properly from the get go and service all 
requests uniformly (also I am not so sure these changes occur at a specified 
point in time i.e. I don't think they necessarily occur after the 1st hit of a 
given UrlBinding and I also wonder how all other bindings are affected... in 
any event it may be harmless but at this point appears a little unsettling ;-)

What follows is the e-mail sent to the list verbatim:
======================================

This issue is very bizarre and VERY interesting indeed.

I run 2 "identical" TestNG tests in a unit test - back to back - and the 1st 
fails and the 2nd succeeds:
    @DataProvider(name = "userIssueRequests")
    public Object[][] userIssueRequests() {
        return new Object[][] {
                { ShareActionBean.class, "en_US", "/share/3gi/_/edit", 
"/share/3gi/_/view" },
                { ShareActionBean.class, "en_US", "/share/3gi/_/edit", 
"/share/3gi/_/view" },
        };
    }

ShareActionBean has the following URL binding:
@UrlBinding("/share/{uuidRadix}/{titleUrlified}/{$event}")

And the following default handler:
    @DefaultHandler
    @DontValidate
    public final Resolution view() {
        return (super.view(VIEW));
    }

The test involves the following (relevant) code:
        MockRoundtrip trip = new MockRoundtrip(context, actionBeanUrl, new 
MockHttpSession(context));
        trip.execute();
        ShareActionBean bean = trip.getActionBean(ShareActionBean.class);

In BOTH cases the ShareActionBean is created and the "edit" handler (as per 
URL) is invoked.  All is well... so far...

However, In the 1st run  bean  is NULL and in the 2nd run  bean  returns the 
action bean that handled the request... HUH????

So, I did some debugging... if we drill down into trip.getActionBean(...) we 
find the following method:
    public <A extends ActionBean> A getActionBean(Class<A> type) {
        A bean = (A) this.request.getAttribute(getUrlBinding(type, 
this.context));
        if (bean == null) {
            bean = (A) 
this.request.getSession().getAttribute(getUrlBinding(type, this.context));
        }
        return bean;
    }

Here is where it gets REALLY interesting - if we simply focus on the 1st line 
of the method call:
        A bean = (A) this.request.getAttribute(getUrlBinding(type, 
this.context));

We find that   getUrlBinding(type, this.context)  returns the following as the 
key to the outer method call:
/share/{uuidRadix}/{titleUrlified}/{$event=view}

And in the 1st run   this.request.getAttribute(...)   has a map that contains:

__stripes_resolved_action=/share/{uuidRadix}/{titleUrlified}/{$event},
/share/{uuidRadix}/{titleUrlified}/{$event}=org.lightagents.ui.web.action.content.ShareActionBean@10fd9d27,
 actionBean=org.lightagents.ui.web.action.content.ShareActionBean@10fd9d27, 
__current_flash_scope=-1806527276, 
_stripes_defaultMessages=[org.lightagents.ui.stripes.extended.LocalizableMessageWarning@779dc644]}
 
whereas in the 2nd run   this.request.getAttribute(...)   has a map that 
contains:

__stripes_resolved_action=/share/{uuidRadix}/{titleUrlified}/{$event=view},
/share/{uuidRadix}/{titleUrlified}/{$event=view}=org.lightagents.ui.web.action.content.ShareActionBean@44dd7637,
 actionBean=org.lightagents.ui.web.action.content.ShareActionBean@44dd7637, 
__current_flash_scope=-624278302, 
_stripes_defaultMessages=[org.lightagents.ui.stripes.extended.LocalizableMessageWarning@779dc644]}

How can Stripes produce 2 different URL bindings for the same ActionBean in the 
same run????

This behaviour is not only odd but worrisome if there is a bug at work here 
that may affect non-Test code.


Now what is more interesting is that the ShareActionBean is setup with the 
Application logic such that if user is trying to change a Share that they do 
not have access to that they are redirected to the default handler with a 
message i.e.:
/share/3gi/_/view?__fsk=-1806527276


So we have the following things happening:

(A) Stripes UrlBinding's are determined when Stripes fires up and receives an 
initial request.  At this point the ShareActionBean is referenced to have 
cached UrlBinding of:
/share/{uuidRadix}/{titleUrlified}/{$event}

(B) Run #1 - we test the request to  "/share/3gi/_/edit" and the 
ShareActionBean "edit" event handler redirects to "/share" with params  "3gi"  
and  "_" and as such no explicitly specified "event" handler so the default one 
should be determined by Stripes.

But that causes UrlBindingParameter.getDefaultValue() to execute to determine 
that the "event" value for this action bean is the @DefaultHandler method "view"
At this point though this changes the UrlBinding component for ShareActionBean 
to have "event" with  defaultValue = "view" and moreover the ShareActionBean 
cached UrlBinding from this point forward is:
/share/{uuidRadix}/{titleUrlified}/{$event=view}

(C) However when the trip.getActionBean(...) method fires a lookup for the 
request attribute the key it got initially is used:
/share/{uuidRadix}/{titleUrlified}/{$event}

And of course this fails and no ActionBean is returned b/c this no longer maps 
to any cached UrlBinding.

(D) When Run #2 comes along and does the same thing the same thing occurs as in 
Run #1 except from the start this time though the cached UrlBinding is:
/share/{uuidRadix}/{titleUrlified}/{$event=view}

And nothing changes and all is well in that the  trip.getActionBean(...)  
method return the ShareActionBean instance


So it appears that as long as an explicit  "event"  parameter is supplied the 
getDefaultValue() method will not get called on the  "event"  
UrlBindingParameter  and until then the binding of the ActionBean will not have 
the default value embedded in it for  "event"  but once a default event URL is 
produced that bindings will appear differently.

Shouldn't Stripes ensure from the get-go try to trigger the  getDefaultValue()  
for   "event" to have it incorporated in the UrlBinding cached????

What a ride!!!!

--Nikolaos


UrlBindingParameter.java:
    public String getDefaultValue() {
        // for $event parameters with no explicit default value, get default 
from action resolver
        if (this.defaultValue == null && PARAMETER_NAME_EVENT.equals(name)) {
            try {
                Method defaultHandler = 
StripesFilter.getConfiguration().getActionResolver()
                        .getDefaultHandler(beanClass);
                HandlesEvent annotation = 
defaultHandler.getAnnotation(HandlesEvent.class);
                if (annotation != null)
                    this.defaultValue = annotation.value();
                else
                    this.defaultValue = defaultHandler.getName();
            }
            catch (Exception e) {
                /* Ignore any exceptions and just return null. */
            }
        }

        return defaultValue;
    }

-- 
This message is automatically generated by JIRA.
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

------------------------------------------------------------------------------
Special Offer-- Download ArcSight Logger for FREE (a $49 USD value)!
Finally, a world-class log management solution at an even better price-free!
Download using promo code Free_Logger_4_Dev2Dev. Offer expires 
February 28th, so secure your free ArcSight Logger TODAY! 
http://p.sf.net/sfu/arcsight-sfd2d
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to