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: 
julia_lakatos
Explorer

In this series of blog entries we will describe the development of a mobile chat app using SAP NetWeaver Cloud as a backend. The last time we explained the web service which the mobile app consumes. Now we want to tell you more about how we store the data – on NW Cloud and also on the mobile device.

How we store data on the device?

We thought it would be useful to be able to read messages although you don’t have an Internet connection. Therefore we decided to save some data on the iPhone. We had the opportunity to use a SQLite Database, as we did in former applications, or to use Core Data. If you choose the SQLite Database you have to use SQL Statements to access to the data. Core Data is object-orientated instead, as you might now from JPA on NW Cloud. To read more about data management in iOS check out Apple developer’s website. We decided to choose Core Data because Apple recommends it and it’s always good to try something new.

There is a getting-started documentation from Apple available which explains the first steps when you want to use Core Data. When you create a new Xcode project there is a small check box with the caption “use Core Data”. If you check this one some necessary methods will already be created for you in the new application.

When you start using Core Data you will read a lot about the managedObjectContext. This is a powerful object with a central role in Core Data. You have to pass it to every ViewController which wants to access to the stored data. You can easily handle this with the few lines below in every viewDidLoad method.

// Core Data

if(managedObjectContext == nil){

managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

    }

We don’t want to talk much about Core Data because there are a lot of tutorials online and there is also the documentation from Apple. So we hope that’s enough at this point but if you have questions or suggestions please feel free to comment.

iOS Memory Management

When you have some experiences with iOS development you probably know that you have to take care of the memory yourself. And that’s sometimes a difficult topic. Since iOS 4 Apple provides the opportunity to use Automatic Reference Counting (ARC) to make the memory management easier for developers. When you are using ARC you do not have to use retain, release or autorelease anymore. We decided to use ARC to have all the advantages and an easier memory management. One error source for us was how to access the objects the right way. You have to put “self.” in front of an object to do so. If you forget that, the object will be released too early. 

Some details about how we use JPA

As we mentioned in our previous blog posts we use JPA to save all the data which is necessary for our web service. In blog post 2 [LINK] we showed you the connection between our three entities user, message and chat room. We want to show you how we implemented the link between this entities by providing you the code we need to create a new user and chat rooms for him. Let’s start with the declaration of the user entity:

// mark id-property as primary key via @Id-annotation

@Id

private String id;

// simple property of the entity

private String name;

// one user writes lots of messages, but not the other way round

@OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST) //war all

private List<Message> messages;

// a user is in lots of chatrooms, chatrooms consists of lots of users

@ManyToMany(cascade = CascadeType.PERSIST)

private List<Chatroom> chatrooms;

private String devicetoken;

private String authtoken;

// another simple property

private String email;

We leave out the corresponding getter and setter methods as they contain only one single line of code and you can use eclipse to generate them.

The other entities and their properties are created the same way. The relationship between two entities is for the other entity of course the other way round. For example in the messages entity, there is following declaration:

@ManyToOne

private User user;

Let’s take a deeper look into the code we need to create a new user. In a nutshell: Create a new user-object, set its properties and persist the object. To make it a little more complex we also create some new chat rooms for the new created user with every other user (so in the end the new user has a single 1:1 chat room with every other user).

// begin the transaction

em.getTransaction().begin();

String newusername = requestjson.getString("user").toUpperCase();                   

// create user object

User newUser = new User();

newUser.setId(newusername);

newUser.setName(requestjson.getString("user"));

// create chat rooms for new user, therefore fetch all other users

List<User> userlist = em.createQuery("SELECT u FROM User u WHERE u.id <>'" + newusername + "'", User.class).getResultList();

// create a 1:1 chatroom for every single user

for (User oneotheruser : userlist)     

   {     

   // create new chat room     

   Chatroom chatroom = new Chatroom();     

   // set (default) name of chat room on the basis of the name of the two users       

   chatroom.setName(requestjson.getString("user") + " and " + oneotheruser.getName());     

   // add existing user to new chat room     

   chatroom.getUsers().add(oneotheruser);     

   // add new user to new chat room     

   chatroom.getUsers().add(newUser);     

     // assign new created chat room to both users     

   oneotheruser.getChatrooms().add(chatroom);     

   newUser.getChatrooms().add(chatroom);     

   // persist new chatroom     

   em.persist(chatroom);     

   // persist existing user because his chat rooms were updated     

   em.persist(oneotheruser);

   }

// persist new created user after all chat rooms were created

em.persist(newUser);

// commit whole transaction

em.getTransaction().commit();

That’s it. Regarding the topic JPA you might be interested how you can read the connection between two entities. For example we need to know which chat rooms a certain user attends. Because of the many-to-many-relationship that’s where the JOIN-statement comes in:

List<Chatroom> allchatrooms = em.createQuery("SELECT c FROM Chatroom c JOIN c.users u WHERE u.id ='" +       

   requestjson.getString("user").toUpperCase() + "'", Chatroom.class).getResultList();

After this statement you can iterate over allchatrooms as it’s showed above.

How to debug your SQL Statements

Usually by using JPA you don’t need to take care about the generated SQL. But sometimes JPA fails to transfer your JPQL into proper SQL statements. One time during our development we had the strange issue that our project worked fine in the localhost environment, but in the cloud JPA was not able to create the data model. We finally solved the problem by reading the SQL logs. You have to know that in the persistence.xml of your data model project there is a setting called logging level where you can adjust the precision of the logs. Several values are possible, we use following line:

<property name="eclipselink.logging.level" value="FINE"/>


You can access the generated logs via the accounts-web site of NW Cloud (for the public test landscape follow this link). With the help of these logs we solved our issue: One of our properties was called “time” which is of course not allowed as it’s a code word.

One last thing regarding the JPA topic: Whenever we want to clear the database we temporary set the schema generation / DDL generation type to “Drop and Create Tables” and deploy our project again. If there is a more elegant way of resetting the database, please let us know.

How we enabled special characters like German umlauts in chat messages

At the beginning of our development we struggled using special characters in the messages. The reason was that we didn’t implemented UTF8 completely. We had to enable the charset UTF8 at three locations:

  • The response of our servlet has to be set to the UTF8 charset via following line:

response.setCharacterEncoding("UTF-8");

  • When we read the messages from the database we convert them to the UTF8 charset via the following codelines: 

byte[] utf8 = onemessage.getContent().getBytes();

String utf8message = new String(utf8, "UTF-8");

It would be better when we could set the general charset of the database directly to UTF8. When you find a way how to do that, please comment on this blog post.

  • There are several things to do on the iOS part. The String, which includes the JSON data, has to be encoded with UTF8.

NSString *jsonAsString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

Furthermore, we have to encode the HTTPBody of our NSMutableURLRequest with UTF8.

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:glUrl];

NSString *params = [[NSString alloc] initWithFormat:@"post=%@", jsonAsString];

[request setHTTPMethod:@"POST"];

[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];


And finally the data we get as a response of our request has to be encoded with UTF8.

NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

Now you know some details about our application. In the next blog post we will describe how we implement the iOS-Push-technology to send new chat messages directly to the device. We always appreciate your feedback so please feel free to suggest any ideas of improvement.

1 Comment