Add template for assignment 2

This commit is contained in:
2021-04-26 14:12:50 +02:00
parent 6d5b4b7b48
commit dd1e95d6aa
100 changed files with 6085 additions and 0 deletions
@@ -0,0 +1,24 @@
package dst.ass2.service.api.auth;
public class AuthenticationException extends Exception {
private static final long serialVersionUID = 1L;
public AuthenticationException() {
}
public AuthenticationException(String message) {
super(message);
}
public AuthenticationException(String message, Throwable cause) {
super(message, cause);
}
public AuthenticationException(Throwable cause) {
super(cause);
}
public AuthenticationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@@ -0,0 +1,52 @@
package dst.ass2.service.api.auth;
public interface IAuthenticationService {
/**
* Attempts to authenticate the user with the given unique email address and the given password in plain text, by
* checking the data against the records in the database. If the credentials are successfully authenticated, the
* service generates a new authentication token which is stored (with the users email address) in-memory and then
* returned.
*
* @param email the user email
* @param password the password
* @return a new authentication token
* @throws NoSuchUserException if the given user was not found
* @throws AuthenticationException if the credentials could not be authenticated
*/
String authenticate(String email, String password) throws NoSuchUserException, AuthenticationException;
/**
* Changes the password of the given user in the database. Also updates the in-memory cache in a thread-safe way.
*
* @param email the user email
* @param newPassword the new password in plain text.
* @throws NoSuchUserException if the given user was not found
*/
void changePassword(String email, String newPassword) throws NoSuchUserException;
/**
* Returns the user that is associated with this token. Returns null if the token does not exist.
*
* @param token an authentication token previously created via {@link #authenticate(String, String)}
* @return the user's email address or null
*/
String getUser(String token);
/**
* Checks whether the given token is valid (i.e., was issued by this service and has not been invalidated).
*
* @param token the token to validate
* @return true if the token is valid, false otherwise
*/
boolean isValid(String token);
/**
* Invalidates the given token, i.e., removes it from the cache. Returns false if the token did not exist.
*
* @param token the token to invalidate
* @return true if the token existed and was successfully invalidated, false otherwise
*/
boolean invalidate(String token);
}
@@ -0,0 +1,25 @@
package dst.ass2.service.api.auth;
public class NoSuchUserException extends Exception {
private static final long serialVersionUID = 1L;
public NoSuchUserException() {
}
public NoSuchUserException(String message) {
super(message);
}
public NoSuchUserException(String message, Throwable cause) {
super(message, cause);
}
public NoSuchUserException(Throwable cause) {
super(cause);
}
public NoSuchUserException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@@ -0,0 +1,18 @@
package dst.ass2.service.api.auth.rest;
import javax.ws.rs.core.Response;
import dst.ass2.service.api.auth.AuthenticationException;
import dst.ass2.service.api.auth.NoSuchUserException;
/**
* The IAuthenticationResource exposes parts of the {@code IAuthenticationService} as a RESTful interface.
*/
public interface IAuthenticationResource {
// TODO annotate the class and methods with the correct javax.ws.rs annotations
Response authenticate(String email, String password)
throws NoSuchUserException, AuthenticationException;
}
@@ -0,0 +1,29 @@
package dst.ass2.service.api.match;
import dst.ass2.service.api.trip.InvalidTripException;
import dst.ass2.service.api.trip.MoneyDTO;
import dst.ass2.service.api.trip.TripDTO;
/**
* An implementation of this interface is provided to you by the application.
*/
public interface IMatchingService {
/**
* The passed trip needs at least the following properties set: riderId, pickup, destination and fare
*
* @param trip the trip the MatchingService will calculate a fare for
* @return the proposed fare for the given trip
* @throws InvalidTripException in case the route cannot be calculated
*/
MoneyDTO calculateFare(TripDTO trip) throws InvalidTripException;
/**
* Puts the trip into the queue for driver matching.
* The trip with the specified ID needs at least the following properties set:
* riderId, pickup, destination and fare
*
* @param tripId
*/
void queueTripForMatching(Long tripId);
}
@@ -0,0 +1,12 @@
package dst.ass2.service.api.trip;
public class DriverNotAvailableException extends Exception {
public DriverNotAvailableException(String message) {
super(message);
}
public DriverNotAvailableException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -0,0 +1,17 @@
package dst.ass2.service.api.trip;
/**
* Exception indicating that a resource that was trying to be accessed does not exist.
*/
public class EntityNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
public EntityNotFoundException(String message) {
super(message);
}
public EntityNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -0,0 +1,112 @@
package dst.ass2.service.api.trip;
public interface ITripService {
/**
* Creates and persists a Trip, sets the state to CREATED and calculates an initial fare estimation for
* the route 'pickupId - destinationId'
*
* @param riderId the id of the rider, who is planning a trip
* @param pickupId the id of the pickupId location
* @param destinationId the id of the destinationId location
* @return a TripDTO corresponding to the persisted Trip and includes the fare (null if route is invalid)
* @throws EntityNotFoundException if the rider or one of the locations doesn't exist
*/
TripDTO create(Long riderId, Long pickupId, Long destinationId) throws EntityNotFoundException;
/**
* Confirms the given trip (i.e., sets the state of the corresponding trip to QUEUED and
* puts it into the queue for matching), if possible (i.e., the trip is still in CREATED state)
*
* @param tripId the trip to confirm
* @throws EntityNotFoundException if the trip cannot be found
* @throws IllegalStateException in case the trip is not in state CREATED or the rider is null
* @throws InvalidTripException in case the fare couldn't be estimated
*/
void confirm(Long tripId) throws EntityNotFoundException, IllegalStateException, InvalidTripException;
/**
* Creates a match for the given trip and sets the trip's state to MATCHED, if possible (i.e., if the trips is
* QUEUED). Rolls back transaction in case something goes wrong and re-queues the trip for a new match.
* You can assume that the locations (pickup, destination and stops) haven't been deleted and will not be deleted
* during the execution of this method.
*
* @param tripId the id of the trip the match will be created for
* @param match the match, containing the driver, the vehicle and the fare
* @throws EntityNotFoundException in case one of the following doesn't exist anymore: trip, driver or
* vehicle
* @throws DriverNotAvailableException in case the driver was assigned in the meantime to another customer
* @throws IllegalStateException in case the rider of the trip is null or the trip is not in QUEUED state
*/
void match(Long tripId, MatchDTO match) throws EntityNotFoundException, DriverNotAvailableException, IllegalStateException;
/**
* Completes the trip (i. e., persists a TripInfo object and set the trips state to COMPLETED)
*
* @param tripId the id of the trip to complete
* @param tripInfoDTO the tripInfo to persist
* @throws EntityNotFoundException in case the trip doesn't exist
*/
void complete(Long tripId, TripInfoDTO tripInfoDTO) throws EntityNotFoundException;
/**
* Cancels the given trip (i.e., sets the state to cancelled)
*
* @param tripId the trip to cancel
* @throws EntityNotFoundException in case the trip doesn't exist
*/
void cancel(Long tripId) throws EntityNotFoundException;
/**
* Adds the location as a stop if possible (i.e., if the referenced trip is still in the CREATED state and
* the given location is not already in the list of stops.)
* As a side effect, the list of the passed TripDTO is modified and the fare freshly estimated.
* In case the the estimation fails, sets the fare to null.
*
* You can assume that the passed TripDTO and the Trip entity have the same values
* @param trip the trip
* @param locationId the location
* @return true if the stop was added, otherwise false
* @throws EntityNotFoundException in case the location or trip doesn't exist
* @throws IllegalStateException in case the trip isn't longer in the CREATED state
*/
boolean addStop(TripDTO trip, Long locationId) throws EntityNotFoundException, IllegalStateException;
/**
* Removes the location from the stops only (i.e., if the referenced trip is still in the CREATED state).
* As a side effect, the list of the passed TripDTO is modified and the fare freshly estimated.
* In case the the estimation fails, sets the fare to null.
*
* You can assume that the passed TripDTO and the Trip entity have the same values
* @param trip the trip
* @param locationId the location to remove
* @return true if the trip was removed, otherwise false (for example when the location wasn't added to the stops)
* @throws EntityNotFoundException in case the location or trip doesn't exist
* @throws IllegalStateException in case the trip isn't longer in the CREATED state
*/
boolean removeStop(TripDTO trip, Long locationId) throws EntityNotFoundException, IllegalStateException;
/**
* Removes the trip with the given id.
*
* @param tripId the id of the trip to remove
* @throws EntityNotFoundException in case the trip doesn't exist
*/
void delete(Long tripId) throws EntityNotFoundException;
/**
* Finds the trip with the given id and returns it as DTO, including the latest fare estimation.
*
* @param tripId the id of the trip
* @return if found the DTO, otherwise null
*/
TripDTO find(Long tripId);
}
@@ -0,0 +1,10 @@
package dst.ass2.service.api.trip;
public class InvalidTripException extends Exception {
public InvalidTripException() {
}
public InvalidTripException(String message) {
super(message);
}
}
@@ -0,0 +1,38 @@
package dst.ass2.service.api.trip;
import java.io.Serializable;
public class MatchDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long driverId;
private Long vehicleId;
private MoneyDTO fare;
public Long getDriverId() {
return driverId;
}
public void setDriverId(Long driverId) {
this.driverId = driverId;
}
public Long getVehicleId() {
return vehicleId;
}
public void setVehicleId(Long vehicleId) {
this.vehicleId = vehicleId;
}
public MoneyDTO getFare() {
return fare;
}
public void setFare(MoneyDTO fare) {
this.fare = fare;
}
}
@@ -0,0 +1,52 @@
package dst.ass2.service.api.trip;
import java.math.BigDecimal;
import java.util.Objects;
public class MoneyDTO {
private String currency;
private BigDecimal value;
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MoneyDTO moneyDTO = (MoneyDTO) o;
return Objects.equals(getCurrency(), moneyDTO.getCurrency()) &&
Objects.equals(getValue(), moneyDTO.getValue());
}
@Override
public int hashCode() {
return Objects.hash(getCurrency(), getValue());
}
@Override
public String toString() {
return "MoneyDTO{" +
"currency='" + currency + '\'' +
", value=" + value +
'}';
}
}
@@ -0,0 +1,68 @@
package dst.ass2.service.api.trip;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
public class TripDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Long riderId;
private Long pickupId;
private Long destinationId;
private List<Long> stops;
private MoneyDTO fare;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getRiderId() {
return riderId;
}
public void setRiderId(Long riderId) {
this.riderId = riderId;
}
public Long getPickupId() {
return pickupId;
}
public void setPickupId(Long pickupId) {
this.pickupId = pickupId;
}
public Long getDestinationId() {
return destinationId;
}
public void setDestinationId(Long destinationId) {
this.destinationId = destinationId;
}
public List<Long> getStops() {
if (stops == null) {
stops = new LinkedList<>();
}
return stops;
}
public void setStops(List<Long> stops) {
this.stops = stops;
}
public MoneyDTO getFare() {
return fare;
}
public void setFare(MoneyDTO fare) {
this.fare = fare;
}
}
@@ -0,0 +1,35 @@
package dst.ass2.service.api.trip;
import java.util.Date;
public class TripInfoDTO {
private Double distance;
private Date completed;
private MoneyDTO fare;
public Double getDistance() {
return distance;
}
public void setDistance(Double distance) {
this.distance = distance;
}
public Date getCompleted() {
return completed;
}
public void setCompleted(Date completed) {
this.completed = completed;
}
public MoneyDTO getFare() {
return fare;
}
public void setFare(MoneyDTO fare) {
this.fare = fare;
}
}
@@ -0,0 +1,36 @@
package dst.ass2.service.api.trip.rest;
import dst.ass2.service.api.trip.*;
import javax.ws.rs.core.Response;
/**
* This interface exposes the {@code ITripService} as a RESTful interface.
*/
public interface ITripServiceResource {
// TODO annotate the class and methods with the correct javax.ws.rs annotations
Response createTrip(Long riderId, Long pickupId, Long destinationId)
throws EntityNotFoundException, InvalidTripException;
Response confirm(Long tripId) throws EntityNotFoundException, InvalidTripException;
Response getTrip(Long tripId) throws EntityNotFoundException;
Response deleteTrip(Long tripId) throws EntityNotFoundException;
Response addStop(Long tripId, Long locationId) throws InvalidTripException, EntityNotFoundException;
Response removeStop(Long tripId, Long locationId) throws InvalidTripException, EntityNotFoundException;
Response match(Long tripId, MatchDTO matchDTO) throws EntityNotFoundException, DriverNotAvailableException;
Response complete(Long tripId, TripInfoDTO tripInfoDTO) throws EntityNotFoundException;
Response cancel(Long tripId) throws EntityNotFoundException;
}
@@ -0,0 +1,3 @@
syntax = "proto3";
// TODO implement authentication service
@@ -0,0 +1,66 @@
package dst.ass2.proto.auth;
import io.grpc.MethodDescriptor;
import io.grpc.ServiceDescriptor;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
public class ProtoSpecificationTest {
private ClassLoader cl;
public static final String SERVICE_NAME = "dst.ass2.service.api.auth.proto.AuthService";
public static final String GRPC_CLASS_NAME = SERVICE_NAME + "Grpc";
@Before
public void setUp() throws Exception {
cl = ProtoSpecificationTest.class.getClassLoader();
}
@Test
public void generatedClass_exists() throws Exception {
try {
cl.loadClass(GRPC_CLASS_NAME);
} catch (ClassNotFoundException e) {
throw new AssertionError("Classpath did not contain expected gRPC service class", e);
}
}
@Test
public void generatedClass_hasMethods() throws Exception {
assertThat(getMethodDescriptors().keySet(), hasItems(
SERVICE_NAME + "/authenticate",
SERVICE_NAME + "/validateToken"
));
}
private Map<String, MethodDescriptor> getMethodDescriptors() throws ClassNotFoundException {
return getMethodDescriptors(getServiceDescriptor(cl.loadClass(GRPC_CLASS_NAME)));
}
private Map<String, MethodDescriptor> getMethodDescriptors(ServiceDescriptor sd) {
return sd.getMethods().stream()
.collect(Collectors.toMap(
MethodDescriptor::getFullMethodName,
Function.identity()
));
}
private ServiceDescriptor getServiceDescriptor(Class<?> grpcClass) {
try {
Method getServiceDescriptor = grpcClass.getDeclaredMethod("getServiceDescriptor");
getServiceDescriptor.setAccessible(true);
return (ServiceDescriptor) getServiceDescriptor.invoke(null);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException("Error finding service descriptor in " + grpcClass.getName(), e);
}
}
}