Re: DynaView, Outbound Rewrite and Action URL

Splash Forums PrettyFaces Users DynaView, Outbound Rewrite and Action URL Re: DynaView, Outbound Rewrite and Action URL



I’ve actually hacked this together somewhat, and so far it appears to be working for my use case. (Im not sure if this will inadventantly cuase other issue – but so far this seems to be working OK)

Firstly, I changed my Tomahawk menu navigation actions to be redirect actions ?faces-redirect=true&includeViewParams=true. (Not my ideal outcome)

I overloaded “restoreView” to detect if a DynaView was used originally to transform URL by PrettyFaces, and if so – then I attempted to get an instance of the DynaView (using my variable resolver) – and used the URL to restore the view.


public UIViewRoot restoreView(final FacesContext context, final String viewId)


PrettyContext prettyContext = PrettyContext.getCurrentInstance(context);


* If pretty faces has created this view via a DynaView mapping, this we should try to restore via the

* rewritten view and not the POST view. This may be different.


* For example, the posted URL might be "/admin/View.htm", but the actual View would be

* "WEB-INF/xhtml/view/View.xhtml" and JSF would have saved that view in the JSF State Manager.


* Its possible that we would get a ViewExpired Exception if we coudl not find the view in the state manager.


if ( prettyContext.isDynaviewProcessed() ) {

MacallaDelegatingVariableResolver macallaDelegatingVariableResolver =

new MacallaDelegatingVariableResolver(FacesContext.getCurrentInstance().getApplication().getVariableResolver());

DynamicViewBean dynamicViewBean = (DynamicViewBean)macallaDelegatingVariableResolver.resolveVariable( context, "dynamicViewBean");

return this.getWrapped().restoreView(context, dynamicViewBean.getViewId());


else {

// Otherwise delegate to default.

return this.getWrapped().restoreView(context, viewId);



I then overloaded the getActionURL method to kind of Reverse the inbound mapping with an outbound mapping that could transform “/WEB-INF/views/htmls/{Path}” to “/virtual/{Path}” URI.


public String getActionURL(FacesContext ctx, String viewId) {


* Normally JSF can work out the correct Action URL because it remains unchanged from a request URI.


* Because "pretty-faces" rewrited this URI JSF may start to calculate invalid URIs for actions because

* The URI view root has changed. I.e JSF might calculate /mp/WEB-INF/xhtml/views/View.xhtml - which will

* produce a 404.


* Solution is to use pretty faces to re-write an outbound URL if a "DynaView" is in use. PrettyFaces will tell

* us if DynaView in use via its API.


String url = this.getWrapped().getActionURL( ctx, viewId );

PrettyContext prettyContext = PrettyContext.getCurrentInstance(ctx);

if ( prettyContext.isInNavigation() && prettyContext.isDynaviewProcessed() ) {

String currentViewId = ctx.getViewRoot().getViewId();

UrlMapping mapping = prettyContext.getCurrentMapping();


* If the current View requested is not the same as the existing view, then we should dynamically

* re-write the outbound URL using the same process as the inbound dynaview mechanism.


if (!StringUtils.equals( currentViewId, viewId ) ) {

PrettyConfig config = prettyContext.getConfig();

// todo: is this needed?

ctx.getViewRoot().setViewId( viewId );

// Get a explicit mapping, coudl detect via URL -

// but probably not as obvious to others.

mapping = config.getMappingById("simple-generic");

injectPathParams(ctx, new URL(viewId), mapping );

DynaviewEngine dynaview = new DynaviewEngine();

url = prettyContext.getContextPath() + dynaview.calculateDynaviewId( ctx, mapping ) ;


else {

// Rewrite the current DynaForm URL.

ExtractedValuesURLBuilder builder = new ExtractedValuesURLBuilder();

url = prettyContext.getContextPath() + builder.buildURL(mapping) + builder.buildQueryString(mapping);



log.debug( "Action URL was " + viewId + " and is " + url );

return url;


Lastly, Added a new Virtual URL mapping..

<url-mapping id="generic">

<pattern value="/#{dynamicViewBean.context}/#{dynamicViewBean.path}" />

<view-id value="#{dynamicViewBean.getViewId }" />


<url-mapping id="simple-generic">

<pattern value="/WEB-INF/xhtml/views/#{actionViewBean.viewName}" />

<view-id value="#{actionViewBean.getViewId }" />


I think this is a bit of a hack which I may regret later – but I thikn for now ill use this to get started.

Lincoln if you have any feedback/improvement R.e approach and code please do share. Im completely new to JSF 2.