Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Introduction

This post will walk you through creating a custom MessageParser using a sample scenario for an example in which it could be used. The entire code for the working application created in this post can be found here: pritin-tyagaraj/ui5-message-parser · GitHub

Background

It is fair to say that most UI5 applications have a Netweaver Gateway/HANA XSOData service connecting it to the backend, and thus use the ODataModel of the UI5 framework. The OData protocol defines exactly how data should be passed between the UI and the Gateway service and as a result, the framework does a lot of tasks that your application would otherwise have had to do. These tasks include taking care of paging (using $top and $count) for controls that use list bindings, converting the Filter objects you apply on list bindings to equivalent $filter strings and converting dates returned by the OData service to Javascript date objects to name a few.

One more important thing it does, is take care of handling messages (success/error/information) returned by the server and convert them into appropriate UI5 objects which can then be used by your application (for example, by an sap.m.MessagePopover control instance). It is able to do this without you writing any application code, because it knows (thanks to the OData protocol that is being followed) how exactly the server's response will be structured and where within it to look for messages.


If you've built an application that uses the ODataModel - even without code to explicitly handle messages - you can still already see the messages that the framework is automagically creating by executing the following snippet in your console.


sap.ui.getCore().getMessageManager().getMessageModel().getData()



















But what happens when you are not using an OData service? What if it's a HANA XS service or some other service that does not follow the OData protocol? Here is where things get interesting - the framework is unable to understand the server's response because it does not follow a protocol that UI5 understands.



Enter, stage left - sap.ui.core.message.MessageParser

To solve this problem in a neat way, we must implement the MessageParser interface that the framework provides. This lets us write code to specify how to extract messages from the server's response. Before jumping into sample code however, let's understand the different entities that are involved in getting custom message parsing to work in our application. The following diagram gives a high level overview of how the various pieces fit together. As we continue reading about the roles that each of these boxes plays, the diagram will become easier to comprehend.

EntityDescription

Message Model

(sap.ui.model.message.MessageModel)

This is a type of model (just like JSONModel, XMLModel etc. are types) which stores, by no surprise, messages. By 'messages' here, I mean instances of the sap.ui.core.message.Message class. These have properties like 'id', 'type', 'description' and 'descriptionUrl' that are typically used to describe each message.

Message Manager

(sap.ui.core.message.MessageManager)

An instance of this class gets to know (indirectly from our message parser) which messages are no longer relevant (need to be removed from the MessageModel) and which messages are new (need to be added to the MessageModel). That's pretty much the only role that the MessageManager is playing in this picture - to make sure the messages within the MessageModel are up to date.

Message Parser

(sap.ui.core.message.MessageParser)

A MessageParser is a static class that implements the sap.ui.core.message.MessageParser interface. The only two methods that must mandatorily be implemented are parse() and setProcessor().

The parse() method expects one argument - the server's response. Our implementation of this method is expected to extract the messages within the response, and then decide which messages are 'new' and which ones are 'old' (The MessageManager uses this, like we saw above)

Message Processor

(sap.ui.core.message.MessageProcessor)

This is the class that is actually processing the server's response (and as a result, processing (or 'receiving') the messages from the server). If your application uses an ODataModel, your ODataModel is playing the role of Message Processor, since it is responsible for talking to the OData service and sending/receiving information.


The ODataModel uses a standard implementation of the MessageParser interface (sap.ui.model.odata.ODataMessageParser); and this is how messages from the OData service got pushed into the core MessageModel without us writing any code.


To demonstrate how exactly our CustomMessageParser will fit into the equation though, we'll be creating our own model. Since we will be interacting with the non-OData service using this custom model, it plays the role of MessageProcessor.

Our sample application

Defining the protocol

So we've decided to not use the OData protocol, but we still need to stick to some protocol! Let's make up a protocol (as is common to do within non-OData projects) and decide that the server's response must always have a structure similar to the following:

So our protocol requires any response from our server to be a JSON object with a 'data' node in the response, and a separate node called 'messages', which should be an array of objects - each object representing one message.



Creating the CustomMessageParser

Since we have now defined a protocol for our application to follow, we can already write our own implementation of a MessageParser.

This parse() method is called from our custom model (we'll see this next), and gets the server's response as an argument. Since we know that the response will have a node called 'messages' within it, we loop through it and create instances of sap.ui.core.message.Message (Step #2 in the overview diagram).

Once we have an array of all sap.ui.core.message.Message instances, we fire the messageChange event (Step #3) to which the standard MessageManager class will react and in response keep its MessageModel in sync. The MessageManager is instantiated in our view's controller, and our sap.m.MessagePopover control will be bound to the MessageManager's model. We will see both of these towards the end of this post.

Creating a custom model

We call the parse() method of our very own MessageParser from within the 'Message Processor', which as we saw a while back is the entity that is actually making the network request to fetch data. Since the ODataModel already ships with a powerful message parser, let's extend the JSONModel with a 'read' method similar to the ODataModel's to demonstrate where the call MessageParser is plugged in.

Once our method fetches data from the server (in our example we just fetch it from a file), it passes the response to the parse() method of the MessageParser (Step #1) to extract any messages that the response may contain. Then, it goes on to update its own internal structures to contain the actual data that the server returned. This can then be bound to UI controls via data binding.


Controller

In the view's controller, we trigger the read() method of our custom model to trigger (OK, "simulate") a network operation which retrieves a JSON object from the server. The method is expected to place the received data in the '/Customers' path; to which the sap.m.List control in our view will be bound.

Apart from triggering the read, we also create an instance of the standard sap.ui.core.message.MessageManager class. Once we register our custom model (a.k.a "the message processor") with this MessageManager instance, it will react to any messageChange events that our parser fires on the model (Step #4)


Showing messages on the UI

With everything we've looked at so far, we now have a MessageManager which contains a MessageModel - which in turn contains all the messages that we've received from our server. We now use a suitable control which can be bound (via a ListBinding) to the MessageModel. The sap.m library has a control specifically built for showing messages, so we use it - the sap.m.MessagePopover control.

End result

What we get will this work (which is by no means "just a few lines of code") and this exact output could have been achieved with much fewer lines of code. However, this is a neat and more importantly "scalable" way to handle messages when using protocols other than OData in your project - in the sense that even in a project which has a complex protocol being followed, this approach will work well and the developed code will be easy to maintain.

Hope you enjoyed reading this writeup! The source code for a working example can be found at pritin-tyagaraj/ui5-message-parser · GitHub. Your feedback is most welcome in the comments section below. :smile:

10 Comments