diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000000..b409df77dd --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,62 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + compile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: maven install gps + run: mvn install:install-file -Dfile="libs/gpsUtil.jar" -DgroupId="gpsUtil" -DartifactId="gpsUtil" -Dversion="1.0.0" -f TourGuide/pom.xml -Dpackaging=jar + - name: maven install RewardCentral + run: mvn install:install-file -Dfile="libs/RewardCentral.jar" -DgroupId="RewardCentral" -DartifactId="RewardCentral" -Dversion="1.0.0" -f TourGuide/pom.xml -Dpackaging=jar + - name: mvn install TripPricer + run: mvn install:install-file -Dfile="libs/TripPricer.jar" -DgroupId="TripPricer" -DartifactId="TripPricer" -Dversion="1.0.0" -f TourGuide/pom.xml -Dpackaging=jar + + test: + runs-on: ubuntu-latest + needs: compile + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: test + run: mvn test --file TourGuide/pom.xml + + build: + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file TourGuide/pom.xml + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..9f970225ad --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..b901097f2d --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000..2cc7d4a55c Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..642d572ce9 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..e0f15db2eb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/TourGuide/pom.xml b/TourGuide/pom.xml index d3aaeeb349..3c42829d1a 100644 --- a/TourGuide/pom.xml +++ b/TourGuide/pom.xml @@ -1,12 +1,13 @@ - 4.0.0 org.springframework.boot spring-boot-starter-parent 3.1.1 - + com.openclassrooms tourguide @@ -14,13 +15,16 @@ tourguide Demo project for Spring Boot - 17 + 21 org.springframework.boot spring-boot-starter-actuator + + + org.springframework.boot spring-boot-starter-validation @@ -28,6 +32,7 @@ org.springframework.boot spring-boot-starter-web + 3.3.3 @@ -35,44 +40,60 @@ spring-boot-starter-test test - org.apache.commons commons-lang3 - - - org.junit.jupiter - junit-jupiter-api - test - - gpsUtil gpsUtil + system + ${project.basedir}/libs/gpsUtil.jar 1.0.0 - - tripPricer - tripPricer + RewardCentral + RewardCentral + system + ${project.basedir}/libs/RewardCentral.jar 1.0.0 - - rewardCentral - rewardCentral + TripPricer + TripPricer + system + ${project.basedir}/libs/TripPricer.jar 1.0.0 + + org.junit.jupiter + junit-jupiter-api + test + - + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.3.1 + + + **/TestPerformance.java + + + + + + org.springframework.boot spring-boot-maven-plugin + - + \ No newline at end of file diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/TourGuideController.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/TourGuideController.java index a884e6590b..b5b155e646 100644 --- a/TourGuide/src/main/java/com/openclassrooms/tourguide/TourGuideController.java +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/TourGuideController.java @@ -1,15 +1,19 @@ package com.openclassrooms.tourguide; import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; 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.dto.NearAttractionDto; import com.openclassrooms.tourguide.service.TourGuideService; import com.openclassrooms.tourguide.user.User; import com.openclassrooms.tourguide.user.UserReward; @@ -18,37 +22,28 @@ @RestController public class TourGuideController { - - @Autowired - TourGuideService tourGuideService; - + private TourGuideService tourGuideService; + public TourGuideController(TourGuideService tourGuideService) { + this.tourGuideService = tourGuideService; + } @RequestMapping("/") public String index() { return "Greetings from TourGuide!"; } - + @Async @RequestMapping("/getLocation") - public VisitedLocation getLocation(@RequestParam String userName) { + public CompletableFuture getLocation(@RequestParam String userName) throws InterruptedException, ExecutionException { return tourGuideService.getUserLocation(getUser(userName)); } - - // TODO: Change this method to no longer return a List of Attractions. - // Instead: Get the closest five tourist attractions to the user - no matter how far away they are. - // Return a new JSON object that contains: - // Name of Tourist attraction, - // Tourist attractions lat/long, - // The user's location lat/long, - // 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 + @Async @RequestMapping("/getNearbyAttractions") - public List getNearbyAttractions(@RequestParam String userName) { - VisitedLocation visitedLocation = tourGuideService.getUserLocation(getUser(userName)); + public CompletableFuture getNearbyAttractions(@RequestParam String userName) throws InterruptedException, ExecutionException { + CompletableFuture visitedLocation = tourGuideService.getUserLocation(getUser(userName)); return tourGuideService.getNearByAttractions(visitedLocation); } @RequestMapping("/getRewards") - public List getRewards(@RequestParam String userName) { + public Map getRewards(@RequestParam String userName) { return tourGuideService.getUserRewards(getUser(userName)); } diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/config/ConfigClass.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/config/ConfigClass.java new file mode 100644 index 0000000000..3b64283c9e --- /dev/null +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/config/ConfigClass.java @@ -0,0 +1,10 @@ +package com.openclassrooms.tourguide.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; + +@Configuration +@EnableAsync +public class ConfigClass { + +} diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/dto/NearAttractionDto.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/dto/NearAttractionDto.java new file mode 100644 index 0000000000..b387c09a84 --- /dev/null +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/dto/NearAttractionDto.java @@ -0,0 +1,43 @@ +package com.openclassrooms.tourguide.dto; + +import gpsUtil.location.Location; + +public class NearAttractionDto { + + private String TouristAttractionName; + private String TouristAttractionLocation; + private Location userLocations; + private double distance; + private int rewardPoints; + + public String getTouristAttractionName() { + return TouristAttractionName; + } + public void setTouristAttractionName(String touristAttractionName) { + TouristAttractionName = touristAttractionName; + } + public String getTouristAttractionLocation() { + return TouristAttractionLocation; + } + public void setTouristAttractionLocation(String touristAttractionLocation) { + TouristAttractionLocation = touristAttractionLocation; + } + public Location getUserLocations() { + return userLocations; + } + public void setUserLocations(Location userLocations) { + this.userLocations = userLocations; + } + public double getDistance() { + return distance; + } + public void setDistance(double distance) { + this.distance = distance; + } + public int getRewardPoints() { + return rewardPoints; + } + public void setRewardPoints(int rewardPoints) { + this.rewardPoints = rewardPoints; + } +} diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/service/RewardsService.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/service/RewardsService.java index ad440eb484..1b89fe9f56 100644 --- a/TourGuide/src/main/java/com/openclassrooms/tourguide/service/RewardsService.java +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/service/RewardsService.java @@ -1,9 +1,7 @@ package com.openclassrooms.tourguide.service; import java.util.List; - import org.springframework.stereotype.Service; - import gpsUtil.GpsUtil; import gpsUtil.location.Attraction; import gpsUtil.location.Location; @@ -14,67 +12,75 @@ @Service public class RewardsService { - private static final double STATUTE_MILES_PER_NAUTICAL_MILE = 1.15077945; + private static final double STATUTE_MILES_PER_NAUTICAL_MILE = 1.15077945; - // proximity in miles - private int defaultProximityBuffer = 10; + // definition of proximity buffer in miles + private int defaultProximityBuffer = 10; private int proximityBuffer = defaultProximityBuffer; private int attractionProximityRange = 200; + private final GpsUtil gpsUtil; private final RewardCentral rewardsCentral; - + 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; } + //calculates rewards for given user from all visited locations public void calculateRewards(User user) { List userLocations = user.getVisitedLocations(); List 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))); - } + for (int i = 0; i < userLocations.size(); i++) { + for (int j = 0; j < attractions.size(); j++) { + Attraction attraction = attractions.get(j); + VisitedLocation userLocation = userLocations.get(i); + if (nearAttraction(userLocation, attraction)) { + user.addUserReward(new UserReward(userLocation, attraction, getRewardPoints(attraction, user))); } } } } - + //calculates rewards for given user from all visited locations in a separate thread + public Thread calculateRewardsThread(User user) { + return new Thread(() -> calculateRewards(user)); + } + + //check if user is within attraction proximity public boolean isWithinAttractionProximity(Attraction attraction, Location location) { return getDistance(attraction, location) > attractionProximityRange ? false : true; } - + //check if user is near attraction private boolean nearAttraction(VisitedLocation visitedLocation, Attraction attraction) { return getDistance(attraction, visitedLocation.location) > proximityBuffer ? false : true; } - + //get reward points for attraction private int getRewardPoints(Attraction attraction, User user) { return rewardsCentral.getAttractionRewardPoints(attraction.attractionId, user.getUserId()); } - + //calculate distance between 2 locations in miles public double getDistance(Location loc1, Location loc2) { - double lat1 = Math.toRadians(loc1.latitude); - double lon1 = Math.toRadians(loc1.longitude); - double lat2 = Math.toRadians(loc2.latitude); - double lon2 = Math.toRadians(loc2.longitude); + double lat1 = Math.toRadians(loc1.latitude); + double lon1 = Math.toRadians(loc1.longitude); + double lat2 = Math.toRadians(loc2.latitude); + double lon2 = Math.toRadians(loc2.longitude); - double angle = Math.acos(Math.sin(lat1) * Math.sin(lat2) - + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); + double angle = Math.acos(Math.sin(lat1) * Math.sin(lat2) + + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); - double nauticalMiles = 60 * Math.toDegrees(angle); - double statuteMiles = STATUTE_MILES_PER_NAUTICAL_MILE * nauticalMiles; - return statuteMiles; + double nauticalMiles = 60 * Math.toDegrees(angle); + double statuteMiles = STATUTE_MILES_PER_NAUTICAL_MILE * nauticalMiles; + return statuteMiles; } + } diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/service/TourGuideService.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/service/TourGuideService.java index 1aa6472dc9..89d1ad56ab 100644 --- a/TourGuide/src/main/java/com/openclassrooms/tourguide/service/TourGuideService.java +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/service/TourGuideService.java @@ -1,5 +1,6 @@ package com.openclassrooms.tourguide.service; +import com.openclassrooms.tourguide.dto.NearAttractionDto; import com.openclassrooms.tourguide.helper.InternalTestHelper; import com.openclassrooms.tourguide.tracker.Tracker; import com.openclassrooms.tourguide.user.User; @@ -7,7 +8,7 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.ArrayList; + import java.util.Date; import java.util.HashMap; import java.util.List; @@ -15,7 +16,8 @@ import java.util.Map; import java.util.Random; import java.util.UUID; -import java.util.stream.Collectors; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.stream.IntStream; import org.slf4j.Logger; @@ -29,58 +31,152 @@ import tripPricer.Provider; import tripPricer.TripPricer; - +/** + * Service that handles all the operations related to the users of the tour guide system. + * + * @author Aitor + */ @Service public class TourGuideService { + + /** + * Logger to log information about the service. + */ private Logger logger = LoggerFactory.getLogger(TourGuideService.class); + + /** + * GPS utility to get the user location. + */ private final GpsUtil gpsUtil; + + /** + * Service to calculate the rewards of the users. + */ private final RewardsService rewardsService; + + /** + * Trip pricer to get the trip deals for the users. + */ private final TripPricer tripPricer = new TripPricer(); + + /** + * Tracker to track the user location. + */ public final Tracker tracker; + + /** + * Flag to indicate if the test mode is enabled. + */ boolean testMode = true; + /** + * Constructor to initialize the service. + * + * @param gpsUtil + * GPS utility to get the user location. + * @param rewardsService + * Service to calculate the rewards of the users. + */ public TourGuideService(GpsUtil gpsUtil, RewardsService rewardsService) { this.gpsUtil = gpsUtil; this.rewardsService = rewardsService; - + + // Set the default locale to US. Locale.setDefault(Locale.US); if (testMode) { + // Log information about the test mode. logger.info("TestMode enabled"); logger.debug("Initializing users"); initializeInternalUsers(); logger.debug("Finished initializing users"); } + + // Initialize the tracker. tracker = new Tracker(this); + + // Add a shutdown hook to stop the tracker when the application is closed. addShutDownHook(); } - public List getUserRewards(User user) { + /** + * Get the rewards of the user. + * + * @param user + * User to get the rewards. + * @return Map of rewards. + */ + public Map getUserRewards(User user) { return user.getUserRewards(); } - public VisitedLocation getUserLocation(User user) { - VisitedLocation visitedLocation = (user.getVisitedLocations().size() > 0) ? user.getLastVisitedLocation() - : trackUserLocation(user); - return visitedLocation; + /** + * Get the location of the user. + * + * @param user + * User to get the location. + * @return CompletableFuture with the location of the user. + * @throws InterruptedException + * If the thread is interrupted. + * @throws ExecutionException + * If an error occurs while executing the future. + */ + public CompletableFuture getUserLocation(User user) throws InterruptedException, ExecutionException { + if (user.getVisitedLocations().size() > 0) { + return CompletableFuture.supplyAsync(() -> user.getLastVisitedLocation()); + } else { + CompletableFuture visitedLocation = trackUserLocation(user); + + return visitedLocation; + } } + /** + * Get the user by username. + * + * @param userName + * Username of the user to get. + * @return User with the given username. + */ public User getUser(String userName) { return internalUserMap.get(userName); } + /** + * Get all the users. + * + * @return List of all users. + */ public List getAllUsers() { - return internalUserMap.values().stream().collect(Collectors.toList()); + return internalUserMap.values().stream().toList(); } + /** + * Add a user to the internal user map. + * + * @param user + * User to add. + */ public void addUser(User user) { if (!internalUserMap.containsKey(user.getUserName())) { internalUserMap.put(user.getUserName(), user); } } + /** + * Get the trip deals for the user. + * + * @param user + * User to get the trip deals. + * @return List of trip deals. + */ public List getTripDeals(User user) { - int cumulatativeRewardPoints = user.getUserRewards().stream().mapToInt(i -> i.getRewardPoints()).sum(); + Map userRewards = user.getUserRewards(); + + int cumulatativeRewardPoints = 0; + for (UserReward userReward : userRewards.values()) { + cumulatativeRewardPoints += cumulatativeRewardPoints + userReward.getRewardPoints(); + } List providers = tripPricer.getPrice(tripPricerApiKey, user.getUserId(), user.getUserPreferences().getNumberOfAdults(), user.getUserPreferences().getNumberOfChildren(), user.getUserPreferences().getTripDuration(), cumulatativeRewardPoints); @@ -88,24 +184,53 @@ public List getTripDeals(User user) { return providers; } - public VisitedLocation trackUserLocation(User user) { - VisitedLocation visitedLocation = gpsUtil.getUserLocation(user.getUserId()); - user.addToVisitedLocations(visitedLocation); - rewardsService.calculateRewards(user); - return visitedLocation; + /** + * Track the user location. + * + * @param user + * User to track the location. + * @return CompletableFuture with the new location of the user. + */ + public CompletableFuture trackUserLocation(User user) { + + return CompletableFuture.supplyAsync(() -> { + VisitedLocation newLocation = gpsUtil.getUserLocation(user.getUserId()); + user.addToVisitedLocations(newLocation); + rewardsService.calculateRewardsThread(user).start(); + return newLocation; + }); } - public List getNearByAttractions(VisitedLocation visitedLocation) { - List nearbyAttractions = new ArrayList<>(); - for (Attraction attraction : gpsUtil.getAttractions()) { - if (rewardsService.isWithinAttractionProximity(attraction, visitedLocation.location)) { - nearbyAttractions.add(attraction); - } + /** + * Get the nearby attractions of the user. + * + * @param CompletableFuture with the visitedLocation + * Visited location of the user. + * @return Array of nearby attractions. + */ + public CompletableFuture getNearByAttractions(CompletableFuture visitedLocationf) { + return visitedLocationf.thenApplyAsync(visitedLocation -> { + List Attractions = gpsUtil.getAttractions(); + NearAttractionDto[] nearByAttractions = new NearAttractionDto[5]; + Attractions.sort((o1, o2) -> { + double l1 = rewardsService.getDistance(o1, visitedLocation.location); + double l2 = rewardsService.getDistance(o2, visitedLocation.location); + return Double.compare(l1, l2); + }); + + for (int i = 0; i < nearByAttractions.length; i++) { + NearAttractionDto nearAttractionDto = new NearAttractionDto(); + nearAttractionDto.setUserLocations(visitedLocation.location); + nearAttractionDto.setDistance(rewardsService.getDistance(Attractions.get(i), visitedLocation.location)); } - - return nearbyAttractions; + return nearByAttractions; + }); + } + /** + * Add a shutdown hook to stop the tracker when the application is closed. + */ private void addShutDownHook() { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { @@ -114,16 +239,23 @@ public void run() { }); } - /********************************************************************************** - * - * Methods Below: For Internal Testing - * - **********************************************************************************/ + /** + * Methods below: For internal testing + */ + + /** + * API key to get the trip deals. + */ private static final String tripPricerApiKey = "test-server-api-key"; - // Database connection will be used for external users, but for testing purposes - // internal users are provided and stored in memory + + /** + * Map to store the internal users. + */ private final Map internalUserMap = new HashMap<>(); + /** + * Initialize the internal users. + */ private void initializeInternalUsers() { IntStream.range(0, InternalTestHelper.getInternalUserNumber()).forEach(i -> { String userName = "internalUser" + i; @@ -137,6 +269,12 @@ private void initializeInternalUsers() { logger.debug("Created " + InternalTestHelper.getInternalUserNumber() + " internal test users."); } + /** + * Generate a random user location history. + * + * @param user + * User to generate the location history. + */ private void generateUserLocationHistory(User user) { IntStream.range(0, 3).forEach(i -> { user.addToVisitedLocations(new VisitedLocation(user.getUserId(), @@ -144,21 +282,36 @@ private void generateUserLocationHistory(User user) { }); } - private double generateRandomLongitude() { - double leftLimit = -180; - double rightLimit = 180; - return leftLimit + new Random().nextDouble() * (rightLimit - leftLimit); - } - + /** + * Generate a random latitude. + * + * @return Random latitude. + */ private double generateRandomLatitude() { double leftLimit = -85.05112878; double rightLimit = 85.05112878; return leftLimit + new Random().nextDouble() * (rightLimit - leftLimit); } + /** + * Generate a random longitude. + * + * @return Random longitude. + */ + private double generateRandomLongitude() { + double leftLimit = -180; + double rightLimit = 180; + return leftLimit + new Random().nextDouble() * (rightLimit - leftLimit); + } + + /** + * Generate a random time. + * + * @return Random time. + */ private Date getRandomTime() { LocalDateTime localDateTime = LocalDateTime.now().minusDays(new Random().nextInt(30)); return Date.from(localDateTime.toInstant(ZoneOffset.UTC)); } - } + diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/tracker/Tracker.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/tracker/Tracker.java index 179d3d7753..2e39a93223 100644 --- a/TourGuide/src/main/java/com/openclassrooms/tourguide/tracker/Tracker.java +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/tracker/Tracker.java @@ -39,13 +39,17 @@ public void run() { while (true) { if (Thread.currentThread().isInterrupted() || stop) { logger.debug("Tracker stopping"); + System.out.println("Tracker stopping"); break; } List users = tourGuideService.getAllUsers(); + System.out.println("users size is " + users.size()); logger.debug("Begin Tracker. Tracking " + users.size() + " users."); stopWatch.start(); - users.forEach(u -> tourGuideService.trackUserLocation(u)); + users.forEach(u -> { + tourGuideService.trackUserLocation(u).join(); + }); stopWatch.stop(); logger.debug("Tracker Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds."); stopWatch.reset(); diff --git a/TourGuide/src/main/java/com/openclassrooms/tourguide/user/User.java b/TourGuide/src/main/java/com/openclassrooms/tourguide/user/User.java index 32ed3b14ea..fbf77af0b3 100644 --- a/TourGuide/src/main/java/com/openclassrooms/tourguide/user/User.java +++ b/TourGuide/src/main/java/com/openclassrooms/tourguide/user/User.java @@ -2,7 +2,9 @@ import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import gpsUtil.location.VisitedLocation; @@ -15,7 +17,7 @@ public class User { private String emailAddress; private Date latestLocationTimestamp; private List visitedLocations = new ArrayList<>(); - private List userRewards = new ArrayList<>(); + private Map userRewards = new HashMap<>(); private UserPreferences userPreferences = new UserPreferences(); private List tripDeals = new ArrayList<>(); public User(UUID userId, String userName, String phoneNumber, String emailAddress) { @@ -70,12 +72,13 @@ public void clearVisitedLocations() { } public void addUserReward(UserReward userReward) { - if(userRewards.stream().filter(r -> !r.attraction.attractionName.equals(userReward.attraction)).count() == 0) { - userRewards.add(userReward); + String visitedLocationName=userReward.attraction.attractionName; + if(!userRewards.containsKey(visitedLocationName)) { + userRewards.put(visitedLocationName, userReward); } } - public List getUserRewards() { + public Map getUserRewards() { return userRewards; } diff --git a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestPerformance.java b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestPerformance.java index aed028f861..e508f9a3c4 100644 --- a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestPerformance.java +++ b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestPerformance.java @@ -5,12 +5,14 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.time.StopWatch; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; import gpsUtil.GpsUtil; import gpsUtil.location.Attraction; import gpsUtil.location.VisitedLocation; @@ -20,8 +22,9 @@ import com.openclassrooms.tourguide.service.TourGuideService; import com.openclassrooms.tourguide.user.User; +@SpringBootTest +@AutoConfigureMockMvc public class TestPerformance { - /* * A note on performance improvements: * @@ -45,14 +48,13 @@ public class TestPerformance { * TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime())); */ - @Disabled @Test - public void highVolumeTrackLocation() { + public void highVolumeTrackLocation() throws InterruptedException, ExecutionException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); // Users should be incremented up to 100,000, and test finishes within 15 // minutes - InternalTestHelper.setInternalUserNumber(100); + InternalTestHelper.setInternalUserNumber(100000); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); List allUsers = new ArrayList<>(); @@ -60,9 +62,15 @@ public void highVolumeTrackLocation() { StopWatch stopWatch = new StopWatch(); stopWatch.start(); - for (User user : allUsers) { - tourGuideService.trackUserLocation(user); + @SuppressWarnings("unchecked") + CompletableFuture[] future = new CompletableFuture[allUsers.size()]; + for (int i = 0; i < allUsers.size(); i++) { + CompletableFuture visitedLocation = tourGuideService.trackUserLocation(allUsers.get(i)); + future[i]=visitedLocation; } + + CompletableFuture.allOf(future).join(); + stopWatch.stop(); tourGuideService.tracker.stopTracking(); @@ -71,28 +79,33 @@ public void highVolumeTrackLocation() { assertTrue(TimeUnit.MINUTES.toSeconds(15) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime())); } - @Disabled @Test - public void highVolumeGetRewards() { + public void highVolumeGetRewards() throws InterruptedException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); // Users should be incremented up to 100,000, and test finishes within 20 // minutes - InternalTestHelper.setInternalUserNumber(100); + InternalTestHelper.setInternalUserNumber(100000); StopWatch stopWatch = new StopWatch(); stopWatch.start(); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); Attraction attraction = gpsUtil.getAttractions().get(0); - List allUsers = new ArrayList<>(); - allUsers = tourGuideService.getAllUsers(); + List allUsers = tourGuideService.getAllUsers(); allUsers.forEach(u -> u.addToVisitedLocations(new VisitedLocation(u.getUserId(), attraction, new Date()))); - allUsers.forEach(u -> rewardsService.calculateRewards(u)); + Thread[] futures = new Thread[allUsers.size()]; - for (User user : allUsers) { - assertTrue(user.getUserRewards().size() > 0); + for (int i = 0; i < futures.length; i++) { + futures[i] = rewardsService.calculateRewardsThread(allUsers.get(i)); + futures[i].start(); + } + for (int i = 0; i < futures.length; i++) { + futures[i].join(); + } + for (int i = 0; i < allUsers.size(); i++) { + assertTrue(allUsers.get(i).getUserRewards().size() > 0); } stopWatch.stop(); tourGuideService.tracker.stopTracking(); @@ -101,5 +114,4 @@ public void highVolumeGetRewards() { + " seconds."); assertTrue(TimeUnit.MINUTES.toSeconds(20) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime())); } - } diff --git a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestRewardsService.java b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestRewardsService.java index 2bcc2fb13e..faa1a7d4d9 100644 --- a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestRewardsService.java +++ b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestRewardsService.java @@ -2,12 +2,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.Date; -import java.util.List; + +import java.util.Map; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import gpsUtil.GpsUtil; @@ -23,7 +24,7 @@ public class TestRewardsService { @Test - public void userGetRewards() { + public void userGetRewards() throws InterruptedException, ExecutionException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); @@ -33,8 +34,11 @@ public void userGetRewards() { User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com"); Attraction attraction = gpsUtil.getAttractions().get(0); user.addToVisitedLocations(new VisitedLocation(user.getUserId(), attraction, new Date())); - tourGuideService.trackUserLocation(user); - List userRewards = user.getUserRewards(); + + CompletableFuture visitedLocationContainer = tourGuideService.trackUserLocation(user); + visitedLocationContainer.get(); + Thread.sleep(2000); + Map userRewards = user.getUserRewards(); tourGuideService.tracker.stopTracking(); assertTrue(userRewards.size() == 1); } @@ -47,20 +51,18 @@ 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); - InternalTestHelper.setInternalUserNumber(1); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); - - rewardsService.calculateRewards(tourGuideService.getAllUsers().get(0)); - List userRewards = tourGuideService.getUserRewards(tourGuideService.getAllUsers().get(0)); + User user =tourGuideService.getAllUsers().get(0); + rewardsService.calculateRewards(user); + Map userRewards = tourGuideService.getUserRewards(tourGuideService.getAllUsers().get(0)); tourGuideService.tracker.stopTracking(); - assertEquals(gpsUtil.getAttractions().size(), userRewards.size()); } diff --git a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestTourGuideService.java b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestTourGuideService.java index 2b053739e2..4c0655da75 100644 --- a/TourGuide/src/test/java/com/openclassrooms/tourguide/TestTourGuideService.java +++ b/TourGuide/src/test/java/com/openclassrooms/tourguide/TestTourGuideService.java @@ -5,14 +5,16 @@ import java.util.List; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import gpsUtil.GpsUtil; -import gpsUtil.location.Attraction; import gpsUtil.location.VisitedLocation; import rewardCentral.RewardCentral; + +import com.openclassrooms.tourguide.dto.NearAttractionDto; import com.openclassrooms.tourguide.helper.InternalTestHelper; import com.openclassrooms.tourguide.service.RewardsService; import com.openclassrooms.tourguide.service.TourGuideService; @@ -22,14 +24,17 @@ public class TestTourGuideService { @Test - public void getUserLocation() { + public void getUserLocation() throws InterruptedException, ExecutionException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); - InternalTestHelper.setInternalUserNumber(0); + InternalTestHelper.setInternalUserNumber(1); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com"); - VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user); + + CompletableFuture u=tourGuideService.trackUserLocation(user); + + VisitedLocation visitedLocation =u.get() ; tourGuideService.tracker.stopTracking(); assertTrue(visitedLocation.userId.equals(user.getUserId())); } @@ -78,36 +83,32 @@ public void getAllUsers() { } @Test - public void trackUser() { + public void trackUser() throws InterruptedException, ExecutionException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); InternalTestHelper.setInternalUserNumber(0); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com"); - VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user); - + CompletableFuture u=tourGuideService.trackUserLocation(user); + VisitedLocation visitedLocation =u.get(); tourGuideService.tracker.stopTracking(); assertEquals(user.getUserId(), visitedLocation.userId); } - @Disabled // Not yet implemented @Test - public void getNearbyAttractions() { + public void getNearbyAttractionsTest() throws InterruptedException, ExecutionException { GpsUtil gpsUtil = new GpsUtil(); RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral()); InternalTestHelper.setInternalUserNumber(0); TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService); User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com"); - VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user); - - List attractions = tourGuideService.getNearByAttractions(visitedLocation); - + CompletableFuture u=tourGuideService.trackUserLocation(user); + CompletableFuture nearByAttractions = tourGuideService.getNearByAttractions(u); + assertEquals(5, nearByAttractions.get().length); tourGuideService.tracker.stopTracking(); - - assertEquals(5, attractions.size()); } public void getTripDeals() { diff --git a/mvnw b/mvnw new file mode 100644 index 0000000000..41c0f0c23d --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000000..86115719e5 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE%