How to catch client-side messages server-side

After reading this article you should be able to make your own custom client-side error handler that would allow you to send client-side errors to your backend when running a JSF Edition application.

Problem

The problem, which this article tries to address, could be simply described with the question: ”How to communicate client-side generated messages to the server?”. By enabling a mechanism which could gather information regarding client-side thrown errors and redirect them to your back-end, would make possible to log the generated client messages on server-side, which in return could be used for further analysis from a software vendor. The solution described in this article can be split up in two parts, a client-side part and obviously a server-side part.

Important Notice

Obviously this mechanism should not be abused, resulting on sending all possible client information messages to the server, including warnings and info. It can be rather considered as a tool on remote debugging, selectively and cautiously used. Communicating every single client message to the server continually, in a production environment is a highly discouraged application of the mechanism, as it will probably result on overwhelming the server traffic.

Client-side event subscription

This method is based on the fact that there is an elegant way to subscribe to-client side exceptions within the Backbase Client Framework.

The client engine dispatches client events to the document after each thrown client-side exception. The exception event object contains information in its properties, like severity and description. By using a client event handler which listens to client events of type exception (“error”) it is possible to read out the required information of caught events and then send this information to the server.

But where to attach such an event handler? Well, by stating that the events are dispatched to the document, an appropriate place would be the document and with the use of the Backbase JavaScript API it could look something like the following:

<f:verbatim>
        <e:script type="text/javascript"><![CDATA[
                               
                //define some global variable
                window.storage='';
                               
                bb.document.addEventListener('exception',function(event) {
event.stopImmediatePropagation();
                var oArgs = [event.description];
                                                       
                var sMessage = '';
                        switch(event.severity){
                                case 1:
                                        sMessage = 'severity: info'; break;
                                case 2:
                                        sMessage = 'severity: warning'; break;
                                case 3:
                                        sMessage = 'severity: error'; break;
                        }
                                                       
                                oArgs.push(sMessage);
                                                       
                        if(event.context && event.context.nodeType)
                                oArgs.push(bb.xml.serialize(event.context));
                                if(event.arguments)
                                        oArgs.push(event.arguments);
                                        //add error to global variable 
                                        window.storage = window.storage + oArgs;
                                        },
                                false
                        );
        ]]></e:script>
</f:verbatim>

The JavaScript code is inside the XEL script tag (e:script) and the first line shows how to attach an event to the document with the addEventListener method. The method accepts three arguments, the first is the name of the event type, the second is the handler function to be invoked, and the last one is a flag indicating a boolean value to initiate capture. More information about this method can be found in the Backbase Client Framework documentation.

In this article the body of the method in the second argument of the addEventListener is of most importance. Each time a message is thrown, it will be intercepted by the event handler and passed into the third argument function. In this function the severity and its corresponding description will be added to some global variable (here window.storage). Since it is possible to read out the severity, one might choose to only take errors in consideration (and not warning or info messages) in order to reduce the information load to the server. Note that because the back-end technology used in this example is Backbase JSF Edition, the f:verbatim tag is used to wrap the custom client code.

Server-side binding

With having the previous code snippet in your Backbase JSF Edition application, we are half way there. The second half requires a way to bind the gathered messages to the server. For this we use a Backbase JSF Edition inputHidden component with a valueChangeListener to hook it up to a backing bean. The following snippet illustrates this:

<bjsf:inputHidden id="clientErrorListener"
         binding="#{clientErrorCatcherBean.errorCatcher}"
         value="Backbase input text"
 valueChangeListener="#{clientErrorCatcherBean.errorCatcherChanged}" />

Here the Backbase JSF Edition inputHidden component is bound to a backing bean named clientErrorCatherBean. A valueChangeListener is added and connected to the method errorCatherChanged in the backing bean. Please notice the id attribute with the value clientErrorListener. We could have chosen to write the caught messages in the exception handler to the value of this component and register its changes. This would send a message to the server instantly after it has been caught. However this is probably not a good practice since it might become a huge overload of requests from the client to the server. Instead, we can use a visual component with some click event handler which will send the recorded messages to the back-end. Take a look to the following snippet:

<bjsf:commandButton value="Send Errors to server">
<f:verbatim>
        <e:handler event="click" type="text/javascript">
              //set window.storage value to the clientErrorListener
              bb.bjsf.registerValueChange('clientErrorListener', 'value', window.storage);
              //submit changes
              bb.bjsf.sync(bb.document.getElementById('clientErrorListener'), 'submit');
               
              //reset global
              window.storage='';
        </e:handler>
</f:verbatim>
</bjsf:commandButton>  

After clicking this command button the value stored in the global variable will be registered as a value change on the inputHidden component. Then the submit method of that component is triggered and the value is sent to the server.

Comments

docs?

Nice idea. Absolutely essential for our customer support efforts.

Can a similar technique be used in Backbase Community Edition? You refer to properties of event object like "description", "context", "severity", and "arguments", which I can find nowhere in the Backbase Client Framework 4.1.2 Reference.

Also, how do exception events work with try...catch...throw? Docs tantalize with the statement "Code within the throw element determines what to do in case of an error inside the try block" but no further information or examples are given. Can the application somehow catch and throw specific Backbase exceptions like

Exception 10 GENERIC: Unknown element: "%%"