For updated content from Camunda, check out the Camunda Blog.

JSF: Passing Parameters per HTTP GET within the URL

In JSF communication between browser and server is done by JSF with post-backs using HTTP POST. This means in all cases, that it is not possible to use parameters within the URL of a page (HTTP GET). However, for some reasons (often not technical ones) it might be desirable to use the URL (e.g. to allow visitors to bookmark a page). Within the community some discussion have been held. In this article I will introduce my solution that is working well as a pragmatical real-world solution.

Written by Hendrik Beck.

Introduction

In web applications, communication from the client to the server is usually accomplished using one of the two following ways (leaving out especially AJAX for now):

  • HTTP GET, meaning parameters and their values are being transported within the URL.
  • HTTP POST, meaning parameters are transported inside of HTTP and are (and that is the important point for us) not visible within the URL.

As a matter of fact, in the Java Server Faces (JSF) framework communication between client and server is always “automatically” done via HTTP POST, the so-called “post-back” mechanism. Although for some reasons this is obviously the right decision on how to implement post-backs, this solution has one major downside, although not really a technical one: As parameters are not being passed within the URL, usage of the URL–  for bookmarking, posting deeplinks to other pages and the like– is impossible. But this especially was a major requirement for some of our projects (like www.mad-moxx.de). If we take a closer look, there are slightly different requirements:

  • It must be possible to change the state of the web application by passing parameters per GET. This means, for example, that telling customers deeplinks to specific pages is possible, since something like …/page.jsf?pageId=123 really could change the internal state . In this case it would set the ID of the current page to ‘123’.
  • Only a group of some important parameters within the web application must be passed via HTTP GET, so that e.g. a visitor can bookmark a deep-linked page. This was the case in www.mad-moxx.de as only product and content navigation had to be handled in that way but most of the parameters could be handled using JSF’s standard mechanism.
  • All parameters must be passed via HTTP GET. This solution lacks of non-technical as well as of technical sense, so at this point I will not address it.

In the following article I describe my own solution realized using a JSF phase listener component. The component can be downloaded at the end of the article. It consists of the following:

  1. camunda-url-parameter.jar: this JAR contains two classes (the actual listener class and one for configuration purposes).
  2. url-parameter-configuration.xml: In this XML file it is configured which parameters should be processed and in which way

1. Changing the state of the web application using the URL parameter component

In JSF the state of a session is stored within the so-called ‘backing beans.’ Passing a parameter within the URL now means that the state of that session should be changed (e.g. tell the session, that the current page to display now has the ID 123). Looking at JSF, this is done by posting back values from the client to Java Objects on the server within the lifecycle phase “Update Model Values.”

Now we want to do the same but taking parameters from our URL and posting them to our backing beans. So we basically need something that reads the URL, recognizes parameters and then calls setters in our backing beans with the given values. As this should be done for every request (i.e. every time a new URL is being sent to our application) the listener mechanism seems to be a good place to put that component.

Our listener now just reads all parameters that are available in the current URL, checks in its configuration if there is an entry for the current parameter and then calls the configured method on the configured object within the current session scope (identified by its class name), eventually creating the object first and putting it into the session. That way every configured parameter can modify objects within the current session.

What we need to be able to configure now is the following:

  • The parameter itself that is being identified by its name (e.g. pageId). The name must be unique across the whole web application.
  • The class is identified by its name within the session and by its full-qualified class name.
  • The method to call is identified by its name. As a signature of this method only one String parameter is expected

This configuration can be done via XML. The following snippet shows an example configuration:

<url-parameter-configuration>
	<url-parameter>
	<name>pageId</name><managed-bean-name>Visit</managed-bean-name>
	<managed-bean-class>com.camunda.jsf.webapp.VisitBean</managed-bean-class>
	<managed-bean-method>setPageId</managed-bean-method>
	</url-parameter>
	…
<url-parameter-configuration>

As the class tries to open the XML file from “/url-parameter-configuration.xml” it must be available within the classpath. Two popular ways would be to put that file directly into the web application or to put it into a JAR and place the JAR into the /WEB-INF/lib directory of the web application. With some modifications of the source code a variety of ways is imaginable how to put that configuration into the component (Dependency Injection or Spring might be some of the keywords of interest).

The actual Listener component is a JAR file containing two classes:

  • UrlParameter: Used for the configuration of every single URL parameter.
  • UrlParameterListener: The actual listener class that has to be registered in faces-config.xml of the web application.

To register the listener, just put the following code into your faces-config.xml:

<lifecycle>
	<phase-listener>com.camunda.jsf.tools.urlparameter.UrlParameterListener</phase-listener>
</lifecycle>

Once this is done and a proper configuration is available, the component can be tested by just adding one of the configured parameters at the end of the URL: Assuming that the configuration is correct this should invoke the specified method on the backing bean.

http://localhost:8080/webapp/test.jsf?pageId=123

2. Changing internal JSF-Links to URL parameters

If it works well, parameters are being passed within the URL. The one remaining question is how links can be created inside of JSF pages that are using this mechanism. This is something the component doesn’t deal with at the moment which means it has to be done by hand. One easy–but also difficult — way would be to replace internal JSF links (h:commandLink) with h:outputLinks which allows to specify URL parameters via nested f:param tags:

<h:outputLink value="nextPage.jsf">
	<f:param name="pageId" value="#{bean.nextPageId}"/>
</h:outputLink>

This will be rendered to

http://localhost:8080/webapp/nextPage.jsf?pageId=123

But what about the JSF navigation mechanism? Good question, it doesn’t exist here anymore. In our projects (e.g. www.mad-moxx.de) we are using it only for navigation purposes (according to requirement no. 2) to enable bookmarking, etc. for product lists, product details and the like. So the number of tags to be taken care of is limited. Everything else is still being done by JSF because it’s just not interesting to see other things within the URL. It works fine in these special cases but scenarios where it’s not feasible anymore might be easy to find.

Summary: Configuration of camunda-url-parameter:

  1. Configure parameters in XML and make XML available in classpath of the web application
  2. Make camunda-url-parameter.jar available in the classpath (e.g. in /WEB-INF/lib)
  3. Register the listener in faces-config.xml

Conclusion

  • Camunda-url-parameter allows to conveniently configure parameters to be passed within the URL.
  • Links within JSF pages using that way of passing parameters still have to be done by hand (h:outputLink), but for a not too excessive use it can be a pragmatic way to solve the problem.
  • For a more extensive use a solution has to be found to create appropriate Links within JSF pages.

Download

Already read?

Scientific performance benchmark of open source BPMN engines

Why BPMN is not enough

Decision Model and Notation (DMN) – the new Business Rules Standard. An introduction by example.

New Whitepaper: The Zero-Code BPM Myth

Leave a reply