SlideShare a Scribd company logo
Creating a WhatsApp Clone - Part XIII
The next step is the services layer which implements the relatively simple business layer of this application
@Service
public class UserService {
@Autowired
private UserRepository users;
@Autowired
private ChatGroupRepository groups;
@Autowired
private ChatMessageRepository messages;
@Autowired
private APIKeys keys;
@Autowired
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
e
UserService
We’ll start with the UserService class, it’s the main class in this package and handles pretty much the entire business logic of the app

It’s a service bean, this means it handles generic business logic for the application
@Service
public class UserService {
@Autowired
private UserRepository users;
@Autowired
private ChatGroupRepository groups;
@Autowired
private ChatMessageRepository messages;
@Autowired
private APIKeys keys;
@Autowired
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
e
UserService
We need access to the repositories we just defined for users, groups and messages
@Service
public class UserService {
@Autowired
private UserRepository users;
@Autowired
private ChatGroupRepository groups;
@Autowired
private ChatMessageRepository messages;
@Autowired
private APIKeys keys;
@Autowired
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
e
UserService
The API keys service is the exact one I used in facebook with the exception of a different properties file name. I’ll discuss that later, it generally abstracts API keys and
separates them from the source code
@Service
public class UserService {
@Autowired
private UserRepository users;
@Autowired
private ChatGroupRepository groups;
@Autowired
private ChatMessageRepository messages;
@Autowired
private APIKeys keys;
@Autowired
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
e
UserService
The password encoder is used to encrypt and verify the token
private UserRepository users;
@Autowired
private ChatGroupRepository groups;
@Autowired
private ChatMessageRepository messages;
@Autowired
private APIKeys keys;
@Autowired
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
@Autowired
private NotificationService notifications;
private void sendActivationSMS(String number, String text) {
Twilio.init(keys.get("twilio.sid"), keys.get("twilio.auth"));
Message message = Message
e
UserService
MediaRepository and NotificationService are identical to the stuff we had in the facebook clone app
private PasswordEncoder encoder;
@Autowired
private MediaRepository medias;
@Autowired
private NotificationService notifications;
private void sendActivationSMS(String number, String text) {
Twilio.init(keys.get("twilio.sid"), keys.get("twilio.auth"));
Message message = Message
.creator(new PhoneNumber(number),
new PhoneNumber(keys.get("twilio.phone")),
text)
.create();
message.getSid();
}
public UserDAO login(String phone, String auth)
throws LoginException {
List<User> userList;
userList = users.findByPhone(phone);
if (userList != null && userList.size() == 1) {
e
UserService
This method sends an SMS message via the twilio web service. If you recall we added the twilio SDK into the pom file in the first lesson. This SDK makes sending an
SMS message very easy as you can see from this code.
.creator(new PhoneNumber(number),
new PhoneNumber(keys.get("twilio.phone")),
text)
.create();
message.getSid();
}
public UserDAO login(String phone, String auth)
throws LoginException {
List<User> userList;
userList = users.findByPhone(phone);
if (userList != null && userList.size() == 1) {
User u = userList.get(0);
if (encoder.matches(auth, u.getAuthtoken())) {
return u.getLoginDAO();
}
throw new LoginException("Authentication error!");
}
throw new LoginException("User not found!");
}
private String createVerificationCode(int length) {
StringBuilder k = new StringBuilder();
Random r = new Random();
e
UserService
The login API lets us validate a user and get the current data the server has for that user. Since there is no username/password we need to use a token to authenticate
.creator(new PhoneNumber(number),
new PhoneNumber(keys.get("twilio.phone")),
text)
.create();
message.getSid();
}
public UserDAO login(String phone, String auth)
throws LoginException {
List<User> userList;
userList = users.findByPhone(phone);
if (userList != null && userList.size() == 1) {
User u = userList.get(0);
if (encoder.matches(auth, u.getAuthtoken())) {
return u.getLoginDAO();
}
throw new LoginException("Authentication error!");
}
throw new LoginException("User not found!");
}
private String createVerificationCode(int length) {
StringBuilder k = new StringBuilder();
Random r = new Random();
e
UserService
First we need to find the user with the given phone. Assuming the user isn’t there we’ll throw an exception
.creator(new PhoneNumber(number),
new PhoneNumber(keys.get("twilio.phone")),
text)
.create();
message.getSid();
}
public UserDAO login(String phone, String auth)
throws LoginException {
List<User> userList;
userList = users.findByPhone(phone);
if (userList != null && userList.size() == 1) {
User u = userList.get(0);
if (encoder.matches(auth, u.getAuthtoken())) {
return u.getLoginDAO();
}
throw new LoginException("Authentication error!");
}
throw new LoginException("User not found!");
}
private String createVerificationCode(int length) {
StringBuilder k = new StringBuilder();
Random r = new Random();
e
UserService
Since the auth is hashed as we discussed before, we need to test the incoming auth via the matches method in the encoder. It verifies the hash matches the auth token
if (encoder.matches(auth, u.getAuthtoken())) {
return u.getLoginDAO();
}
throw new LoginException("Authentication error!");
}
throw new LoginException("User not found!");
}
private String createVerificationCode(int length) {
StringBuilder k = new StringBuilder();
Random r = new Random();
for (int iter = 0; iter < length; iter++) {
k.append(r.nextInt(10));
}
return k.toString();
}
public UserDAO signup(UserDAO user) throws SignupException {
List<User> ul = users.findByPhone(user.getPhone());
if (ul != null && ul.size() > 0) {
throw new SignupException(
"The phone number is already registered!");
e
UserService
This method creates a string of the given length which includes a random number for verification
return k.toString();
}
public UserDAO signup(UserDAO user) throws SignupException {
List<User> ul = users.findByPhone(user.getPhone());
if (ul != null && ul.size() > 0) {
throw new SignupException(
"The phone number is already registered!");
}
User u = new User();
setProps(user, u);
u.setAuthtoken(UUID.randomUUID().toString());
u.setVerificationCode(createVerificationCode(4));
users.save(u);
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
e
UserService
Signup creates an entry for a specific user but does’t activate the account until it’s verified
return k.toString();
}
public UserDAO signup(UserDAO user) throws SignupException {
List<User> ul = users.findByPhone(user.getPhone());
if (ul != null && ul.size() > 0) {
throw new SignupException(
"The phone number is already registered!");
}
User u = new User();
setProps(user, u);
u.setAuthtoken(UUID.randomUUID().toString());
u.setVerificationCode(createVerificationCode(4));
users.save(u);
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
e
UserService
We first check if the phone number is already registered. If so we need to fail
return k.toString();
}
public UserDAO signup(UserDAO user) throws SignupException {
List<User> ul = users.findByPhone(user.getPhone());
if (ul != null && ul.size() > 0) {
throw new SignupException(
"The phone number is already registered!");
}
User u = new User();
setProps(user, u);
u.setAuthtoken(UUID.randomUUID().toString());
u.setVerificationCode(createVerificationCode(4));
users.save(u);
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
e
UserService
Otherwise we create the new user and initialize the value of the data and the verification code
return k.toString();
}
public UserDAO signup(UserDAO user) throws SignupException {
List<User> ul = users.findByPhone(user.getPhone());
if (ul != null && ul.size() > 0) {
throw new SignupException(
"The phone number is already registered!");
}
User u = new User();
setProps(user, u);
u.setAuthtoken(UUID.randomUUID().toString());
u.setVerificationCode(createVerificationCode(4));
users.save(u);
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
e
UserService
Finally we send the activation code and return the user entity
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
public boolean verifyPhone(String userId, String code) {
User u = users.findById(userId).get();
if (u.getVerificationCode().equals(code)) {
u.setVerificationCode(null);
u.setVerified(true);
users.save(u);
return true;
}
return false;
}
private void setProps(UserDAO user, User u) {
u.setName(user.getName());
u.setTagline(user.getTagline());
}
public void update(String auth, UserDAO user) {
e
UserService
The verify method activates a user account, if the verification code is correct we mark the user as verified and return true.
sendActivationSMS(user.getPhone(), "Activation key: " + u.
getVerificationCode());
return u.getLoginDAO();
}
public boolean verifyPhone(String userId, String code) {
User u = users.findById(userId).get();
if (u.getVerificationCode().equals(code)) {
u.setVerificationCode(null);
u.setVerified(true);
users.save(u);
return true;
}
return false;
}
private void setProps(UserDAO user, User u) {
u.setName(user.getName());
u.setTagline(user.getTagline());
}
public void update(String auth, UserDAO user) {
e
UserService
We use setProps both from the signup and update methods. There isn’t much here but if we add additional meta-data this might become a bigger method like it is in the
facebook clone
}
private void setProps(UserDAO user, User u) {
u.setName(user.getName());
u.setTagline(user.getTagline());
}
public void update(String auth, UserDAO user) {
User u = users.findById(user.getId()).get();
if (encoder.matches(auth, u.getAuthtoken())) {
setProps(user, u);
users.save(u);
}
}
public byte[] getAvatar(String userId) {
User u = users.findById(userId).get();
if (u.getAvatar() != null) {
return u.getAvatar().getData();
}
return null;
}
public void setAvatar(String auth, String userId, String mediaId) {
e
UserService
Update verifies the users token then updates the properties. There isn’t much here
setProps(user, u);
users.save(u);
}
}
public byte[] getAvatar(String userId) {
User u = users.findById(userId).get();
if (u.getAvatar() != null) {
return u.getAvatar().getData();
}
return null;
}
public void setAvatar(String auth, String userId, String mediaId) {
Media m = medias.findById(mediaId).get();
User u = users.findById(userId).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setAvatar(m);
users.save(u);
}
}
public void userTyping(String userId, String toUser, boolean t) {
Optional<User> to = users.findById(toUser);
e
UserService
These aren’t used at the moment but they are pretty much identical to what we have in the facebook clone and should be easy to integrate in a similar way
User u = users.findById(userId).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setAvatar(m);
users.save(u);
}
}
public void userTyping(String userId, String toUser, boolean t) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t);
} else {
ChatGroup g = groups.findById(toUser).get();
for(User u : g.getMembers()) {
AppSocket.sendUserTyping(u.getAuthtoken(), userId, t);
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
e
UserService
This is part of the work to integrate support for the “user typing" feature. Right now the client app doesn’t send or render this event but it should be relatively simple to
add. When a user starts typing to a conversation we can invoke this method
User u = users.findById(userId).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setAvatar(m);
users.save(u);
}
}
public void userTyping(String userId, String toUser, boolean t) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t);
} else {
ChatGroup g = groups.findById(toUser).get();
for(User u : g.getMembers()) {
AppSocket.sendUserTyping(u.getAuthtoken(), userId, t);
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
e
UserService
toUser can be a user or a group is the user is present it’s a user
User u = users.findById(userId).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setAvatar(m);
users.save(u);
}
}
public void userTyping(String userId, String toUser, boolean t) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t);
} else {
ChatGroup g = groups.findById(toUser).get();
for(User u : g.getMembers()) {
AppSocket.sendUserTyping(u.getAuthtoken(), userId, t);
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
e
UserService
I’ll discuss the event code in the sockets when we reach the app socket class
User u = users.findById(userId).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setAvatar(m);
users.save(u);
}
}
public void userTyping(String userId, String toUser, boolean t) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t);
} else {
ChatGroup g = groups.findById(toUser).get();
for(User u : g.getMembers()) {
AppSocket.sendUserTyping(u.getAuthtoken(), userId, t);
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
e
UserService
If this is a group we need to send the event to all the users within the group via the socket connection
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
e
UserService
This method sends a message to its destination which can be a user or a group.
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
e
UserService
In order to send a message we first need to create a ChatMessage entity so we can persist the message in case delivery failed.
}
}
}
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
e
UserService
This is the same code we saw in the typing event. If the message is destined to a user the following block will occur
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
}
}
return cm.getDAO();
}
e
UserService
Otherwise we’ll go to the else block where the exact same code will execute in a loop over all the members of the group
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
}
}
return cm.getDAO();
}
e
UserService
We mark the destination of the message and convert it to a JSON string
public MessageDAO sendMessage(MessageDAO m) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById(m.getAuthorId()).get());
cm.setBody(m.getBody());
cm.setMessageTime(new Date());
Optional<User> to = users.findById(m.getSentTo());
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(m.getSentTo(), cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json,
m.getBody());
} else {
ChatGroup g = groups.findById(m.getSentTo()).get();
cm.setSentToGroup(g);
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
}
}
return cm.getDAO();
}
e
UserService
We the invoke the send message API
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
}
}
return cm.getDAO();
}
private void sendMessageImpl(String authToken, String pushKey,
String json, String message) {
if(!AppSocket.sendMessage(authToken, json)) {
notifications.sendPushNotification(pushKey, message, 1);
}
}
public void sendMessage(String toUser,
Map<String, Object> parsedJSON) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById((String)parsedJSON.get("authorId")).
get());
cm.setBody((String)parsedJSON.get("body"));
cm.setMessageTime(new Date());
Optional<User> to = users.findById(toUser);
e
UserService
Send message uses the socket to send the message to the device.
String json = createMessageImpl(m.getSentTo(), cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json,
m.getBody());
}
}
return cm.getDAO();
}
private void sendMessageImpl(String authToken, String pushKey,
String json, String message) {
if(!AppSocket.sendMessage(authToken, json)) {
notifications.sendPushNotification(pushKey, message, 1);
}
}
public void sendMessage(String toUser,
Map<String, Object> parsedJSON) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById((String)parsedJSON.get("authorId")).
get());
cm.setBody((String)parsedJSON.get("body"));
cm.setMessageTime(new Date());
Optional<User> to = users.findById(toUser);
e
UserService
If this failed and the device isn't reachable we should send this message as text using push notification
notifications.sendPushNotification(pushKey, message, 1);
}
}
public void sendMessage(String toUser,
Map<String, Object> parsedJSON) {
ChatMessage cm = new ChatMessage();
cm.setAuthor(users.findById((String)parsedJSON.get("authorId")).
get());
cm.setBody((String)parsedJSON.get("body"));
cm.setMessageTime(new Date());
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
cm.setSentTo(to.get());
String json = createMessageImpl(toUser, cm);
User usr = to.get();
sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(),
json, cm.getBody());
} else {
ChatGroup g = groups.findById(toUser).get();
cm.setSentToGroup(g);
String json = createMessageImpl(toUser, cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(),
e
UserService
This method is identical to the other sendMessage method but it uses a JSON string which is more convenient when a message comes in through the websocket. The
previous version is the one used when this is invoked from the webservice (which is what we use) and this one works when a message is sent via the websocket
String json = createMessageImpl(toUser, cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(),
json, cm.getBody());
}
}
}
private String createMessageImpl(String toUser, ChatMessage cm) {
cm = messages.save(cm);
ObjectMapper objectMapper = new ObjectMapper();
try {
String dao = objectMapper.writeValueAsString(cm.getDAO());
return dao;
} catch(JsonProcessingException err) {
throw new RuntimeException(err);
}
}
public void sendJSONTo(String toUser, String json) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendMessage(to.get().getAuthtoken(), json);
e
UserService
This method converts a chat message entity to JSON so we can send it to the client.
String json = createMessageImpl(toUser, cm);
for(User u : g.getMembers()) {
sendMessageImpl(u.getAuthtoken(), u.getPushKey(),
json, cm.getBody());
}
}
}
private String createMessageImpl(String toUser, ChatMessage cm) {
cm = messages.save(cm);
ObjectMapper objectMapper = new ObjectMapper();
try {
String dao = objectMapper.writeValueAsString(cm.getDAO());
return dao;
} catch(JsonProcessingException err) {
throw new RuntimeException(err);
}
}
public void sendJSONTo(String toUser, String json) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendMessage(to.get().getAuthtoken(), json);
e
UserService
object mapper can convert a POJO object to the equivalent JSON string
String dao = objectMapper.writeValueAsString(cm.getDAO());
return dao;
} catch(JsonProcessingException err) {
throw new RuntimeException(err);
}
}
public void sendJSONTo(String toUser, String json) {
Optional<User> to = users.findById(toUser);
if(to.isPresent()) {
AppSocket.sendMessage(to.get().getAuthtoken(), json);
} else {
ChatGroup g = groups.findById(toUser).get();
for(User u : g.getMembers()) {
AppSocket.sendMessage(u.getAuthtoken(), json);
}
}
}
public UserDAO findRegisteredUser(String phone) {
return fromList(users.findByPhone(phone));
}
e
UserService
This method sends JSON via the socket to the group or a user. It allows us to propagate a message onward. It works pretty much like the other methods in this class that
send to group or user
for(User u : g.getMembers()) {
AppSocket.sendMessage(u.getAuthtoken(), json);
}
}
}
public UserDAO findRegisteredUser(String phone) {
return fromList(users.findByPhone(phone));
}
private UserDAO fromList(List<User> ul) {
if(ul.isEmpty()) {
return null;
}
User u = ul.get(0);
if(!u.isVerified()) {
return null;
}
return u.getDAO();
}
public UserDAO findRegisteredUserById(String id) {
return users.findById(id).get().getDAO();
}
e
UserService
This method finds the user matching the given phone number
for(User u : g.getMembers()) {
AppSocket.sendMessage(u.getAuthtoken(), json);
}
}
}
public UserDAO findRegisteredUser(String phone) {
return fromList(users.findByPhone(phone));
}
private UserDAO fromList(List<User> ul) {
if(ul.isEmpty()) {
return null;
}
User u = ul.get(0);
if(!u.isVerified()) {
return null;
}
return u.getDAO();
}
public UserDAO findRegisteredUserById(String id) {
return users.findById(id).get().getDAO();
}
e
UserService
This method is used by findRegisteredUser and findRegisteredUserById. It generalizes the translation of a user list to a single UserDAO value. It implicitly fails for
unverified users as well
public UserDAO findRegisteredUserById(String id) {
return users.findById(id).get().getDAO();
}
public void ackMessage(String id) {
ChatMessage m = messages.findById(id).get();
m.setAck(true);
messages.save(m);
}
public void sendUnAckedMessages(String toUser) {
List<ChatMessage> mess = messages.findByUnAcked(toUser);
for(ChatMessage m : mess) {
sendMessage(m.getDAO());
}
}
public void updatePushKey(String auth, String id, String key) {
User u = users.findById(auth).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setPushKey(key);
users.save(u);
}
e
UserService
Ack allows us to acknowledge that a message was received, it just toggles the ack flag.
public UserDAO findRegisteredUserById(String id) {
return users.findById(id).get().getDAO();
}
public void ackMessage(String id) {
ChatMessage m = messages.findById(id).get();
m.setAck(true);
messages.save(m);
}
public void sendUnAckedMessages(String toUser) {
List<ChatMessage> mess = messages.findByUnAcked(toUser);
for(ChatMessage m : mess) {
sendMessage(m.getDAO());
}
}
public void updatePushKey(String auth, String id, String key) {
User u = users.findById(auth).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setPushKey(key);
users.save(u);
}
e
UserService
When a user connects via websocket this method is invoked, it finds all the messages that weren't acked by the user and sends them to that user. That way if a device
lost connection it will get the content once it’s back online.
public void ackMessage(String id) {
ChatMessage m = messages.findById(id).get();
m.setAck(true);
messages.save(m);
}
public void sendUnAckedMessages(String toUser) {
List<ChatMessage> mess = messages.findByUnAcked(toUser);
for(ChatMessage m : mess) {
sendMessage(m.getDAO());
}
}
public void updatePushKey(String auth, String id, String key) {
User u = users.findById(auth).get();
if (encoder.matches(auth, u.getAuthtoken())) {
u.setPushKey(key);
users.save(u);
}
}
}
e
UserService
This method is invoked on launch to update the push key in the server so we can send push messages to the device. With that UserService is finished

More Related Content

Similar to Creating a Whatsapp Clone - Part XIII - Transcript.pdf

Creating a Whatsapp Clone - Part XIV - Transcript.pdf
Creating a Whatsapp Clone - Part XIV - Transcript.pdfCreating a Whatsapp Clone - Part XIV - Transcript.pdf
Creating a Whatsapp Clone - Part XIV - Transcript.pdfShaiAlmog1
 
Multi client
Multi clientMulti client
Multi clientganteng8
 
Laporan multi client
Laporan multi clientLaporan multi client
Laporan multi clientichsanbarokah
 
Project: Call Center Management
Project: Call Center ManagementProject: Call Center Management
Project: Call Center Managementpritamkumar
 
Creating a Whatsapp Clone - Part III - Transcript.pdf
Creating a Whatsapp Clone - Part III - Transcript.pdfCreating a Whatsapp Clone - Part III - Transcript.pdf
Creating a Whatsapp Clone - Part III - Transcript.pdfShaiAlmog1
 
Creating an Uber Clone - Part XIII.pdf
Creating an Uber Clone - Part XIII.pdfCreating an Uber Clone - Part XIII.pdf
Creating an Uber Clone - Part XIII.pdfShaiAlmog1
 
Testando API's de forma unitária mocando as dependências
Testando API's de forma unitária mocando as dependênciasTestando API's de forma unitária mocando as dependências
Testando API's de forma unitária mocando as dependênciasMarcelo Aymone
 
Creating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdfCreating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdfShaiAlmog1
 
CloudBrew: Windows Azure Mobile Services - Next stage
CloudBrew: Windows Azure Mobile Services - Next stageCloudBrew: Windows Azure Mobile Services - Next stage
CloudBrew: Windows Azure Mobile Services - Next stageTeemu Tapanila
 
Creating a Facebook Clone - Part XXII - Transcript.pdf
Creating a Facebook Clone - Part XXII - Transcript.pdfCreating a Facebook Clone - Part XXII - Transcript.pdf
Creating a Facebook Clone - Part XXII - Transcript.pdfShaiAlmog1
 
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSAprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSLoiane Groner
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part III.pdf
Creating a Whatsapp Clone - Part III.pdfCreating a Whatsapp Clone - Part III.pdf
Creating a Whatsapp Clone - Part III.pdfShaiAlmog1
 
- the modification will be done in Main class- first, asks the use.pdf
- the modification will be done in Main class- first, asks the use.pdf- the modification will be done in Main class- first, asks the use.pdf
- the modification will be done in Main class- first, asks the use.pdfhanumanparsadhsr
 
Creating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdfCreating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdfShaiAlmog1
 
Creating a Facebook Clone - Part XXIV - Transcript.pdf
Creating a Facebook Clone - Part XXIV - Transcript.pdfCreating a Facebook Clone - Part XXIV - Transcript.pdf
Creating a Facebook Clone - Part XXIV - Transcript.pdfShaiAlmog1
 
My code is below How do I write this code without usin.pdf
My code is below How do I write this code without usin.pdfMy code is below How do I write this code without usin.pdf
My code is below How do I write this code without usin.pdfadianantsolutions
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambaryoyomay93
 

Similar to Creating a Whatsapp Clone - Part XIII - Transcript.pdf (20)

Creating a Whatsapp Clone - Part XIV - Transcript.pdf
Creating a Whatsapp Clone - Part XIV - Transcript.pdfCreating a Whatsapp Clone - Part XIV - Transcript.pdf
Creating a Whatsapp Clone - Part XIV - Transcript.pdf
 
Multi client
Multi clientMulti client
Multi client
 
Laporan multi client
Laporan multi clientLaporan multi client
Laporan multi client
 
Project: Call Center Management
Project: Call Center ManagementProject: Call Center Management
Project: Call Center Management
 
Creating a Whatsapp Clone - Part III - Transcript.pdf
Creating a Whatsapp Clone - Part III - Transcript.pdfCreating a Whatsapp Clone - Part III - Transcript.pdf
Creating a Whatsapp Clone - Part III - Transcript.pdf
 
Creating an Uber Clone - Part XIII.pdf
Creating an Uber Clone - Part XIII.pdfCreating an Uber Clone - Part XIII.pdf
Creating an Uber Clone - Part XIII.pdf
 
Testando API's de forma unitária mocando as dependências
Testando API's de forma unitária mocando as dependênciasTestando API's de forma unitária mocando as dependências
Testando API's de forma unitária mocando as dependências
 
Creating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdfCreating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdf
 
CloudBrew: Windows Azure Mobile Services - Next stage
CloudBrew: Windows Azure Mobile Services - Next stageCloudBrew: Windows Azure Mobile Services - Next stage
CloudBrew: Windows Azure Mobile Services - Next stage
 
Creating a Facebook Clone - Part XXII - Transcript.pdf
Creating a Facebook Clone - Part XXII - Transcript.pdfCreating a Facebook Clone - Part XXII - Transcript.pdf
Creating a Facebook Clone - Part XXII - Transcript.pdf
 
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSAprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdf
 
Android
AndroidAndroid
Android
 
Creating a Whatsapp Clone - Part III.pdf
Creating a Whatsapp Clone - Part III.pdfCreating a Whatsapp Clone - Part III.pdf
Creating a Whatsapp Clone - Part III.pdf
 
- the modification will be done in Main class- first, asks the use.pdf
- the modification will be done in Main class- first, asks the use.pdf- the modification will be done in Main class- first, asks the use.pdf
- the modification will be done in Main class- first, asks the use.pdf
 
Creating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdfCreating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdf
 
Creating a Facebook Clone - Part XXIV - Transcript.pdf
Creating a Facebook Clone - Part XXIV - Transcript.pdfCreating a Facebook Clone - Part XXIV - Transcript.pdf
Creating a Facebook Clone - Part XXIV - Transcript.pdf
 
My code is below How do I write this code without usin.pdf
My code is below How do I write this code without usin.pdfMy code is below How do I write this code without usin.pdf
My code is below How do I write this code without usin.pdf
 
Webauthn Tutorial
Webauthn TutorialWebauthn Tutorial
Webauthn Tutorial
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambar
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualityInflectra
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backElena Simperl
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingThijs Feryn
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...Product School
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaRTTS
 
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...QADay
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™UiPathCommunity
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Product School
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Thierry Lestable
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersSafe Software
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...Product School
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxAbida Shariff
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGuy Korland
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...Product School
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsPaul Groth
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Tobias Schneck
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...UiPathCommunity
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...BookNet Canada
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor TurskyiFwdays
 

Recently uploaded (20)

Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 

Creating a Whatsapp Clone - Part XIII - Transcript.pdf

  • 1. Creating a WhatsApp Clone - Part XIII The next step is the services layer which implements the relatively simple business layer of this application
  • 2. @Service public class UserService { @Autowired private UserRepository users; @Autowired private ChatGroupRepository groups; @Autowired private ChatMessageRepository messages; @Autowired private APIKeys keys; @Autowired private PasswordEncoder encoder; @Autowired private MediaRepository medias; e UserService We’ll start with the UserService class, it’s the main class in this package and handles pretty much the entire business logic of the app It’s a service bean, this means it handles generic business logic for the application
  • 3. @Service public class UserService { @Autowired private UserRepository users; @Autowired private ChatGroupRepository groups; @Autowired private ChatMessageRepository messages; @Autowired private APIKeys keys; @Autowired private PasswordEncoder encoder; @Autowired private MediaRepository medias; e UserService We need access to the repositories we just defined for users, groups and messages
  • 4. @Service public class UserService { @Autowired private UserRepository users; @Autowired private ChatGroupRepository groups; @Autowired private ChatMessageRepository messages; @Autowired private APIKeys keys; @Autowired private PasswordEncoder encoder; @Autowired private MediaRepository medias; e UserService The API keys service is the exact one I used in facebook with the exception of a different properties file name. I’ll discuss that later, it generally abstracts API keys and separates them from the source code
  • 5. @Service public class UserService { @Autowired private UserRepository users; @Autowired private ChatGroupRepository groups; @Autowired private ChatMessageRepository messages; @Autowired private APIKeys keys; @Autowired private PasswordEncoder encoder; @Autowired private MediaRepository medias; e UserService The password encoder is used to encrypt and verify the token
  • 6. private UserRepository users; @Autowired private ChatGroupRepository groups; @Autowired private ChatMessageRepository messages; @Autowired private APIKeys keys; @Autowired private PasswordEncoder encoder; @Autowired private MediaRepository medias; @Autowired private NotificationService notifications; private void sendActivationSMS(String number, String text) { Twilio.init(keys.get("twilio.sid"), keys.get("twilio.auth")); Message message = Message e UserService MediaRepository and NotificationService are identical to the stuff we had in the facebook clone app
  • 7. private PasswordEncoder encoder; @Autowired private MediaRepository medias; @Autowired private NotificationService notifications; private void sendActivationSMS(String number, String text) { Twilio.init(keys.get("twilio.sid"), keys.get("twilio.auth")); Message message = Message .creator(new PhoneNumber(number), new PhoneNumber(keys.get("twilio.phone")), text) .create(); message.getSid(); } public UserDAO login(String phone, String auth) throws LoginException { List<User> userList; userList = users.findByPhone(phone); if (userList != null && userList.size() == 1) { e UserService This method sends an SMS message via the twilio web service. If you recall we added the twilio SDK into the pom file in the first lesson. This SDK makes sending an SMS message very easy as you can see from this code.
  • 8. .creator(new PhoneNumber(number), new PhoneNumber(keys.get("twilio.phone")), text) .create(); message.getSid(); } public UserDAO login(String phone, String auth) throws LoginException { List<User> userList; userList = users.findByPhone(phone); if (userList != null && userList.size() == 1) { User u = userList.get(0); if (encoder.matches(auth, u.getAuthtoken())) { return u.getLoginDAO(); } throw new LoginException("Authentication error!"); } throw new LoginException("User not found!"); } private String createVerificationCode(int length) { StringBuilder k = new StringBuilder(); Random r = new Random(); e UserService The login API lets us validate a user and get the current data the server has for that user. Since there is no username/password we need to use a token to authenticate
  • 9. .creator(new PhoneNumber(number), new PhoneNumber(keys.get("twilio.phone")), text) .create(); message.getSid(); } public UserDAO login(String phone, String auth) throws LoginException { List<User> userList; userList = users.findByPhone(phone); if (userList != null && userList.size() == 1) { User u = userList.get(0); if (encoder.matches(auth, u.getAuthtoken())) { return u.getLoginDAO(); } throw new LoginException("Authentication error!"); } throw new LoginException("User not found!"); } private String createVerificationCode(int length) { StringBuilder k = new StringBuilder(); Random r = new Random(); e UserService First we need to find the user with the given phone. Assuming the user isn’t there we’ll throw an exception
  • 10. .creator(new PhoneNumber(number), new PhoneNumber(keys.get("twilio.phone")), text) .create(); message.getSid(); } public UserDAO login(String phone, String auth) throws LoginException { List<User> userList; userList = users.findByPhone(phone); if (userList != null && userList.size() == 1) { User u = userList.get(0); if (encoder.matches(auth, u.getAuthtoken())) { return u.getLoginDAO(); } throw new LoginException("Authentication error!"); } throw new LoginException("User not found!"); } private String createVerificationCode(int length) { StringBuilder k = new StringBuilder(); Random r = new Random(); e UserService Since the auth is hashed as we discussed before, we need to test the incoming auth via the matches method in the encoder. It verifies the hash matches the auth token
  • 11. if (encoder.matches(auth, u.getAuthtoken())) { return u.getLoginDAO(); } throw new LoginException("Authentication error!"); } throw new LoginException("User not found!"); } private String createVerificationCode(int length) { StringBuilder k = new StringBuilder(); Random r = new Random(); for (int iter = 0; iter < length; iter++) { k.append(r.nextInt(10)); } return k.toString(); } public UserDAO signup(UserDAO user) throws SignupException { List<User> ul = users.findByPhone(user.getPhone()); if (ul != null && ul.size() > 0) { throw new SignupException( "The phone number is already registered!"); e UserService This method creates a string of the given length which includes a random number for verification
  • 12. return k.toString(); } public UserDAO signup(UserDAO user) throws SignupException { List<User> ul = users.findByPhone(user.getPhone()); if (ul != null && ul.size() > 0) { throw new SignupException( "The phone number is already registered!"); } User u = new User(); setProps(user, u); u.setAuthtoken(UUID.randomUUID().toString()); u.setVerificationCode(createVerificationCode(4)); users.save(u); sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } e UserService Signup creates an entry for a specific user but does’t activate the account until it’s verified
  • 13. return k.toString(); } public UserDAO signup(UserDAO user) throws SignupException { List<User> ul = users.findByPhone(user.getPhone()); if (ul != null && ul.size() > 0) { throw new SignupException( "The phone number is already registered!"); } User u = new User(); setProps(user, u); u.setAuthtoken(UUID.randomUUID().toString()); u.setVerificationCode(createVerificationCode(4)); users.save(u); sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } e UserService We first check if the phone number is already registered. If so we need to fail
  • 14. return k.toString(); } public UserDAO signup(UserDAO user) throws SignupException { List<User> ul = users.findByPhone(user.getPhone()); if (ul != null && ul.size() > 0) { throw new SignupException( "The phone number is already registered!"); } User u = new User(); setProps(user, u); u.setAuthtoken(UUID.randomUUID().toString()); u.setVerificationCode(createVerificationCode(4)); users.save(u); sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } e UserService Otherwise we create the new user and initialize the value of the data and the verification code
  • 15. return k.toString(); } public UserDAO signup(UserDAO user) throws SignupException { List<User> ul = users.findByPhone(user.getPhone()); if (ul != null && ul.size() > 0) { throw new SignupException( "The phone number is already registered!"); } User u = new User(); setProps(user, u); u.setAuthtoken(UUID.randomUUID().toString()); u.setVerificationCode(createVerificationCode(4)); users.save(u); sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } e UserService Finally we send the activation code and return the user entity
  • 16. sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } public boolean verifyPhone(String userId, String code) { User u = users.findById(userId).get(); if (u.getVerificationCode().equals(code)) { u.setVerificationCode(null); u.setVerified(true); users.save(u); return true; } return false; } private void setProps(UserDAO user, User u) { u.setName(user.getName()); u.setTagline(user.getTagline()); } public void update(String auth, UserDAO user) { e UserService The verify method activates a user account, if the verification code is correct we mark the user as verified and return true.
  • 17. sendActivationSMS(user.getPhone(), "Activation key: " + u. getVerificationCode()); return u.getLoginDAO(); } public boolean verifyPhone(String userId, String code) { User u = users.findById(userId).get(); if (u.getVerificationCode().equals(code)) { u.setVerificationCode(null); u.setVerified(true); users.save(u); return true; } return false; } private void setProps(UserDAO user, User u) { u.setName(user.getName()); u.setTagline(user.getTagline()); } public void update(String auth, UserDAO user) { e UserService We use setProps both from the signup and update methods. There isn’t much here but if we add additional meta-data this might become a bigger method like it is in the facebook clone
  • 18. } private void setProps(UserDAO user, User u) { u.setName(user.getName()); u.setTagline(user.getTagline()); } public void update(String auth, UserDAO user) { User u = users.findById(user.getId()).get(); if (encoder.matches(auth, u.getAuthtoken())) { setProps(user, u); users.save(u); } } public byte[] getAvatar(String userId) { User u = users.findById(userId).get(); if (u.getAvatar() != null) { return u.getAvatar().getData(); } return null; } public void setAvatar(String auth, String userId, String mediaId) { e UserService Update verifies the users token then updates the properties. There isn’t much here
  • 19. setProps(user, u); users.save(u); } } public byte[] getAvatar(String userId) { User u = users.findById(userId).get(); if (u.getAvatar() != null) { return u.getAvatar().getData(); } return null; } public void setAvatar(String auth, String userId, String mediaId) { Media m = medias.findById(mediaId).get(); User u = users.findById(userId).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setAvatar(m); users.save(u); } } public void userTyping(String userId, String toUser, boolean t) { Optional<User> to = users.findById(toUser); e UserService These aren’t used at the moment but they are pretty much identical to what we have in the facebook clone and should be easy to integrate in a similar way
  • 20. User u = users.findById(userId).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setAvatar(m); users.save(u); } } public void userTyping(String userId, String toUser, boolean t) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t); } else { ChatGroup g = groups.findById(toUser).get(); for(User u : g.getMembers()) { AppSocket.sendUserTyping(u.getAuthtoken(), userId, t); } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); e UserService This is part of the work to integrate support for the “user typing" feature. Right now the client app doesn’t send or render this event but it should be relatively simple to add. When a user starts typing to a conversation we can invoke this method
  • 21. User u = users.findById(userId).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setAvatar(m); users.save(u); } } public void userTyping(String userId, String toUser, boolean t) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t); } else { ChatGroup g = groups.findById(toUser).get(); for(User u : g.getMembers()) { AppSocket.sendUserTyping(u.getAuthtoken(), userId, t); } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); e UserService toUser can be a user or a group is the user is present it’s a user
  • 22. User u = users.findById(userId).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setAvatar(m); users.save(u); } } public void userTyping(String userId, String toUser, boolean t) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t); } else { ChatGroup g = groups.findById(toUser).get(); for(User u : g.getMembers()) { AppSocket.sendUserTyping(u.getAuthtoken(), userId, t); } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); e UserService I’ll discuss the event code in the sockets when we reach the app socket class
  • 23. User u = users.findById(userId).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setAvatar(m); users.save(u); } } public void userTyping(String userId, String toUser, boolean t) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendUserTyping(to.get().getAuthtoken(), userId, t); } else { ChatGroup g = groups.findById(toUser).get(); for(User u : g.getMembers()) { AppSocket.sendUserTyping(u.getAuthtoken(), userId, t); } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); e UserService If this is a group we need to send the event to all the users within the group via the socket connection
  • 24. } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); e UserService This method sends a message to its destination which can be a user or a group.
  • 25. } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); e UserService In order to send a message we first need to create a ChatMessage entity so we can persist the message in case delivery failed.
  • 26. } } } public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); e UserService This is the same code we saw in the typing event. If the message is destined to a user the following block will occur
  • 27. public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); } } return cm.getDAO(); } e UserService Otherwise we’ll go to the else block where the exact same code will execute in a loop over all the members of the group
  • 28. public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); } } return cm.getDAO(); } e UserService We mark the destination of the message and convert it to a JSON string
  • 29. public MessageDAO sendMessage(MessageDAO m) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById(m.getAuthorId()).get()); cm.setBody(m.getBody()); cm.setMessageTime(new Date()); Optional<User> to = users.findById(m.getSentTo()); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(m.getSentTo(), cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, m.getBody()); } else { ChatGroup g = groups.findById(m.getSentTo()).get(); cm.setSentToGroup(g); String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); } } return cm.getDAO(); } e UserService We the invoke the send message API
  • 30. String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); } } return cm.getDAO(); } private void sendMessageImpl(String authToken, String pushKey, String json, String message) { if(!AppSocket.sendMessage(authToken, json)) { notifications.sendPushNotification(pushKey, message, 1); } } public void sendMessage(String toUser, Map<String, Object> parsedJSON) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById((String)parsedJSON.get("authorId")). get()); cm.setBody((String)parsedJSON.get("body")); cm.setMessageTime(new Date()); Optional<User> to = users.findById(toUser); e UserService Send message uses the socket to send the message to the device.
  • 31. String json = createMessageImpl(m.getSentTo(), cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, m.getBody()); } } return cm.getDAO(); } private void sendMessageImpl(String authToken, String pushKey, String json, String message) { if(!AppSocket.sendMessage(authToken, json)) { notifications.sendPushNotification(pushKey, message, 1); } } public void sendMessage(String toUser, Map<String, Object> parsedJSON) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById((String)parsedJSON.get("authorId")). get()); cm.setBody((String)parsedJSON.get("body")); cm.setMessageTime(new Date()); Optional<User> to = users.findById(toUser); e UserService If this failed and the device isn't reachable we should send this message as text using push notification
  • 32. notifications.sendPushNotification(pushKey, message, 1); } } public void sendMessage(String toUser, Map<String, Object> parsedJSON) { ChatMessage cm = new ChatMessage(); cm.setAuthor(users.findById((String)parsedJSON.get("authorId")). get()); cm.setBody((String)parsedJSON.get("body")); cm.setMessageTime(new Date()); Optional<User> to = users.findById(toUser); if(to.isPresent()) { cm.setSentTo(to.get()); String json = createMessageImpl(toUser, cm); User usr = to.get(); sendMessageImpl(usr.getAuthtoken(), usr.getPushKey(), json, cm.getBody()); } else { ChatGroup g = groups.findById(toUser).get(); cm.setSentToGroup(g); String json = createMessageImpl(toUser, cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), e UserService This method is identical to the other sendMessage method but it uses a JSON string which is more convenient when a message comes in through the websocket. The previous version is the one used when this is invoked from the webservice (which is what we use) and this one works when a message is sent via the websocket
  • 33. String json = createMessageImpl(toUser, cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, cm.getBody()); } } } private String createMessageImpl(String toUser, ChatMessage cm) { cm = messages.save(cm); ObjectMapper objectMapper = new ObjectMapper(); try { String dao = objectMapper.writeValueAsString(cm.getDAO()); return dao; } catch(JsonProcessingException err) { throw new RuntimeException(err); } } public void sendJSONTo(String toUser, String json) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendMessage(to.get().getAuthtoken(), json); e UserService This method converts a chat message entity to JSON so we can send it to the client.
  • 34. String json = createMessageImpl(toUser, cm); for(User u : g.getMembers()) { sendMessageImpl(u.getAuthtoken(), u.getPushKey(), json, cm.getBody()); } } } private String createMessageImpl(String toUser, ChatMessage cm) { cm = messages.save(cm); ObjectMapper objectMapper = new ObjectMapper(); try { String dao = objectMapper.writeValueAsString(cm.getDAO()); return dao; } catch(JsonProcessingException err) { throw new RuntimeException(err); } } public void sendJSONTo(String toUser, String json) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendMessage(to.get().getAuthtoken(), json); e UserService object mapper can convert a POJO object to the equivalent JSON string
  • 35. String dao = objectMapper.writeValueAsString(cm.getDAO()); return dao; } catch(JsonProcessingException err) { throw new RuntimeException(err); } } public void sendJSONTo(String toUser, String json) { Optional<User> to = users.findById(toUser); if(to.isPresent()) { AppSocket.sendMessage(to.get().getAuthtoken(), json); } else { ChatGroup g = groups.findById(toUser).get(); for(User u : g.getMembers()) { AppSocket.sendMessage(u.getAuthtoken(), json); } } } public UserDAO findRegisteredUser(String phone) { return fromList(users.findByPhone(phone)); } e UserService This method sends JSON via the socket to the group or a user. It allows us to propagate a message onward. It works pretty much like the other methods in this class that send to group or user
  • 36. for(User u : g.getMembers()) { AppSocket.sendMessage(u.getAuthtoken(), json); } } } public UserDAO findRegisteredUser(String phone) { return fromList(users.findByPhone(phone)); } private UserDAO fromList(List<User> ul) { if(ul.isEmpty()) { return null; } User u = ul.get(0); if(!u.isVerified()) { return null; } return u.getDAO(); } public UserDAO findRegisteredUserById(String id) { return users.findById(id).get().getDAO(); } e UserService This method finds the user matching the given phone number
  • 37. for(User u : g.getMembers()) { AppSocket.sendMessage(u.getAuthtoken(), json); } } } public UserDAO findRegisteredUser(String phone) { return fromList(users.findByPhone(phone)); } private UserDAO fromList(List<User> ul) { if(ul.isEmpty()) { return null; } User u = ul.get(0); if(!u.isVerified()) { return null; } return u.getDAO(); } public UserDAO findRegisteredUserById(String id) { return users.findById(id).get().getDAO(); } e UserService This method is used by findRegisteredUser and findRegisteredUserById. It generalizes the translation of a user list to a single UserDAO value. It implicitly fails for unverified users as well
  • 38. public UserDAO findRegisteredUserById(String id) { return users.findById(id).get().getDAO(); } public void ackMessage(String id) { ChatMessage m = messages.findById(id).get(); m.setAck(true); messages.save(m); } public void sendUnAckedMessages(String toUser) { List<ChatMessage> mess = messages.findByUnAcked(toUser); for(ChatMessage m : mess) { sendMessage(m.getDAO()); } } public void updatePushKey(String auth, String id, String key) { User u = users.findById(auth).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setPushKey(key); users.save(u); } e UserService Ack allows us to acknowledge that a message was received, it just toggles the ack flag.
  • 39. public UserDAO findRegisteredUserById(String id) { return users.findById(id).get().getDAO(); } public void ackMessage(String id) { ChatMessage m = messages.findById(id).get(); m.setAck(true); messages.save(m); } public void sendUnAckedMessages(String toUser) { List<ChatMessage> mess = messages.findByUnAcked(toUser); for(ChatMessage m : mess) { sendMessage(m.getDAO()); } } public void updatePushKey(String auth, String id, String key) { User u = users.findById(auth).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setPushKey(key); users.save(u); } e UserService When a user connects via websocket this method is invoked, it finds all the messages that weren't acked by the user and sends them to that user. That way if a device lost connection it will get the content once it’s back online.
  • 40. public void ackMessage(String id) { ChatMessage m = messages.findById(id).get(); m.setAck(true); messages.save(m); } public void sendUnAckedMessages(String toUser) { List<ChatMessage> mess = messages.findByUnAcked(toUser); for(ChatMessage m : mess) { sendMessage(m.getDAO()); } } public void updatePushKey(String auth, String id, String key) { User u = users.findById(auth).get(); if (encoder.matches(auth, u.getAuthtoken())) { u.setPushKey(key); users.save(u); } } } e UserService This method is invoked on launch to update the push key in the server so we can send push messages to the device. With that UserService is finished