package nl.quintor.jsf;
import java.io.IOException;
import java.util.Locale;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import nl.quintor.jsf.util.GenericUtils;
/**
* This ViewHandler decorates the Facelets ViewHandler (which is final) so that we
* can intercept the view resolution and generate GET urls with embedded parameters.
*/
public class DynamicGETurlGeneratingViewHandler extends ViewHandler {
public static final String COUPLINGSIGN = "-";
public static final String PARAMETERINDICATOR = "?";
/**
* The decoratee, which handles everything but the view resolution.
*/
private com.sun.facelets.FaceletViewHandler faceletViewHandler;
public DynamicGETurlGeneratingViewHandler(ViewHandler parent) {
faceletViewHandler = new com.sun.facelets.FaceletViewHandler(parent);
}
/**
* Generates a url with the GET parameters embedded (something like
* http://www.peanutbutter.com/faces/newsitems/params/id-22234.xhtml
)
*/
@Override
public String getActionURL(final FacesContext context, final String viewId) {
String resolvedViewId = solveValueBindings(context, viewId);
String result = faceletViewHandler.getActionURL(context, resolvedViewId);
int queryStart = result.indexOf(PARAMETERINDICATOR);
if (result.indexOf(PARAMETERINDICATOR) != -1) {
result = convertToJsfCompatibleUrl(result.substring(0, queryStart), result.substring(queryStart + 1));
}
return result;
}
private String convertToJsfCompatibleUrl(String viewid, String parameters) {
return viewid.replace(".xhtml", "/params/" + parameters + ".xhtml");
}
/**
* Solves all valuebindings in the given String, using a
* ExpressionFactory
from the FacesContext
.
*
* @param context The context with the resourcepool to solve expressions with.
* @param input The inputstring with optional valuebindings.
* @return A new String with all valuebindings solved.
*/
private String solveValueBindings(final FacesContext context, final String input) {
// identify all valuebindings and dynamically replace each one with its own result
String resolvedViewId = GenericUtils.replaceStrings("[\\#\\$]\\{.*\\}", input, new GenericUtils.Replacer() {
public String solve(String oldValue) {
ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
ValueExpression expression = expressionFactory.createValueExpression(context.getELContext(), oldValue, String.class);
return expression.getValue(context.getELContext()).toString();
}
});
return resolvedViewId;
}
/*
* overridden non-abstract methods
*/
@Override
public void initView(FacesContext context)
throws FacesException {
faceletViewHandler.initView(context);
}
@Override
public String calculateCharacterEncoding(FacesContext context) {
return faceletViewHandler.calculateCharacterEncoding(context);
}
/*
* implemented abstract methods
*/
@Override
public Locale calculateLocale(FacesContext context) {
return faceletViewHandler.calculateLocale(context);
}
@Override
public String calculateRenderKitId(FacesContext context) {
return faceletViewHandler.calculateRenderKitId(context);
}
@Override
public UIViewRoot createView(FacesContext context, String viewId) {
return faceletViewHandler.createView(context, viewId);
}
@Override
public String getResourceURL(FacesContext context, String path) {
return faceletViewHandler.getResourceURL(context, path);
}
@Override
public void renderView(FacesContext context, UIViewRoot viewRoot)
throws IOException, FacesException {
faceletViewHandler.renderView(context, viewRoot);
}
@Override
public UIViewRoot restoreView(FacesContext context, String viewId) {
return faceletViewHandler.restoreView(context, viewId);
}
@Override
public void writeState(FacesContext context)
throws IOException {
faceletViewHandler.writeState(context);
}
}