In this series of blog entries we will describe the development of a mobile chat app using SAP NetWeaver HANA Cloud as a backend. The last time Julia and Johannes explained how they enabled user authentication for our app. Now we want to give you an overview how we continued the development of this app and focus especially on the parts which are related to HANA Cloud.
Julia and Johannes did an excellent job building a Mobile Chat App and the corresponding backend totally from scratch. Our goals now are to re-design the iOS App, create a cross-platform Web App and to refactor the backend so that it is a platform which can be easily used by developers as API to develop chat clients on other devices and operating systems. Our highest priority is to keep conversations in sync with all our devices. This requires changes in the backend as well as on the iOS App.
Who writes this blog now?
Since Julia’s and Johannes’ internship at SAP is finished the project was taken over by Sanket Firodiya and me. Sanket is a SAP employee, focusing on the iOS App while I as an intern am developing a HTML5 WebApp from scratch. Together we are refactoring the backend to offer more functionality and make it more open for developers and different kind of platforms. Like Julia and Johannes did before we want to share our experiences with HANA Cloud.
By the way, we also changed the name of our project. To memorize the name easier (and actually to honor the inventors of the telegraph) we call it Wire 🙂
iOS App: New Authentication + Communication Tuning
We introduced a new, sleek navigation to the iOS app using the open source framework ViewDeck. This navigation approach is used by many top iOS apps such as Facebook, Path etc. and we thought it would be a good fit for Wire.
The user authentication now uses native SAML2 authentication instead of the previous approach of using webviews. This has lead to increased performance and also helps in debugging the authentication process better.
The Chatroom model in Core Data now has a flag to indicate whether there are unread messages in it, which is used to display chatrooms differently depending on whether they are read or unread. Chatrooms also store the latest message timestamp in them, so its easier to arrange the chatrooms in the view based on the timestamp of their messages.
One major performance drain we saw in the earlier version of the app was that we were refreshing all messages in a chatroom everytime a new message arrives. We changed that and started maintaining unique ids for messages and retrieveing only the latest messages from the server, everytime a chatroom is refreshed.
This means that a chatroom with even hundreds of messages loads much faster now since it gets almost all its messages from the Core Data store. Also, the chatroom does not have to continously ping the server to get the latest messages. The chat room is notified by the Application Delegate when it receives a remote notification from APNS and the chatroom can request the latest messages from the server only if it is currently the view for the main window of the app.
Web App: Connection to HANA Cloud
After calling a method the Service takes care of the communication. We’re using SAPUI5’s EventBus to notify the UI once a request is finished and we got a response from the backend. This helps us to make the UI independent from the communication with the backend. This gives us a big advantage: If the webservice changes and the way how we have to communicate with the backend we don’t have to rewrite the whole WebApp, but only change the service-module – the abstracted methods inside the WebApp stay the same.
We faced the problem that pulling chat-messages from the server sometimes causes the WebApp to lag and freeze for half a second, even if we handle our requestes asynchronously. So we implemented HTML5 WebWorkers in our Service-module. Everytime the service wants to send an request to the backend, the service is delegating this request to a WebWorker which is running on a another thread. The WebWorker makes the requests, is waiting for the response and is passing the response back as a JSON object. The result is a really fluid HTML5 App.
Our first approach was to implement the Web App as a separate Java Web project which is also running on HANA cloud so it is detached from the backend. Doing it this way the backend and the Web App are running on 2 different domains. Even if we are hosting both applications on HANA cloud the subdomain is different. If we then want to to an AJAX call to the backend we violate the Same origin policy concept and the browser restricts the connection with the backend.
Because of that problem our second approach was to run the Web App inside the same web project as the backend is running in. This solves the Same origin policy problem but faces us with the fact that every time we want to deploy a new version of the Web App we will have to deploy the whole backend again. To avoid this problem in the future we want to split the backend and the Web App apart again but then want to use CORS – Cross-origin resource sharing. This mechanism allows us to make XmlHttpRequests to another domain without violating the Same origin policy.
Limits of HTTP communication
So for now both, the iOS App as well as the Web App are communicating with HANA Cloud by using a RESTful webservice via HTTP. This webservice is based on a request-response-architecture. To detect if there are new messages in a chatroom we currently have two different approaches:
- One the Web App we make a request to the backend and the backend sends us back a response containing new messages (or just a successful response containing no messages if there aren’t any). Since chat messages should get distributed in real-time we check for new messages every 2.5 seconds.
- One the iOS App we rely on push notifications. Every time the App gets a push notification it updates the latest messages. This is not a reliable approach because you have to envisage that the push service is not always working or that it gets blocked inside a corporate network, caused by a proxy or firewall. To solve it we have to take as the same approach as used in the Web App.
And there is the problem.
Just imagine if this Chat App is used by several thousand people in an organization and every app that is running is sending HTTP requests every 2.5 seconds, only to check if there are new messages in a chatroom. And the server always has to respond, even if there are no new messages at all. This causes a lot of traffic and overhead. We could now try to tune our application by minimizing the requests, but this reduces only the traffic – we still would have to face a lot of requests on the backend. We could also reduce the amount of requests by just extending the interval how often an app checks for updates, but then it’s not really real-time anymore. So we decided to take a look at HTML5 WebSocket which enables us to open a consistent connection with the backend which stays open over the whole time the client is running. This has a few advantages:
- After a WebSocket connection is opened not only the client can send a request to the server, but also the server can send a request to the client. The client doesn’t have to check for new messages over and over again, it just waits until the server is notifying him when new messages arrived. Even better: Once a client sends a message the backend can forward this messages to all corresponding clients which are currently online right away – in real-time.
- Only one connection handshake per session is necessary. After that both, the client and backend can just send messages without establishing a connection over and over again.
- Because there is only one initial handshake the following communication between the client and the server runs more efficient with less overhead. This saves a lot of traffic compared to the HTTP-approach.
What we definitely have to consider in the future is how scalable WebSocket is when it comes to simultaneous open connections the server has to manage. Even if managing an idle connection is as less expensive as constantly setting up a new connection, it might be interesting how Tomcat handles these open connections, how much memory each connection consumes and most important: Where the limits are.
Currently we are implementing WebSocket on our backend. We have faced a few problems with WebSocket regarding to HANA Cloud (see) but hopefully find a way around it. Once WebSocket communication is working we have the opportunity to implement a lot of new features. Due to the increased performance and reduced delay enabled by WebSocket we could for example implement features like Write-Notification (showing “User is currently typing a message”) or synchronizing conversations across running apps within milliseconds. We’re also planning to do Performance Testing and try out to find the limits of the WebSocket-approach.
In the following blog post series we want to explain you parts of the mentioned topics such as the API (which can be used by other developers) as well as our approach using WebSocket in detail.