Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Creating a Whatsapp Clone - Part XII - Transcript.pdf
1. Creating a WhatsApp Clone - Part XII
Lets continue with the other entities. I’ll skip media as it’s just a copy and paste of the facebook media class and partially implemented to boot.
2. @Entity
@Indexed
public class ChatGroup {
@Id
private String id;
@Field
private String name;
@Field
private String tagline;
@Temporal(TemporalType.DATE)
private Date creationDate;
@ManyToOne
private Media avatar;
@ManyToOne
ChatGroup
ChatGroup is an entity that wraps the concept of a group. In a sense it’s similar to the User entity but has no phone
3. @Entity
@Indexed
public class ChatGroup {
@Id
private String id;
@Field
private String name;
@Field
private String tagline;
@Temporal(TemporalType.DATE)
private Date creationDate;
@ManyToOne
private Media avatar;
@ManyToOne
ChatGroup
All of these properties, the id, name, tagline, creation date and even avatar are a part of a group.
4. @Temporal(TemporalType.DATE)
private Date creationDate;
@ManyToOne
private Media avatar;
@ManyToOne
private User createdBy;
@OneToMany
@OrderBy("name ASC")
private Set<User> admins;
@OneToMany
@OrderBy("name ASC")
private Set<User> members;
public ChatGroup() {
id = UUID.randomUUID().toString();
}
ChatGroup
However, unlike a regular user a group is effectively created by a user
5. @Temporal(TemporalType.DATE)
private Date creationDate;
@ManyToOne
private Media avatar;
@ManyToOne
private User createdBy;
@OneToMany
@OrderBy("name ASC")
private Set<User> admins;
@OneToMany
@OrderBy("name ASC")
private Set<User> members;
public ChatGroup() {
id = UUID.randomUUID().toString();
}
ChatGroup
A group also has two lists of group administrators and group members
7. @Entity
@Indexed
public class ChatMessage {
@Id
private String id;
@ManyToOne
private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
ChatMessage
A chat message must be stored on servers for a while. If your device isn’t connected at this moment (e.g. flight) the server would need to keep the message until you’re
available again. It can then be purged. If we wish to be very secure we can encrypt the message based on a client public key, that way no one in the middle could “peek”
into the message. This should be easy enough to implement but I didn’t get around to do it, this would mostly be client side work. Here we store messages so they can
be fetched by the app.
Like everything else we have a unique string id per message
8. @Entity
@Indexed
public class ChatMessage {
@Id
private String id;
@ManyToOne
private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
ChatMessage
Every message naturally has an author of that message
9. @Entity
@Indexed
public class ChatMessage {
@Id
private String id;
@ManyToOne
private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
ChatGroupRepository
But more importantly a destination which can be either a different user or a group. Not both…
10. private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
private boolean ack;
@OneToMany
@OrderBy("date ASC")
private Set<Media> attachments;
public ChatMessage() {
id = UUID.randomUUID().toString();
}
ChatMessage
Every message has a date time stamp for when it was sent
11. private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
private boolean ack;
@OneToMany
@OrderBy("date ASC")
private Set<Media> attachments;
public ChatMessage() {
id = UUID.randomUUID().toString();
}
ChatMessage
The message has a text body alway, it can be null though
12. private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
private boolean ack;
@OneToMany
@OrderBy("date ASC")
private Set<Media> attachments;
public ChatMessage() {
id = UUID.randomUUID().toString();
}
ChatMessage
If we have media attachments to the message
13. private User author;
@ManyToOne
private User sentTo;
@ManyToOne
private ChatGroup sentToGroup;
@Temporal(TemporalType.TIMESTAMP)
private Date messageTime;
private String body;
private boolean ack;
@OneToMany
@OrderBy("date ASC")
private Set<Media> attachments;
public ChatMessage() {
id = UUID.randomUUID().toString();
}
ChatMessage
The ack flag indicates whether the client acknowledged receiving the message. This works great for one-to-one messages but a message sent to a group would probably
need a more elaborate ack implementation.
14. @OneToMany
@OrderBy("date ASC")
private Set<Media> attachments;
public ChatMessage() {
id = UUID.randomUUID().toString();
}
public MessageDAO getDAO() {
String[] a;
if(attachments != null && !attachments.isEmpty()) {
a = new String[attachments.size()];
Iterator<Media> i = attachments.iterator();
for(int iter = 0 ; iter < a.length ; iter++) {
a[iter] = i.next().getId();
}
} else {
a = new String[0];
}
return new MessageDAO(id, author.getId(),
sentTo != null ? sentTo.getId() : sentToGroup.getId(),
messageTime, body, a);
}
ChatMessage
The DAO is again practically copied from the facebook app, we can include the id’s for the attachments as part of the message
15. package com.codename1.whatsapp.server.entities;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface ChatMessageRepository extends
CrudRepository<ChatMessage, String> {
@Query("select n from ChatMessage n where n.ack = false and "
+ "n.sentTo.id = ?1 order by messageTime asc")
public List<ChatMessage> findByUnAcked(String sentTo);
}
ChatMessageRepository
The chat message repository includes one find method which helps us find messages that we didn’t acknowledge yet. If a specific user has pending messages this
finder is used to locate such messages and send them again.
16. import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
public class MessageDAO {
private String id;
private String authorId;
private String sentTo;
@JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSS")
private Date time;
private String body;
private String[] attachments;
public MessageDAO() {
}
public MessageDAO(String id, String authorId, String sentTo,
Date time, String body, String[] attachments) {
this.id = id;
this.authorId = authorId;
this.sentTo = sentTo;
this.time = time;
this.body = body;
MessageDAO
The MessageDAO entry represents the current message. It maps pretty accurately to the entity object.
With that we are effectively done with the entity and DAO layers. There is still an ErrorDAO but it’s effectively identical to what we had in the facebook app and is totally
trivial so I’ll skip that.