Question

I am trying to implement an audit trail functionality for my web application that records:

  • lastModified (timestamp)
  • modifiedBy (user information)
  • userComment (reason for value change)

for each of my input fields (input fields are spread over several forms with different backing beans and different valueHolder classes).

The first two (lastModified and modifiedBy) are easily done with the help of an JPA AuditListener and @PrePersit and @PreUpdate methods.

The third one is a bit tricky since it requires user interaction. Best would be a dialog that asks for the user comment.

So there are (at least) two open issues: Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching <f:valueChangeListener> to each single input component? Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.

Was it helpful?

Solution

Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching to each single input component?

Yes, with a SystemEventListener which get executed during PreRenderViewEvent. You need to walk through the component tree as obtained by FacesContext#getViewRoot() to find all components which are an instanceofEditableValueHolder (or something more finer-grained) and then add the new YourValueChangeListener() by the addValueChangeListener() method. See also this answer how to register the system event listener: How to apply a JSF2 phaselistener after viewroot gets built?


Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.

You could in YourValueChangeListener#processValueChange() set the component in question as a property of some request or view scoped which you grab by evaluateExpressionGet().

Recorder recorder = (Recorder) context.getApplication().evaluateExpressionGet(context, "#{recorder}", Recorder.class);
recorder.setComponent(event.getComponent());
// ...

It will execute the EL and auto-create the bean in its scope if necessary. The bean in turn should also hold the property representing the user comment. Finally, you can use it in your <p:dialog>.

<p>You have edited #{recorder.component.label}, please mention the reason:</p>
...
<h:inputText value="#{recorder.comment}" />
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top