SlideShare a Scribd company logo
Creating an Uber Clone - Part XXVI
Before we proceed into the actual driver app work & push notification we need to implement all the infrastructure in the server side. I also need to implement some
changes we need in the protocol.
private String hailingFrom;
private String hailingTo;
private String pushToken;
public RideDAO getRideDao() {
return new RideDAO(id, givenName, hailingFrom, hailingTo);
}
public UserDAO getDao() {
return new UserDAO(id, givenName, surname, phone, email,
facebookId, googleId, driver, car, currentRating,
latitude, longitude, direction, pushToken);
}
public UserDAO getPartialDao() {
return new UserDAO(id, givenName, surname, null, null,
null, null, driver, car, currentRating, latitude,
longitude, direction, pushToken);
}
User (Server)
Lets start by looking at the User class. I had to add 3 new fields and modify/add some methods.

hailingFrom & hailingTo allow us to communicate our trip details with the driver community
private String hailingFrom;
private String hailingTo;
private String pushToken;
public RideDAO getRideDao() {
return new RideDAO(id, givenName, hailingFrom, hailingTo);
}
public UserDAO getDao() {
return new UserDAO(id, givenName, surname, phone, email,
facebookId, googleId, driver, car, currentRating,
latitude, longitude, direction, pushToken);
}
public UserDAO getPartialDao() {
return new UserDAO(id, givenName, surname, null, null,
null, null, driver, car, currentRating, latitude,
longitude, direction, pushToken);
}
User (Server)
I need the pushToken of drivers so we can hail them directly from the app
private String hailingFrom;
private String hailingTo;
private String pushToken;
public RideDAO getRideDao() {
return new RideDAO(id, givenName, hailingFrom, hailingTo);
}
public UserDAO getDao() {
return new UserDAO(id, givenName, surname, phone, email,
facebookId, googleId, driver, car, currentRating,
latitude, longitude, direction, pushToken);
}
public UserDAO getPartialDao() {
return new UserDAO(id, givenName, surname, null, null,
null, null, driver, car, currentRating, latitude,
longitude, direction, pushToken);
}
User (Server)
I'll discuss the `RideDAO` class soon, it allows us to send details about the trip to drivers
private String hailingFrom;
private String hailingTo;
private String pushToken;
public RideDAO getRideDao() {
return new RideDAO(id, givenName, hailingFrom, hailingTo);
}
public UserDAO getDao() {
return new UserDAO(id, givenName, surname, phone, email,
facebookId, googleId, driver, car, currentRating,
latitude, longitude, direction, pushToken);
}
public UserDAO getPartialDao() {
return new UserDAO(id, givenName, surname, null, null,
null, null, driver, car, currentRating, latitude,
longitude, direction, pushToken);
}
User (Server)
Not much of a change but I added the pushToken to the UserDAO factory methods
public class RideDAO implements Serializable {
private long userId;
private String name;
private String from;
private String destination;
public RideDAO() {
}
public RideDAO(long userId, String name, String from, String destination) {
this.userId = userId;
this.name = name;
if(this.name == null) {
this.name = "[Unnamed User]";
}
this.from = from;
this.destination = destination;
}
// getters and setters trimmed out
}
RideDAO
The RideDAO class is a pretty trivial object. There's no point in enumerating the details of this class as it's pretty simple. The main usage for this is in the new RideService
which I will get to soon but first we need to discuss the Ride class.
@Entity
public class Ride {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User passenger;
@ManyToOne
private User driver;
@OneToMany
@OrderBy("time ASC")
private Set<Waypoint> route;
private BigDecimal cost;
private String currency;
private boolean finished;
private boolean started;
// trimmed out constructors, getters and setters
}
Ride
Ride isn't as simple as RideDAO despite their common name. It contains far more information. Currently we don't use all of that but the fact that it's logged will let you
provide all of that information within the app or a management app easily.

The Ride class is a JPA entity similar to the User class.

I used an auto-increment value for the id instead of a random string. I wanted to keep things simple but notice this can expose a security vulnerability of scanning for
rides…
@Entity
public class Ride {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User passenger;
@ManyToOne
private User driver;
@OneToMany
@OrderBy("time ASC")
private Set<Waypoint> route;
private BigDecimal cost;
private String currency;
private boolean finished;
private boolean started;
// trimmed out constructors, getters and setters
}
Ride
The passenger & driver are relational database references to the respective database objects representing each one of them
@Entity
public class Ride {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User passenger;
@ManyToOne
private User driver;
@OneToMany
@OrderBy("time ASC")
private Set<Waypoint> route;
private BigDecimal cost;
private String currency;
private boolean finished;
private boolean started;
// trimmed out constructors, getters and setters
}
Ride
The route itself is a set of waypoints sorted by the time associated with the given waypoint. We'll discuss waypoints soon enough but technically it's just a set of
coordinates
@Entity
public class Ride {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User passenger;
@ManyToOne
private User driver;
@OneToMany
@OrderBy("time ASC")
private Set<Waypoint> route;
private BigDecimal cost;
private String currency;
private boolean finished;
private boolean started;
// trimmed out constructors, getters and setters
}
Ride
I really oversimplified the cost field. It should work for sum and currency but it's usually not as simple as that. It's important to use something like BigDecimal and not
double when dealing with financial numbers as double is built for scientific usage and has rounding errors
@Entity
public class Ride {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User passenger;
@ManyToOne
private User driver;
@OneToMany
@OrderBy("time ASC")
private Set<Waypoint> route;
private BigDecimal cost;
private String currency;
private boolean finished;
private boolean started;
// trimmed out constructors, getters and setters
}
Ride
We have two boolean flags, a ride is started once a passenger is picked up. It’s finished once he is dropped off or if the ride was canceled
public interface RideRepository extends CrudRepository<Ride, Long> {
@Query("select b from Ride b where b.finished = false and b.driver.id = ?1")
public List<Ride> findByNotFinishedUser(long id);
}
RideRepository
The companion CRUD RideRepository is pretty standard with one big exception. I added a special case finder that lets us locate the User that is currently hailing a car.
Notice the syntax b.driver.id = ?1 which points through the relation to the driver object.
@Entity
public class Waypoint {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private long time;
private double latitude;
private double longitude;
private float direction;
// trimmed out constructors, getters and setters
}
Waypoint
The Waypoint entity referenced from the Ride entity is pretty trivial. Notice we still need a unique id for a waypoint even if we don't actually use it in code...

The interesting part here is the time value which is the value of System.currentTimeMillis(). This allows us to build a path based on the time sequence. It will also allow us
to reconstruct a trip and generate additional details such as speed/cost if we wish to do that in the future.

Notice that there is also a WaypointRepository interface. I’m skipping it as it contains no actual code
@Service
public class RideService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Transactional
public UserDAO hailCar(String token, boolean h, String from, String to) {
User u = users.findByAuthToken(token).get(0);
if(h) {
if(u.getAssignedUser() != null) {
long driverId = u.getAssignedUser();
u.setAssignedUser(null);
users.save(u);
User driver = users.findOne(driverId);
return driver.getPartialDao();
}
} else {
u.setAssignedUser(null);
}
u.setHailing(h);
u.setHailingFrom(from);
u.setHailingTo(to);
users.save(u);
return null;
}
RideService
The RideService class serves the same purpose as the UserService class focusing on rides and driver related features. I could have just stuck all of this logic into one
huge class but separating functionality to different service classes based on logic makes sense.

We manipulate both the rides and users CRUD objects from this class
@Service
public class RideService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Transactional
public UserDAO hailCar(String token, boolean h, String from, String to) {
User u = users.findByAuthToken(token).get(0);
if(h) {
if(u.getAssignedUser() != null) {
long driverId = u.getAssignedUser();
u.setAssignedUser(null);
users.save(u);
User driver = users.findOne(driverId);
return driver.getPartialDao();
}
} else {
u.setAssignedUser(null);
}
u.setHailing(h);
u.setHailingFrom(from);
u.setHailingTo(to);
users.save(u);
return null;
}
RideService
Hailing is a transactional method, this means that all operations within the method will either succeed or fail depending on the outcome. This is important to prevent an
inconsistent state in the database
@Service
public class RideService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Transactional
public UserDAO hailCar(String token, boolean h, String from, String to) {
User u = users.findByAuthToken(token).get(0);
if(h) {
if(u.getAssignedUser() != null) {
long driverId = u.getAssignedUser();
u.setAssignedUser(null);
users.save(u);
User driver = users.findOne(driverId);
return driver.getPartialDao();
}
} else {
u.setAssignedUser(null);
}
u.setHailing(h);
u.setHailingFrom(from);
u.setHailingTo(to);
users.save(u);
return null;
}
RideService
This method can be invoked to start and stop hailing. In this case we use the assigned user property to detect if a driver accepted the ride. If so we return the driver data
to the client
users.save(u);
return null;
}
public RideDAO getRideData(long userId) {
User u = users.findOne(userId);
if(u == null) {
return null;
}
return u.getRideDao();
}
@Transactional
public long acceptRide(String token, long userId) {
User driver = users.findByAuthToken(token).get(0);
User passenger = users.findOne(userId);
if(!passenger.isHailing()) {
throw new RuntimeException("Not hailing");
}
passenger.setHailing(false);
passenger.setAssignedUser(driver.getId());
driver.setAssignedUser(userId);
users.save(driver);
users.save(passenger);
Ride r = new Ride();
r.setDriver(driver);
r.setPassenger(passenger);
rides.save(r);
RideService
When a driver gets a notification of a ride he invokes this method to get back the data about the ride
users.save(u);
return null;
}
public RideDAO getRideData(long userId) {
User u = users.findOne(userId);
if(u == null) {
return null;
}
return u.getRideDao();
}
@Transactional
public long acceptRide(String token, long userId) {
User driver = users.findByAuthToken(token).get(0);
User passenger = users.findOne(userId);
if(!passenger.isHailing()) {
throw new RuntimeException("Not hailing");
}
passenger.setHailing(false);
passenger.setAssignedUser(driver.getId());
driver.setAssignedUser(userId);
users.save(driver);
users.save(passenger);
Ride r = new Ride();
r.setDriver(driver);
r.setPassenger(passenger);
rides.save(r);
RideService
If the driver wishes to accept the ride he invokes this transactional method. The method accepts the token from the driver and the id of the user hailing the ride. It creates
a new Ride entity and returns its ID, from this point on we need to refer to the Ride id and not the user id or token
User driver = users.findByAuthToken(token).get(0);
User passenger = users.findOne(userId);
if(!passenger.isHailing()) {
throw new RuntimeException("Not hailing");
}
passenger.setHailing(false);
passenger.setAssignedUser(driver.getId());
driver.setAssignedUser(userId);
users.save(driver);
users.save(passenger);
Ride r = new Ride();
r.setDriver(driver);
r.setPassenger(passenger);
rides.save(r);
return r.getId();
}
public void startRide(long rideId) {
Ride current = rides.findOne(rideId);
current.setStarted(true);
rides.save(current);
}
public void finishRide(long rideId) {
Ride current = rides.findOne(rideId);
current.setFinished(true);
rides.save(current);
}
}
RideService
Start ride and finish ride are invoked by the driver when he picks up the passenger and when he drops him off. Normally, finish ride should also handle elements like
billing etc. but I won't go into that now
@Controller
@RequestMapping("/ride")
public class RideWebservice {
@Autowired
private RideService rides;
@RequestMapping(method=RequestMethod.GET,value = "/get")
public @ResponseBody RideDAO getRideData(long id) {
return rides.getRideData(id);
}
@RequestMapping(method=RequestMethod.GET,value="/accept")
public @ResponseBody String acceptRide(@RequestParam(name="token", required = true) String token,
@RequestParam(name="userId", required = true) long userId) {
long val = rides.acceptRide(token, userId);
return "" + val;
}
@RequestMapping(method=RequestMethod.POST,value="/start")
public @ResponseBody String startRide(@RequestParam(name="id", required = true) long rideId) {
rides.startRide(rideId);
return "OK";
}
@RequestMapping(method=RequestMethod.POST,value="/finish")
public @ResponseBody String finishRide(@RequestParam(name="id", required = true) long rideId) {
rides.finishRide(rideId);
return "OK";
}
}
RideWebservice
The next step is bridging this to the user through a webservice...

The RideWebservice class exposes the RideService calls almost verbatim to the client.

The get call fetches the RideDAO for the given user id
@Controller
@RequestMapping("/ride")
public class RideWebservice {
@Autowired
private RideService rides;
@RequestMapping(method=RequestMethod.GET,value = "/get")
public @ResponseBody RideDAO getRideData(long id) {
return rides.getRideData(id);
}
@RequestMapping(method=RequestMethod.GET,value="/accept")
public @ResponseBody String acceptRide(@RequestParam(name="token", required = true) String token,
@RequestParam(name="userId", required = true) long userId) {
long val = rides.acceptRide(token, userId);
return "" + val;
}
@RequestMapping(method=RequestMethod.POST,value="/start")
public @ResponseBody String startRide(@RequestParam(name="id", required = true) long rideId) {
rides.startRide(rideId);
return "OK";
}
@RequestMapping(method=RequestMethod.POST,value="/finish")
public @ResponseBody String finishRide(@RequestParam(name="id", required = true) long rideId) {
rides.finishRide(rideId);
return "OK";
}
}
RideWebservice
Start and finish rides are again very simple with only one argument which is the ride id
public void updatePushToken(String token, String pushToken) {
User u = users.findByAuthToken(token).get(0);
u.setPushToken(pushToken);
users.save(u);
}
UserService
We also have to add some minor changes to the UserService and LocationService classes. Lets start with the UserService class. Drivers need a push token so we can
hail them. This is always set outside of the user creation code for two reasons. 

The first time around the user is created but the push key isn't there yet (it arrives asynchronously)

Push is re-registered in every launch and refreshed, there is no reason to update the entire object for that
@RequestMapping(method = RequestMethod.GET,value = "/setPushToken")
public @ResponseBody String updatePushToken(
@RequestParam(name="token", required = true) String token,
@RequestParam(name="pushToken", required = true) String
pushToken) {
users.updatePushToken(token, pushToken);
return "OK";
}
UserWebservice
The UserWebservice class needs to mirror these changes obviously...

There isn't much here we just added a new setPushToken URL and we accept this update.
public class LocationService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Autowired
private WaypointRepository waypoints;
public void updateUserLocation(String token,double lat,double lon,float dir) {
List<User> us = users.findByAuthToken(token);
User u = us.get(0);
u.setLatitude(lat);
u.setLongitude(lat);
u.setDirection(dir);
users.save(u);
if(u.isDriver() && u.getAssignedUser() != null) {
List<Ride> r = rides.findByNotFinishedUser(u.getId());
if(r != null && !r.isEmpty()) {
Ride ride = r.get(0);
if(ride.isStarted() && !ride.isFinished()) {
Set<Waypoint> route = ride.getRoute();
Waypoint newPosition = new Waypoint(
System.currentTimeMillis(), lat, lon, dir);
waypoints.save(newPosition);
route.add(newPosition);
ride.setRoute(route);
rides.save(ride);
LocationService
The LocationService needs a bit more work.

Every time we update a users location we check if he's a driver on a ride
public class LocationService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Autowired
private WaypointRepository waypoints;
public void updateUserLocation(String token,double lat,double lon,float dir) {
List<User> us = users.findByAuthToken(token);
User u = us.get(0);
u.setLatitude(lat);
u.setLongitude(lat);
u.setDirection(dir);
users.save(u);
if(u.isDriver() && u.getAssignedUser() != null) {
List<Ride> r = rides.findByNotFinishedUser(u.getId());
if(r != null && !r.isEmpty()) {
Ride ride = r.get(0);
if(ride.isStarted() && !ride.isFinished()) {
Set<Waypoint> route = ride.getRoute();
Waypoint newPosition = new Waypoint(
System.currentTimeMillis(), lat, lon, dir);
waypoints.save(newPosition);
route.add(newPosition);
ride.setRoute(route);
rides.save(ride);
LocationService
Assuming we have a Ride object we check if this is currently an ongoing ride that wasn't finished
public class LocationService {
@Autowired
private UserRepository users;
@Autowired
private RideRepository rides;
@Autowired
private WaypointRepository waypoints;
public void updateUserLocation(String token,double lat,double lon,float dir) {
List<User> us = users.findByAuthToken(token);
User u = us.get(0);
u.setLatitude(lat);
u.setLongitude(lat);
u.setDirection(dir);
users.save(u);
if(u.isDriver() && u.getAssignedUser() != null) {
List<Ride> r = rides.findByNotFinishedUser(u.getId());
if(r != null && !r.isEmpty()) {
Ride ride = r.get(0);
if(ride.isStarted() && !ride.isFinished()) {
Set<Waypoint> route = ride.getRoute();
Waypoint newPosition = new Waypoint(
System.currentTimeMillis(), lat, lon, dir);
waypoints.save(newPosition);
route.add(newPosition);
ride.setRoute(route);
rides.save(ride);
LocationService
If so we add a waypoint to the ride and update it so we can later on inspect the path of the Ride. 

This pretty much tracks rides seamlessly. If we wanted to be really smart we could detect the driver and user position to detect them traveling together and automatically
handle the ride. There are obviously problems with this as it means a user can't order a cab for someone else but it might be an interesting feature since we have two
close data points…

More Related Content

Similar to Creating an Uber Clone - Part XXVI - Transcript.pdf

Creating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdfCreating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdf
ShaiAlmog1
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverSpike Brehm
 
Js in Automotive - JS.everywhere(2013)
Js in Automotive - JS.everywhere(2013)Js in Automotive - JS.everywhere(2013)
Js in Automotive - JS.everywhere(2013)Alexandre Morgaut
 
Creating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdfCreating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part XXXI - Transcript.pdf
Creating an Uber Clone - Part XXXI - Transcript.pdfCreating an Uber Clone - Part XXXI - Transcript.pdf
Creating an Uber Clone - Part XXXI - Transcript.pdf
ShaiAlmog1
 
Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics
Eliran Eliassy
 
Angular directive filter and routing
Angular directive filter and routingAngular directive filter and routing
Angular directive filter and routing
jagriti srivastava
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
For the following questions, you will implement the data structure to.pdf
For the following questions, you will implement the data structure to.pdfFor the following questions, you will implement the data structure to.pdf
For the following questions, you will implement the data structure to.pdf
arjunhassan8
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
Gregor Woiwode
 
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Angular routing
Angular routingAngular routing
Angular routing
Sultan Ahmed
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing options
Nir Kaufman
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
OdessaJS Conf
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
Richard Dingwall
 
Creating an Uber Clone - Part XXVII - Transcript.pdf
Creating an Uber Clone - Part XXVII - Transcript.pdfCreating an Uber Clone - Part XXVII - Transcript.pdf
Creating an Uber Clone - Part XXVII - Transcript.pdf
ShaiAlmog1
 
Clean Architecture @ Taxibeat
Clean Architecture @ TaxibeatClean Architecture @ Taxibeat
Clean Architecture @ Taxibeat
Michael Bakogiannis
 
Sahana introduction to the code v2
Sahana   introduction to the code v2Sahana   introduction to the code v2
Sahana introduction to the code v2AidIQ
 

Similar to Creating an Uber Clone - Part XXVI - Transcript.pdf (20)

Creating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdfCreating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdf
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and server
 
Js in Automotive - JS.everywhere(2013)
Js in Automotive - JS.everywhere(2013)Js in Automotive - JS.everywhere(2013)
Js in Automotive - JS.everywhere(2013)
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 
Creating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdfCreating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdf
 
Creating an Uber Clone - Part XXXI - Transcript.pdf
Creating an Uber Clone - Part XXXI - Transcript.pdfCreating an Uber Clone - Part XXXI - Transcript.pdf
Creating an Uber Clone - Part XXXI - Transcript.pdf
 
Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics
 
TripThru_API_Doc_v1
TripThru_API_Doc_v1TripThru_API_Doc_v1
TripThru_API_Doc_v1
 
Angular directive filter and routing
Angular directive filter and routingAngular directive filter and routing
Angular directive filter and routing
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
For the following questions, you will implement the data structure to.pdf
For the following questions, you will implement the data structure to.pdfFor the following questions, you will implement the data structure to.pdf
For the following questions, you will implement the data structure to.pdf
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
 
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
 
Angular routing
Angular routingAngular routing
Angular routing
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing options
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
Creating an Uber Clone - Part XXVII - Transcript.pdf
Creating an Uber Clone - Part XXVII - Transcript.pdfCreating an Uber Clone - Part XXVII - Transcript.pdf
Creating an Uber Clone - Part XXVII - Transcript.pdf
 
Clean Architecture @ Taxibeat
Clean Architecture @ TaxibeatClean Architecture @ Taxibeat
Clean Architecture @ Taxibeat
 
Sahana introduction to the code v2
Sahana   introduction to the code v2Sahana   introduction to the code v2
Sahana introduction to the code v2
 

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.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 

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

Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
Bhaskar Mitra
 
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
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
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
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
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.pdf
FIDO Alliance
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
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
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
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
Guy Korland
 
"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
Fwdays
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
Abida Shariff
 
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
Elena Simperl
 
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
 

Recently uploaded (20)

Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
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...
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
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...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
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
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
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 ...
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
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
 
"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
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
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
 
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...
 

Creating an Uber Clone - Part XXVI - Transcript.pdf

  • 1. Creating an Uber Clone - Part XXVI Before we proceed into the actual driver app work & push notification we need to implement all the infrastructure in the server side. I also need to implement some changes we need in the protocol.
  • 2. private String hailingFrom; private String hailingTo; private String pushToken; public RideDAO getRideDao() { return new RideDAO(id, givenName, hailingFrom, hailingTo); } public UserDAO getDao() { return new UserDAO(id, givenName, surname, phone, email, facebookId, googleId, driver, car, currentRating, latitude, longitude, direction, pushToken); } public UserDAO getPartialDao() { return new UserDAO(id, givenName, surname, null, null, null, null, driver, car, currentRating, latitude, longitude, direction, pushToken); } User (Server) Lets start by looking at the User class. I had to add 3 new fields and modify/add some methods. hailingFrom & hailingTo allow us to communicate our trip details with the driver community
  • 3. private String hailingFrom; private String hailingTo; private String pushToken; public RideDAO getRideDao() { return new RideDAO(id, givenName, hailingFrom, hailingTo); } public UserDAO getDao() { return new UserDAO(id, givenName, surname, phone, email, facebookId, googleId, driver, car, currentRating, latitude, longitude, direction, pushToken); } public UserDAO getPartialDao() { return new UserDAO(id, givenName, surname, null, null, null, null, driver, car, currentRating, latitude, longitude, direction, pushToken); } User (Server) I need the pushToken of drivers so we can hail them directly from the app
  • 4. private String hailingFrom; private String hailingTo; private String pushToken; public RideDAO getRideDao() { return new RideDAO(id, givenName, hailingFrom, hailingTo); } public UserDAO getDao() { return new UserDAO(id, givenName, surname, phone, email, facebookId, googleId, driver, car, currentRating, latitude, longitude, direction, pushToken); } public UserDAO getPartialDao() { return new UserDAO(id, givenName, surname, null, null, null, null, driver, car, currentRating, latitude, longitude, direction, pushToken); } User (Server) I'll discuss the `RideDAO` class soon, it allows us to send details about the trip to drivers
  • 5. private String hailingFrom; private String hailingTo; private String pushToken; public RideDAO getRideDao() { return new RideDAO(id, givenName, hailingFrom, hailingTo); } public UserDAO getDao() { return new UserDAO(id, givenName, surname, phone, email, facebookId, googleId, driver, car, currentRating, latitude, longitude, direction, pushToken); } public UserDAO getPartialDao() { return new UserDAO(id, givenName, surname, null, null, null, null, driver, car, currentRating, latitude, longitude, direction, pushToken); } User (Server) Not much of a change but I added the pushToken to the UserDAO factory methods
  • 6. public class RideDAO implements Serializable { private long userId; private String name; private String from; private String destination; public RideDAO() { } public RideDAO(long userId, String name, String from, String destination) { this.userId = userId; this.name = name; if(this.name == null) { this.name = "[Unnamed User]"; } this.from = from; this.destination = destination; } // getters and setters trimmed out } RideDAO The RideDAO class is a pretty trivial object. There's no point in enumerating the details of this class as it's pretty simple. The main usage for this is in the new RideService which I will get to soon but first we need to discuss the Ride class.
  • 7. @Entity public class Ride { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User passenger; @ManyToOne private User driver; @OneToMany @OrderBy("time ASC") private Set<Waypoint> route; private BigDecimal cost; private String currency; private boolean finished; private boolean started; // trimmed out constructors, getters and setters } Ride Ride isn't as simple as RideDAO despite their common name. It contains far more information. Currently we don't use all of that but the fact that it's logged will let you provide all of that information within the app or a management app easily. The Ride class is a JPA entity similar to the User class. I used an auto-increment value for the id instead of a random string. I wanted to keep things simple but notice this can expose a security vulnerability of scanning for rides…
  • 8. @Entity public class Ride { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User passenger; @ManyToOne private User driver; @OneToMany @OrderBy("time ASC") private Set<Waypoint> route; private BigDecimal cost; private String currency; private boolean finished; private boolean started; // trimmed out constructors, getters and setters } Ride The passenger & driver are relational database references to the respective database objects representing each one of them
  • 9. @Entity public class Ride { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User passenger; @ManyToOne private User driver; @OneToMany @OrderBy("time ASC") private Set<Waypoint> route; private BigDecimal cost; private String currency; private boolean finished; private boolean started; // trimmed out constructors, getters and setters } Ride The route itself is a set of waypoints sorted by the time associated with the given waypoint. We'll discuss waypoints soon enough but technically it's just a set of coordinates
  • 10. @Entity public class Ride { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User passenger; @ManyToOne private User driver; @OneToMany @OrderBy("time ASC") private Set<Waypoint> route; private BigDecimal cost; private String currency; private boolean finished; private boolean started; // trimmed out constructors, getters and setters } Ride I really oversimplified the cost field. It should work for sum and currency but it's usually not as simple as that. It's important to use something like BigDecimal and not double when dealing with financial numbers as double is built for scientific usage and has rounding errors
  • 11. @Entity public class Ride { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User passenger; @ManyToOne private User driver; @OneToMany @OrderBy("time ASC") private Set<Waypoint> route; private BigDecimal cost; private String currency; private boolean finished; private boolean started; // trimmed out constructors, getters and setters } Ride We have two boolean flags, a ride is started once a passenger is picked up. It’s finished once he is dropped off or if the ride was canceled
  • 12. public interface RideRepository extends CrudRepository<Ride, Long> { @Query("select b from Ride b where b.finished = false and b.driver.id = ?1") public List<Ride> findByNotFinishedUser(long id); } RideRepository The companion CRUD RideRepository is pretty standard with one big exception. I added a special case finder that lets us locate the User that is currently hailing a car. Notice the syntax b.driver.id = ?1 which points through the relation to the driver object.
  • 13. @Entity public class Waypoint { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private long time; private double latitude; private double longitude; private float direction; // trimmed out constructors, getters and setters } Waypoint The Waypoint entity referenced from the Ride entity is pretty trivial. Notice we still need a unique id for a waypoint even if we don't actually use it in code... The interesting part here is the time value which is the value of System.currentTimeMillis(). This allows us to build a path based on the time sequence. It will also allow us to reconstruct a trip and generate additional details such as speed/cost if we wish to do that in the future. Notice that there is also a WaypointRepository interface. I’m skipping it as it contains no actual code
  • 14. @Service public class RideService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Transactional public UserDAO hailCar(String token, boolean h, String from, String to) { User u = users.findByAuthToken(token).get(0); if(h) { if(u.getAssignedUser() != null) { long driverId = u.getAssignedUser(); u.setAssignedUser(null); users.save(u); User driver = users.findOne(driverId); return driver.getPartialDao(); } } else { u.setAssignedUser(null); } u.setHailing(h); u.setHailingFrom(from); u.setHailingTo(to); users.save(u); return null; } RideService The RideService class serves the same purpose as the UserService class focusing on rides and driver related features. I could have just stuck all of this logic into one huge class but separating functionality to different service classes based on logic makes sense. We manipulate both the rides and users CRUD objects from this class
  • 15. @Service public class RideService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Transactional public UserDAO hailCar(String token, boolean h, String from, String to) { User u = users.findByAuthToken(token).get(0); if(h) { if(u.getAssignedUser() != null) { long driverId = u.getAssignedUser(); u.setAssignedUser(null); users.save(u); User driver = users.findOne(driverId); return driver.getPartialDao(); } } else { u.setAssignedUser(null); } u.setHailing(h); u.setHailingFrom(from); u.setHailingTo(to); users.save(u); return null; } RideService Hailing is a transactional method, this means that all operations within the method will either succeed or fail depending on the outcome. This is important to prevent an inconsistent state in the database
  • 16. @Service public class RideService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Transactional public UserDAO hailCar(String token, boolean h, String from, String to) { User u = users.findByAuthToken(token).get(0); if(h) { if(u.getAssignedUser() != null) { long driverId = u.getAssignedUser(); u.setAssignedUser(null); users.save(u); User driver = users.findOne(driverId); return driver.getPartialDao(); } } else { u.setAssignedUser(null); } u.setHailing(h); u.setHailingFrom(from); u.setHailingTo(to); users.save(u); return null; } RideService This method can be invoked to start and stop hailing. In this case we use the assigned user property to detect if a driver accepted the ride. If so we return the driver data to the client
  • 17. users.save(u); return null; } public RideDAO getRideData(long userId) { User u = users.findOne(userId); if(u == null) { return null; } return u.getRideDao(); } @Transactional public long acceptRide(String token, long userId) { User driver = users.findByAuthToken(token).get(0); User passenger = users.findOne(userId); if(!passenger.isHailing()) { throw new RuntimeException("Not hailing"); } passenger.setHailing(false); passenger.setAssignedUser(driver.getId()); driver.setAssignedUser(userId); users.save(driver); users.save(passenger); Ride r = new Ride(); r.setDriver(driver); r.setPassenger(passenger); rides.save(r); RideService When a driver gets a notification of a ride he invokes this method to get back the data about the ride
  • 18. users.save(u); return null; } public RideDAO getRideData(long userId) { User u = users.findOne(userId); if(u == null) { return null; } return u.getRideDao(); } @Transactional public long acceptRide(String token, long userId) { User driver = users.findByAuthToken(token).get(0); User passenger = users.findOne(userId); if(!passenger.isHailing()) { throw new RuntimeException("Not hailing"); } passenger.setHailing(false); passenger.setAssignedUser(driver.getId()); driver.setAssignedUser(userId); users.save(driver); users.save(passenger); Ride r = new Ride(); r.setDriver(driver); r.setPassenger(passenger); rides.save(r); RideService If the driver wishes to accept the ride he invokes this transactional method. The method accepts the token from the driver and the id of the user hailing the ride. It creates a new Ride entity and returns its ID, from this point on we need to refer to the Ride id and not the user id or token
  • 19. User driver = users.findByAuthToken(token).get(0); User passenger = users.findOne(userId); if(!passenger.isHailing()) { throw new RuntimeException("Not hailing"); } passenger.setHailing(false); passenger.setAssignedUser(driver.getId()); driver.setAssignedUser(userId); users.save(driver); users.save(passenger); Ride r = new Ride(); r.setDriver(driver); r.setPassenger(passenger); rides.save(r); return r.getId(); } public void startRide(long rideId) { Ride current = rides.findOne(rideId); current.setStarted(true); rides.save(current); } public void finishRide(long rideId) { Ride current = rides.findOne(rideId); current.setFinished(true); rides.save(current); } } RideService Start ride and finish ride are invoked by the driver when he picks up the passenger and when he drops him off. Normally, finish ride should also handle elements like billing etc. but I won't go into that now
  • 20. @Controller @RequestMapping("/ride") public class RideWebservice { @Autowired private RideService rides; @RequestMapping(method=RequestMethod.GET,value = "/get") public @ResponseBody RideDAO getRideData(long id) { return rides.getRideData(id); } @RequestMapping(method=RequestMethod.GET,value="/accept") public @ResponseBody String acceptRide(@RequestParam(name="token", required = true) String token, @RequestParam(name="userId", required = true) long userId) { long val = rides.acceptRide(token, userId); return "" + val; } @RequestMapping(method=RequestMethod.POST,value="/start") public @ResponseBody String startRide(@RequestParam(name="id", required = true) long rideId) { rides.startRide(rideId); return "OK"; } @RequestMapping(method=RequestMethod.POST,value="/finish") public @ResponseBody String finishRide(@RequestParam(name="id", required = true) long rideId) { rides.finishRide(rideId); return "OK"; } } RideWebservice The next step is bridging this to the user through a webservice... The RideWebservice class exposes the RideService calls almost verbatim to the client. The get call fetches the RideDAO for the given user id
  • 21. @Controller @RequestMapping("/ride") public class RideWebservice { @Autowired private RideService rides; @RequestMapping(method=RequestMethod.GET,value = "/get") public @ResponseBody RideDAO getRideData(long id) { return rides.getRideData(id); } @RequestMapping(method=RequestMethod.GET,value="/accept") public @ResponseBody String acceptRide(@RequestParam(name="token", required = true) String token, @RequestParam(name="userId", required = true) long userId) { long val = rides.acceptRide(token, userId); return "" + val; } @RequestMapping(method=RequestMethod.POST,value="/start") public @ResponseBody String startRide(@RequestParam(name="id", required = true) long rideId) { rides.startRide(rideId); return "OK"; } @RequestMapping(method=RequestMethod.POST,value="/finish") public @ResponseBody String finishRide(@RequestParam(name="id", required = true) long rideId) { rides.finishRide(rideId); return "OK"; } } RideWebservice Start and finish rides are again very simple with only one argument which is the ride id
  • 22. public void updatePushToken(String token, String pushToken) { User u = users.findByAuthToken(token).get(0); u.setPushToken(pushToken); users.save(u); } UserService We also have to add some minor changes to the UserService and LocationService classes. Lets start with the UserService class. Drivers need a push token so we can hail them. This is always set outside of the user creation code for two reasons. The first time around the user is created but the push key isn't there yet (it arrives asynchronously) Push is re-registered in every launch and refreshed, there is no reason to update the entire object for that
  • 23. @RequestMapping(method = RequestMethod.GET,value = "/setPushToken") public @ResponseBody String updatePushToken( @RequestParam(name="token", required = true) String token, @RequestParam(name="pushToken", required = true) String pushToken) { users.updatePushToken(token, pushToken); return "OK"; } UserWebservice The UserWebservice class needs to mirror these changes obviously... There isn't much here we just added a new setPushToken URL and we accept this update.
  • 24. public class LocationService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Autowired private WaypointRepository waypoints; public void updateUserLocation(String token,double lat,double lon,float dir) { List<User> us = users.findByAuthToken(token); User u = us.get(0); u.setLatitude(lat); u.setLongitude(lat); u.setDirection(dir); users.save(u); if(u.isDriver() && u.getAssignedUser() != null) { List<Ride> r = rides.findByNotFinishedUser(u.getId()); if(r != null && !r.isEmpty()) { Ride ride = r.get(0); if(ride.isStarted() && !ride.isFinished()) { Set<Waypoint> route = ride.getRoute(); Waypoint newPosition = new Waypoint( System.currentTimeMillis(), lat, lon, dir); waypoints.save(newPosition); route.add(newPosition); ride.setRoute(route); rides.save(ride); LocationService The LocationService needs a bit more work. Every time we update a users location we check if he's a driver on a ride
  • 25. public class LocationService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Autowired private WaypointRepository waypoints; public void updateUserLocation(String token,double lat,double lon,float dir) { List<User> us = users.findByAuthToken(token); User u = us.get(0); u.setLatitude(lat); u.setLongitude(lat); u.setDirection(dir); users.save(u); if(u.isDriver() && u.getAssignedUser() != null) { List<Ride> r = rides.findByNotFinishedUser(u.getId()); if(r != null && !r.isEmpty()) { Ride ride = r.get(0); if(ride.isStarted() && !ride.isFinished()) { Set<Waypoint> route = ride.getRoute(); Waypoint newPosition = new Waypoint( System.currentTimeMillis(), lat, lon, dir); waypoints.save(newPosition); route.add(newPosition); ride.setRoute(route); rides.save(ride); LocationService Assuming we have a Ride object we check if this is currently an ongoing ride that wasn't finished
  • 26. public class LocationService { @Autowired private UserRepository users; @Autowired private RideRepository rides; @Autowired private WaypointRepository waypoints; public void updateUserLocation(String token,double lat,double lon,float dir) { List<User> us = users.findByAuthToken(token); User u = us.get(0); u.setLatitude(lat); u.setLongitude(lat); u.setDirection(dir); users.save(u); if(u.isDriver() && u.getAssignedUser() != null) { List<Ride> r = rides.findByNotFinishedUser(u.getId()); if(r != null && !r.isEmpty()) { Ride ride = r.get(0); if(ride.isStarted() && !ride.isFinished()) { Set<Waypoint> route = ride.getRoute(); Waypoint newPosition = new Waypoint( System.currentTimeMillis(), lat, lon, dir); waypoints.save(newPosition); route.add(newPosition); ride.setRoute(route); rides.save(ride); LocationService If so we add a waypoint to the ride and update it so we can later on inspect the path of the Ride. This pretty much tracks rides seamlessly. If we wanted to be really smart we could detect the driver and user position to detect them traveling together and automatically handle the ride. There are obviously problems with this as it means a user can't order a cab for someone else but it might be an interesting feature since we have two close data points…