Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions TourGuide/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
<properties>
<java.version>17</java.version>
</properties>
<repositories>
<repository>
<id>local-libs</id>
<url>file://${project.basedir}/libs</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -48,21 +54,27 @@
</dependency>

<dependency>
<groupId>gpsUtil</groupId>
<groupId>com.local</groupId>
<artifactId>gpsUtil</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/gpsUtil.jar</systemPath>
</dependency>

<dependency>
<groupId>tripPricer</groupId>
<artifactId>tripPricer</artifactId>
<groupId>com.local</groupId>
<artifactId>rewardCentral</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/rewardCentral.jar</systemPath>
</dependency>

<dependency>
<groupId>rewardCentral</groupId>
<artifactId>rewardCentral</artifactId>
<groupId>com.local</groupId>
<artifactId>tripPricer</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/tripPricer.jar</systemPath>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import java.util.List;

import com.openclassrooms.tourguide.dto.NearByAttractionDto;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import gpsUtil.location.Attraction;
import gpsUtil.location.VisitedLocation;

import com.openclassrooms.tourguide.service.TourGuideService;
Expand Down Expand Up @@ -41,10 +42,10 @@ public VisitedLocation getLocation(@RequestParam String userName) {
// The distance in miles between the user's location and each of the attractions.
// The reward points for visiting each Attraction.
// Note: Attraction reward points can be gathered from RewardsCentral
@RequestMapping("/getNearbyAttractions")
public List<Attraction> getNearbyAttractions(@RequestParam String userName) {
VisitedLocation visitedLocation = tourGuideService.getUserLocation(getUser(userName));
return tourGuideService.getNearByAttractions(visitedLocation);
@RequestMapping("/getNearbyAttractions")
public List<NearByAttractionDto> getNearbyAttractions(@RequestParam String userName) {
User user = getUser(userName);
return tourGuideService.getNearByAttractionDtos(user);
}

@RequestMapping("/getRewards")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.openclassrooms.tourguide.dto;

import gpsUtil.location.Location;

public class NearByAttractionDto {
public String attractionName;
public Location attractionLocation;
public Location userLocation;
public double distance;
public int rewardPoints;

public NearByAttractionDto(String attractionName, Location attractionLocation,
Location userLocation, double distance, int rewardPoints) {
this.attractionName = attractionName;
this.attractionLocation = attractionLocation;
this.userLocation = userLocation;
this.distance = distance;
this.rewardPoints = rewardPoints;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.openclassrooms.tourguide.service;

import java.util.Comparator;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

Expand All @@ -22,47 +25,54 @@ public class RewardsService {
private int attractionProximityRange = 200;
private final GpsUtil gpsUtil;
private final RewardCentral rewardsCentral;

private final ReentrantLock rewardsLock = new ReentrantLock();

public RewardsService(GpsUtil gpsUtil, RewardCentral rewardCentral) {
this.gpsUtil = gpsUtil;
this.rewardsCentral = rewardCentral;
}

public void setProximityBuffer(int proximityBuffer) {
this.proximityBuffer = proximityBuffer;
}

public void setDefaultProximityBuffer() {
proximityBuffer = defaultProximityBuffer;
}

public void calculateRewards(User user) {
List<VisitedLocation> userLocations = user.getVisitedLocations();
List<Attraction> attractions = gpsUtil.getAttractions();

for(VisitedLocation visitedLocation : userLocations) {
for(Attraction attraction : attractions) {
if(user.getUserRewards().stream().filter(r -> r.attraction.attractionName.equals(attraction.attractionName)).count() == 0) {
if(nearAttraction(visitedLocation, attraction)) {
user.addUserReward(new UserReward(visitedLocation, attraction, getRewardPoints(attraction, user)));
rewardsLock.lock();
try {
List<VisitedLocation> userLocations = user.getVisitedLocations();
List<Attraction> attractions = gpsUtil.getAttractions();

for(VisitedLocation visitedLocation : userLocations) {
for(Attraction attraction : attractions) {
if(user.getUserRewards().stream().noneMatch(reward -> reward.attraction.attractionName
.equals(attraction.attractionName))) {
if(nearAttraction(visitedLocation, attraction)) {
user.addUserReward(new UserReward(visitedLocation, attraction));
}
}
}
}
} finally {
rewardsLock.unlock();
}
}

public boolean isWithinAttractionProximity(Attraction attraction, Location location) {
return getDistance(attraction, location) > attractionProximityRange ? false : true;
}

private boolean nearAttraction(VisitedLocation visitedLocation, Attraction attraction) {
return getDistance(attraction, visitedLocation.location) > proximityBuffer ? false : true;
return !(getDistance(attraction, visitedLocation.location) > proximityBuffer);
}
private int getRewardPoints(Attraction attraction, User user) {

public int getRewardPoints(Attraction attraction, User user) {
return rewardsCentral.getAttractionRewardPoints(attraction.attractionId, user.getUserId());
}

public double getDistance(Location loc1, Location loc2) {
double lat1 = Math.toRadians(loc1.latitude);
double lon1 = Math.toRadians(loc1.longitude);
Expand All @@ -77,4 +87,12 @@ public double getDistance(Location loc1, Location loc2) {
return statuteMiles;
}

public List<Attraction> findClosestAttractions(Location userLocation, List<Attraction> attractions, int limit) {
return attractions.stream()
.sorted(Comparator.comparingDouble(a ->
getDistance(userLocation, new Location(a.latitude, a.longitude))))
.limit(limit)
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package com.openclassrooms.tourguide.service;

import com.openclassrooms.tourguide.dto.NearByAttractionDto;
import com.openclassrooms.tourguide.helper.InternalTestHelper;
import com.openclassrooms.tourguide.tracker.Tracker;
import com.openclassrooms.tourguide.user.User;
import com.openclassrooms.tourguide.user.UserReward;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

Expand Down Expand Up @@ -80,10 +74,26 @@ public void addUser(User user) {
}

public List<Provider> getTripDeals(User user) {
int cumulatativeRewardPoints = user.getUserRewards().stream().mapToInt(i -> i.getRewardPoints()).sum();
List<Provider> providers = tripPricer.getPrice(tripPricerApiKey, user.getUserId(),
user.getUserPreferences().getNumberOfAdults(), user.getUserPreferences().getNumberOfChildren(),
user.getUserPreferences().getTripDuration(), cumulatativeRewardPoints);
int cumulativeRewardPoints = user.getUserRewards().stream()
.mapToInt(UserReward::getRewardPoints)
.sum();

var userPreference = user.getUserPreferences();

// La méthode getPrice(...) retourne 5 providers par appel.
// Le test en attend 10 => on appelle deux fois et on fusionne les résultats.
List<Provider> providers = IntStream.range(0, 2)
.mapToObj(i -> tripPricer.getPrice(
tripPricerApiKey,
user.getUserId(),
userPreference.getNumberOfAdults(),
userPreference.getNumberOfChildren(),
userPreference.getTripDuration(),
cumulativeRewardPoints
))
.flatMap(List::stream)
.collect(Collectors.toList());

user.setTripDeals(providers);
return providers;
}
Expand All @@ -96,14 +106,33 @@ public VisitedLocation trackUserLocation(User user) {
}

public List<Attraction> getNearByAttractions(VisitedLocation visitedLocation) {
List<Attraction> nearbyAttractions = new ArrayList<>();
for (Attraction attraction : gpsUtil.getAttractions()) {
if (rewardsService.isWithinAttractionProximity(attraction, visitedLocation.location)) {
nearbyAttractions.add(attraction);
}
}
Location userLocation = visitedLocation.location;
List<Attraction> allAttractions = gpsUtil.getAttractions();
return rewardsService.findClosestAttractions(userLocation, allAttractions, 5);
}

return nearbyAttractions;
public List<NearByAttractionDto> getNearByAttractionDtos(User user) {
VisitedLocation visitedLocation = getUserLocation(user);
Location userLocation = visitedLocation.location;
List<Attraction> attractions = gpsUtil.getAttractions();

List<Attraction> closestAttractions = rewardsService.findClosestAttractions(userLocation, attractions, 5);

return closestAttractions.stream()
.map(attraction -> {
Location attractionLocation = new Location(attraction.latitude, attraction.longitude);
double distance = rewardsService.getDistance(userLocation, attractionLocation);
int rewardPoints = rewardsService.getRewardPoints(attraction, user);

return new NearByAttractionDto(
attraction.attractionName,
attractionLocation,
userLocation,
distance,
rewardPoints
);
})
.collect(Collectors.toList());
}

private void addShutDownHook() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

import gpsUtil.location.VisitedLocation;
import tripPricer.Provider;
Expand All @@ -14,8 +15,8 @@ public class User {
private String phoneNumber;
private String emailAddress;
private Date latestLocationTimestamp;
private List<VisitedLocation> visitedLocations = new ArrayList<>();
private List<UserReward> userRewards = new ArrayList<>();
private List<VisitedLocation> visitedLocations = new CopyOnWriteArrayList<>();
private List<UserReward> userRewards = new CopyOnWriteArrayList<>();
private UserPreferences userPreferences = new UserPreferences();
private List<Provider> tripDeals = new ArrayList<>();
public User(UUID userId, String userName, String phoneNumber, String emailAddress) {
Expand Down Expand Up @@ -68,12 +69,8 @@ public List<VisitedLocation> getVisitedLocations() {
public void clearVisitedLocations() {
visitedLocations.clear();
}

public void addUserReward(UserReward userReward) {
if(userRewards.stream().filter(r -> !r.attraction.attractionName.equals(userReward.attraction)).count() == 0) {
userRewards.add(userReward);
}
}

public void addUserReward(UserReward userReward) {userRewards.add(userReward);}

public List<UserReward> getUserRewards() {
return userRewards;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.junit.jupiter.api.Disabled;
import gpsUtil.location.Location;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import gpsUtil.GpsUtil;
Expand All @@ -21,6 +23,12 @@
import com.openclassrooms.tourguide.user.UserReward;

public class TestRewardsService {
private RewardsService rewardsService;

@BeforeEach
public void setup() {
rewardsService = new RewardsService(null, null); // on passe null pour gpsUtil et RewardCentral ici si inutilisés
}

@Test
public void userGetRewards() {
Expand All @@ -47,9 +55,9 @@ public void isWithinAttractionProximity() {
assertTrue(rewardsService.isWithinAttractionProximity(attraction, attraction));
}

@Disabled // Needs fixed - can throw ConcurrentModificationException
@Test
public void nearAllAttractions() {

GpsUtil gpsUtil = new GpsUtil();
RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
rewardsService.setProximityBuffer(Integer.MAX_VALUE);
Expand All @@ -64,4 +72,22 @@ public void nearAllAttractions() {
assertEquals(gpsUtil.getAttractions().size(), userRewards.size());
}

@Test
public void testFindClosestAttractions() {
Location userLocation = new Location(40.0, -75.0);

Attraction a1 = new Attraction("Attraction1", "City1", "State1", 40.0, -75.0); // distance 0
Attraction a2 = new Attraction("Attraction2", "City2", "State2", 41.0, -75.0); // plus loin
Attraction a3 = new Attraction("Attraction3", "City3", "State3", 39.0, -75.0); // plus loin
Attraction a4 = new Attraction("Attraction4", "City4", "State4", 40.0, -76.0);
Attraction a5 = new Attraction("Attraction5", "City5", "State5", 42.0, -75.0);
Attraction a6 = new Attraction("Attraction6", "City6", "State6", 38.0, -75.0);

List<Attraction> attractions = Arrays.asList(a6, a3, a5, a2, a4, a1);

List<Attraction> closest = rewardsService.findClosestAttractions(userLocation, attractions, 5);

assertEquals(5, closest.size());
assertEquals("Attraction1", closest.get(0).attractionName);
}
}
Loading