Thanks for the thorough investigation. This does look like a bug. I won't be
able to look into it for a few days, though. Can you open a ticket in Jira
for this?
On Jan 26, 2011 4:54 PM, "Nikolaos Giannopoulos" <[email protected]>
wrote:
> All,
>
> 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;
> }
>
------------------------------------------------------------------------------
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