I will be writing a four part blog about a collaborative scenario implicating the HANA Cloud Platform and an ABAP backend Server. The blog posts will have the following content (summary):
Hopefully, I will manage to write one blog each week :smile: .
I will share the source code for the application on my git: epmwebsocket repository.The source code for this week is in this commit: e3fa300
If anyone tries to deploy a copy to the cloud, use Java Web Profile 6, latest version (currently 2.63), JRE 7.
Websocket is a communication protocol based on TCP which provides full duplex capabilities. This means that, as opposed to the model provided by the HTTP protocol, websocket allows the server to also initiate "requests" to its clients. Websocket is integrated into most modern browsers (see http://caniuse.com/#feat=websockets for a full support matrix).
Websockets are part of the JavaEE 7 Standard. In the SAP world, websockets are present at different levels:
As everything else, this protocol has its downsides when compared to plain HTTP:
So, as a personal opinion: WS should be used to issue commands to the Client and HTTP requests should be used to Transfer the actual data (e.g. via an OData Service).
Our Goal is to build a UI5 application which will react dynamically when changes occur in the underlying OData Services. More specifically, I have made an app which auto-refreshes its data model whenever an user deletes an entity (we will Focus on this simple Scenario as an example, more complex cases can of course be built in a similar fashion). The data model will be SAP's EPM model and mock data will be borrowed from the sap.m Explored apps.
First, I have built the underlying OData Service. I used JPA for the persistency and the Apache Olingo library for implementing the Service itself. I had to make a class for each DB table (= a JPA entity) and to add these classes in a persistence unit.
For simplicity, I used the existing classes and annotations with minimal modification (i.e. no business logic was attached to the Service). The only modification from the straight-forward approach shown in this blog is that I wrapped the ODataSimpleProcessor in a delegator (to be able to hook into the delete entity calls).
public class ODataSingleProcessorWrapper extends ODataSingleProcessor {
private ODataSingleProcessor delegate;
public ODataSingleProcessorWrapper(ODataSingleProcessor delegate) {
this.delegate = delegate;
}
//All the delegated methods follow...
I also included an Initializer class (which is actually a ServletContextListener) to fill in mock data each time the application is started. This will also be useful later on. The OData service could already be tested, by deploying the app and accessing the service's root URL in the browser (and maybe playing around with some requests).
After this, I built a suitable user interface to display the data, which should at least support the Delete operation. I have used a slightly modified Fiori Master-Detail Application template for generating this user Interface.
I also needed to include the logic for handling the WS Connection. With the use of the pre-existing UI5 WS library, this was pretty simple. This was implemented in the MessageHandler class (source), where I have reused some code written a while ago, which has 2 extra features:
For the moment, I had no WS connection URL for the application to use: this was done in the next step.
The Endpoint is a Java class which manages the Server side of the WS communication. The basic life cycle hooks of such connections are (these are method level annotations in the javax.websocket package):
For simplicity, I made a very simple Endpoint, which just keeps a synchronized collection of all sessions (connections with clients) and publishes a simple message to all of the at once. The publishing method (sendRefresh) is called when the OData Service DELETE entity method is called (that's why the delegate OData processor was created).
@ServerEndpoint(value = "/ws")
public class Endpoint {
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
public static void sendRefresh() {
for (Session s : sessions) {
try {
s.getBasicRemote().sendText("{\"action\": \"refresh\"}");
} catch (IOException e) { /* logging */ }
}
}
@OnOpen
public void open(Session session) {
sessions.add(session);
}
@OnClose
public void close(Session session) {
sessions.remove(session);
}
@OnError
public void error(Throwable e) { /* logging */ }
}
The URL used in the ServerEndpoint annotation was also updated in the UI5 application.
When the UI5 application deletes a row, the OData processor instructs the Endpoint to send a "refresh" message to all Clients, which the in turn call the refresh method on their OData models.
We can very simply test if it works: we just need to open the app in two different tabs and delete one row in one of the tabs. The application should automatically refresh the other tab's data model (we should see the row disappear).
That's about for this week, next week we will see how we can port this application to run on an ABAP System. See you next week :smile:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 |