diff --git a/README.md b/README.md index 67a685698bfc2923b05876a900dc63af888b733c..6d5e7750a36f5ff8081d3e3844d083667a4953b1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -_This is an assignment to the class [Programmieren 3](https://hsro-inf-prg3.github.io) at the [University of Applied Sciences Rosenheim](http://www.fh-rosenheim.de)._ +_This is an assignment to the class [Programmieren 3](https://hsro-inf-prg3.github.io) at the [Technical University of Applied Sciences Rosenheim](https://www.th-rosenheim.de)._ # Assignment 11: Futures - CLI variant +[](https://travis-ci.org/hsro-inf-prg3/11-futures-cli) + This assignment covers the more advanced multithreading topics _futures_ and _future chaining_. Futures are a feature of Java 8 and can be compared to the concept of _promises_ in JavaScript. @@ -79,4 +81,4 @@ The required method to fetch a state is already present in the OpenMensaAPI. If you retrieved the state of the canteen at it is open at the specified date you have to retrieve the meals for the same params. Keep in mind to block the main thread to display the retrieved meals after you retrieved them. -If the canteen is not open at the specified date a meaningful message should be printed to inform the user, that the date has to be changed. \ No newline at end of file +If the canteen is not open at the specified date a meaningful message should be printed to inform the user, that the date has to be changed. diff --git a/build.gradle b/build.gradle index b48488a34952496a6a5063df8fd898c7e1f6c3f5..dc6437f474780bd66f92aa88998cd8ebb5efd190 100644 --- a/build.gradle +++ b/build.gradle @@ -15,17 +15,17 @@ mainClassName = 'de.thro.inf.prg3.a11.App' dependencies { /* Commons Lang3 */ - implementation "org.apache.commons:commons-lang3:$commons_lang_version" + implementation ("org.apache.commons:commons-lang3:${commons_lang_version}") /* Retrofit */ - implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" - implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version" + implementation("com.squareup.retrofit2:retrofit:${retrofit2_version}") + implementation("com.squareup.retrofit2:converter-gson:${retrofit2_version}") /* JUnit 5 */ testCompile("org.junit.jupiter:junit-jupiter-api:${junitVersion}") testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") testRuntime("org.junit.jupiter:junit-jupiter-params:${junitVersion}") - testRuntime("org.apache.logging.log4j:log4j-core:${log4jVersion}") + testImplementation("org.apache.logging.log4j:log4j-core:${log4jVersion}") testRuntime("org.apache.logging.log4j:log4j-jul:${log4jVersion}") } diff --git a/src/main/java/de/thro/inf/prg3/a11/App.java b/src/main/java/de/thro/inf/prg3/a11/App.java index 5091ba614c9d43b7ff84d5a0f5d40c80a8f3f256..8558c0004cb33f48f0a8bd8c858a456cb9f5a71a 100644 --- a/src/main/java/de/thro/inf/prg3/a11/App.java +++ b/src/main/java/de/thro/inf/prg3/a11/App.java @@ -16,115 +16,116 @@ import java.util.stream.IntStream; * Created on 12/16/17. */ public class App { - private static final String OPEN_MENSA_DATE_FORMAT = "yyyy-MM-dd"; + private static final String OPEN_MENSA_DATE_FORMAT = "yyyy-MM-dd"; - private static final SimpleDateFormat dateFormat = new SimpleDateFormat(OPEN_MENSA_DATE_FORMAT, Locale.getDefault()); - private static final Scanner inputScanner = new Scanner(System.in); - private static final OpenMensaAPI openMensaAPI = OpenMensaAPIService.getInstance().getOpenMensaAPI(); - private static final Calendar currentDate = Calendar.getInstance(); - private static int currentCanteenId = -1; + private static final SimpleDateFormat dateFormat = new SimpleDateFormat(OPEN_MENSA_DATE_FORMAT, Locale.getDefault()); + private static final Scanner inputScanner = new Scanner(System.in); + private static final OpenMensaAPI openMensaAPI = OpenMensaAPIService.getInstance().getOpenMensaAPI(); + private static final Calendar currentDate = Calendar.getInstance(); + private static int currentCanteenId = -1; - public static void main(String[] args) { - MenuSelection selection; - /* loop while true to get back to the menu every time an action was performed */ - do { - selection = menu(); - switch (selection) { - case SHOW_CANTEENS: - printCanteens(); - break; - case SET_CANTEEN: - readCanteen(); - break; - case SHOW_MEALS: - printMeals(); - break; - case SET_DATE: - readDate(); - break; - case QUIT: - System.exit(0); + public static void main(String[] args) { + MenuSelection selection; + /* loop while true to get back to the menu every time an action was performed */ + do { + selection = menu(); + switch (selection) { + case SHOW_CANTEENS: + printCanteens(); + break; + case SET_CANTEEN: + readCanteen(); + break; + case SHOW_MEALS: + printMeals(); + break; + case SET_DATE: + readDate(); + break; + case QUIT: + System.exit(0); - } - } while (true); - } + } + } while (true); + } - private static void printCanteens() { - System.out.print("Fetching canteens ["); - /* TODO fetch all canteens and print them to STDOUT - * at first get a page without an index to be able to extract the required pagination information - * afterwards you can iterate the remaining pages - * keep in mind that you should await the process as the user has to select canteen with a specific id */ - } + private static void printCanteens() { + System.out.print("Fetching canteens ["); + /* TODO fetch all canteens and print them to STDOUT + * at first get a page without an index to be able to extract the required pagination information + * afterwards you can iterate the remaining pages + * keep in mind that you should await the process as the user has to select canteen with a specific id */ + } - private static void printMeals() { - /* TODO fetch all meals for the currently selected canteen - * to avoid errors retrieve at first the state of the canteen and check if the canteen is opened at the selected day - * don't forget to check if a canteen was selected previously! */ - } + private static void printMeals() { + /* TODO fetch all meals for the currently selected canteen + * to avoid errors retrieve at first the state of the canteen and check if the canteen is opened at the selected day + * don't forget to check if a canteen was selected previously! */ + } - /** - * Utility method to select a canteen - */ - private static void readCanteen() { - /* typical input reading pattern */ - boolean readCanteenId = false; - do { - try { - System.out.println("Enter canteen id:"); - currentCanteenId = inputScanner.nextInt(); - readCanteenId = true; - }catch (Exception e) { - System.out.println("Sorry could not read the canteen id"); - } - }while (!readCanteenId); - } + /** + * Utility method to select a canteen + */ + private static void readCanteen() { + /* typical input reading pattern */ + boolean readCanteenId = false; + do { + try { + System.out.println("Enter canteen id:"); + currentCanteenId = inputScanner.nextInt(); + readCanteenId = true; + } catch (Exception e) { + System.out.println("Sorry could not read the canteen id"); + } + } while (!readCanteenId); + } - /** - * Utility method to read a date and update the calendar - */ - private static void readDate() { - /* typical input reading pattern */ - boolean readDate = false; - do { - try { - System.out.println("Pleae enter date in the format yyyy-mm-dd:"); - Date d = dateFormat.parse(inputScanner.next()); - currentDate.setTime(d); - readDate = true; - }catch (ParseException p) { - System.out.println("Sorry, the entered date could not be parsed."); - } - }while (!readDate); + /** + * Utility method to read a date and update the calendar + */ + private static void readDate() { + /* typical input reading pattern */ + boolean readDate = false; + do { + try { + System.out.println("Pleae enter date in the format yyyy-mm-dd:"); + Date d = dateFormat.parse(inputScanner.next()); + currentDate.setTime(d); + readDate = true; + } catch (ParseException p) { + System.out.println("Sorry, the entered date could not be parsed."); + } + } while (!readDate); - } + } - /** - * Utility method to print menu and read the user selection - * @return user selection as MenuSelection - */ - private static MenuSelection menu() { - IntStream.range(0, 20).forEach(i -> System.out.print("#")); - System.out.println(); - System.out.println("1) Show canteens"); - System.out.println("2) Set canteen"); - System.out.println("3) Show meals"); - System.out.println("4) Set date"); - System.out.println("5) Quit"); - IntStream.range(0, 20).forEach(i -> System.out.print("#")); - System.out.println(); + /** + * Utility method to print menu and read the user selection + * + * @return user selection as MenuSelection + */ + private static MenuSelection menu() { + IntStream.range(0, 20).forEach(i -> System.out.print("#")); + System.out.println(); + System.out.println("1) Show canteens"); + System.out.println("2) Set canteen"); + System.out.println("3) Show meals"); + System.out.println("4) Set date"); + System.out.println("5) Quit"); + IntStream.range(0, 20).forEach(i -> System.out.print("#")); + System.out.println(); - switch (inputScanner.nextInt()) { - case 1: - return MenuSelection.SHOW_CANTEENS; - case 2: - return MenuSelection.SET_CANTEEN; - case 3: - return MenuSelection.SHOW_MEALS; - case 4: - return MenuSelection.SET_DATE; - default: - return MenuSelection.QUIT; - } - } + switch (inputScanner.nextInt()) { + case 1: + return MenuSelection.SHOW_CANTEENS; + case 2: + return MenuSelection.SET_CANTEEN; + case 3: + return MenuSelection.SHOW_MEALS; + case 4: + return MenuSelection.SET_DATE; + default: + return MenuSelection.QUIT; + } + } } diff --git a/src/main/java/de/thro/inf/prg3/a11/MenuSelection.java b/src/main/java/de/thro/inf/prg3/a11/MenuSelection.java index e6d988124824730bedc94639bd866e526e6db291..5cb37d84da314cbab286cf1b5683b7d4fbb0cbb6 100644 --- a/src/main/java/de/thro/inf/prg3/a11/MenuSelection.java +++ b/src/main/java/de/thro/inf/prg3/a11/MenuSelection.java @@ -5,9 +5,9 @@ package de.thro.inf.prg3.a11; * Created on 12/18/17. */ public enum MenuSelection { - SHOW_CANTEENS, - SET_CANTEEN, - SHOW_MEALS, - SET_DATE, - QUIT + SHOW_CANTEENS, + SET_CANTEEN, + SHOW_MEALS, + SET_DATE, + QUIT } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPI.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPI.java index d3893746ac11f03ec1c348c3c427aa3420b9b437..9e82cff2ed3b986894de7a70a41647f50df8addc 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPI.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPI.java @@ -16,39 +16,43 @@ import java.util.concurrent.CompletableFuture; */ public interface OpenMensaAPI { - /** - * Retrieve the first page of all canteens - * includes the response wrapper to be able to extract required headers for further pagination handling - * @return first page of canteens wrapped in a response object - */ - @GET("canteens") - CompletableFuture<Response<List<Canteen>>> getCanteens(); - - /** - * Retrieve any page of all canteens - * does not include the response wrapper because the required information should be retrieved before this method is used - * @param pageNumber index of the page to retrieve - * @return List of canteens as async future - */ - @GET("canteens") - CompletableFuture<List<Canteen>> getCanteens(@Query("page")int pageNumber); - - /** - * Get the state of a canteen specified by its id at the specified date - * @param canteenId id of the canteen - * @param date date for which the state should be looked up - * @return state of the mensa - may be closed or !closed - */ - @GET("canteens/{canteenId}/days/{date}") - CompletableFuture<State> getCanteenState(@Path("canteenId") int canteenId, @Path("date") String date); - - /** - * Retrieve the meals for specified date served at canteen specified by its id - * @param canteenId id of the canteen - * @param date date for which the meals should be retrieved - * @return List of meals wrapped as async future - */ - @GET("canteens/{canteenId}/days/{date}/meals") - CompletableFuture<List<Meal>> getMeals(@Path("canteenId") int canteenId, @Path("date") String date); + /** + * Retrieve the first page of all canteens + * includes the response wrapper to be able to extract required headers for further pagination handling + * + * @return first page of canteens wrapped in a response object + */ + @GET("canteens") + CompletableFuture<Response<List<Canteen>>> getCanteens(); + + /** + * Retrieve any page of all canteens + * does not include the response wrapper because the required information should be retrieved before this method is used + * + * @param pageNumber index of the page to retrieve + * @return List of canteens as async future + */ + @GET("canteens") + CompletableFuture<List<Canteen>> getCanteens(@Query("page") int pageNumber); + + /** + * Get the state of a canteen specified by its id at the specified date + * + * @param canteenId id of the canteen + * @param date date for which the state should be looked up + * @return state of the mensa - may be closed or !closed + */ + @GET("canteens/{canteenId}/days/{date}") + CompletableFuture<State> getCanteenState(@Path("canteenId") int canteenId, @Path("date") String date); + + /** + * Retrieve the meals for specified date served at canteen specified by its id + * + * @param canteenId id of the canteen + * @param date date for which the meals should be retrieved + * @return List of meals wrapped as async future + */ + @GET("canteens/{canteenId}/days/{date}/meals") + CompletableFuture<List<Meal>> getMeals(@Path("canteenId") int canteenId, @Path("date") String date); } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPIService.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPIService.java index b85303f8b33da5954767f8306441fbc2e0a05a09..317e8207c8a0347fad24d2bbe8e495d454e1bfee 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPIService.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/OpenMensaAPIService.java @@ -6,32 +6,33 @@ import retrofit2.converter.gson.GsonConverterFactory; /** * OpenMensaAPI service * holds an instance of OpenMensaAPI to avoid multiple instantiations of the API + * * @author Peter Kurfer */ public final class OpenMensaAPIService { - /* singleton instance */ - private static final OpenMensaAPIService ourInstance = new OpenMensaAPIService(); - private final OpenMensaAPI openMensaAPI; + /* singleton instance */ + private static final OpenMensaAPIService ourInstance = new OpenMensaAPIService(); + private final OpenMensaAPI openMensaAPI; - /* singleton accessor */ - public static OpenMensaAPIService getInstance() { - return ourInstance; - } + private OpenMensaAPIService() { - private OpenMensaAPIService() { + /* Initialize Retrofit */ + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("http://openmensa.org/api/v2/") + .addConverterFactory(GsonConverterFactory.create()) + .build(); - /* Initialize Retrofit */ - Retrofit retrofit = new Retrofit.Builder() - .baseUrl("http://openmensa.org/api/v2/") - .addConverterFactory(GsonConverterFactory.create()) - .build(); + openMensaAPI = retrofit.create(OpenMensaAPI.class); + } - openMensaAPI = retrofit.create(OpenMensaAPI.class); - } + /* singleton accessor */ + public static OpenMensaAPIService getInstance() { + return ourInstance; + } - public OpenMensaAPI getOpenMensaAPI() { - return openMensaAPI; - } + public OpenMensaAPI getOpenMensaAPI() { + return openMensaAPI; + } } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Canteen.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Canteen.java index 55c9733bc0153f970a705414af6554e25dd1efeb..966939d32044dd8dd4122ee80b8549b15cba7076 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Canteen.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Canteen.java @@ -5,86 +5,87 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; /** * Data transfer object for a canteen retrieved from the OpenMensaAPI + * * @author Peter Kurfer */ public final class Canteen { - private int id; - private String name; - private String city; - private String address; - private double[] coordinates; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public double[] getCoordinates() { - return coordinates; - } - - public void setCoordinates(double[] coordinates) { - this.coordinates = coordinates; - } - - @Override - public String toString() { - return String.format("%s\t%s", getId(), getName()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - - if (!(o instanceof Canteen)) return false; - - Canteen canteen = (Canteen) o; - - return new EqualsBuilder() - .append(getId(), canteen.getId()) - .append(getName(), canteen.getName()) - .append(getCity(), canteen.getCity()) - .append(getAddress(), canteen.getAddress()) - .append(getCoordinates(), canteen.getCoordinates()) - .isEquals(); - } - - @Override - public int hashCode() { - return new HashCodeBuilder(17, 37) - .append(getId()) - .append(getName()) - .append(getCity()) - .append(getAddress()) - .append(getCoordinates()) - .toHashCode(); - } + private int id; + private String name; + private String city; + private String address; + private double[] coordinates; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public double[] getCoordinates() { + return coordinates; + } + + public void setCoordinates(double[] coordinates) { + this.coordinates = coordinates; + } + + @Override + public String toString() { + return String.format("%s\t%s", getId(), getName()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (!(o instanceof Canteen)) return false; + + Canteen canteen = (Canteen) o; + + return new EqualsBuilder() + .append(getId(), canteen.getId()) + .append(getName(), canteen.getName()) + .append(getCity(), canteen.getCity()) + .append(getAddress(), canteen.getAddress()) + .append(getCoordinates(), canteen.getCoordinates()) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(getId()) + .append(getName()) + .append(getCity()) + .append(getAddress()) + .append(getCoordinates()) + .toHashCode(); + } } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Meal.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Meal.java index 62ec1ac35543095c0fe616e6143cb32979499a6d..ef67ebd578cbb3b944e0605b4ede4412fded121f 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Meal.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/Meal.java @@ -8,79 +8,80 @@ import java.util.List; /** * Data transfer object for a meal retrieved from the OpenMensaAPI + * * @author Peter Kurfer */ public final class Meal { - private int id; - private String name; - private String category; - private List<String> notes; - - public Meal() { - notes = new LinkedList<>(); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCategory() { - return category; - } - - public void setCategory(String category) { - this.category = category; - } - - public List<String> getNotes() { - return notes; - } - - public void setNotes(List<String> notes) { - this.notes = notes; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - - if (!(o instanceof Meal)) return false; - - Meal meal = (Meal) o; - - return new EqualsBuilder() - .append(getId(), meal.getId()) - .append(getName(), meal.getName()) - .append(getCategory(), meal.getCategory()) - .append(getNotes(), meal.getNotes()) - .isEquals(); - } - - @Override - public int hashCode() { - return new HashCodeBuilder(17, 37) - .append(getId()) - .append(getName()) - .append(getCategory()) - .append(getNotes()) - .toHashCode(); - } - - @Override - public String toString() { - return name; - } + private int id; + private String name; + private String category; + private List<String> notes; + + public Meal() { + notes = new LinkedList<>(); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public List<String> getNotes() { + return notes; + } + + public void setNotes(List<String> notes) { + this.notes = notes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (!(o instanceof Meal)) return false; + + Meal meal = (Meal) o; + + return new EqualsBuilder() + .append(getId(), meal.getId()) + .append(getName(), meal.getName()) + .append(getCategory(), meal.getCategory()) + .append(getNotes(), meal.getNotes()) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(getId()) + .append(getName()) + .append(getCategory()) + .append(getNotes()) + .toHashCode(); + } + + @Override + public String toString() { + return name; + } } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/PageInfo.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/PageInfo.java index 89106c36e34545655cb6630b3e43fa7b1cc717a7..8b0579bfa793779deb2687c047acc2fded80eca3 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/PageInfo.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/PageInfo.java @@ -12,74 +12,74 @@ import retrofit2.Response; public final class PageInfo { - private static final String TOTAL_PAGES_HEADER = "X-Total-Pages"; - private static final String TOTAL_ITEM_COUNT_HEADER = "X-Total-Count"; - private static final String ITEM_COUNT_PER_PAGE_HEADER = "X-Per-Page"; - private static final String CURRENT_PAGE_INDEX_HEADER = "X-Current-Page"; + private static final String TOTAL_PAGES_HEADER = "X-Total-Pages"; + private static final String TOTAL_ITEM_COUNT_HEADER = "X-Total-Count"; + private static final String ITEM_COUNT_PER_PAGE_HEADER = "X-Per-Page"; + private static final String CURRENT_PAGE_INDEX_HEADER = "X-Current-Page"; - private final int totalCountOfPages; - private final int totalCountOfItems; - private final int itemCountPerPage; - private final int currentPageIndex; + private final int totalCountOfPages; + private final int totalCountOfItems; + private final int itemCountPerPage; + private final int currentPageIndex; - /** - * Default constructor - * only used by 'factory method' `extractFromReponse(...)` - */ - private PageInfo(int totalCountOfPages, int totalCountOfItems, int itemCountPerPage, int currentPageIndex) { - this.totalCountOfPages = totalCountOfPages; - this.totalCountOfItems = totalCountOfItems; - this.itemCountPerPage = itemCountPerPage; - this.currentPageIndex = currentPageIndex; - } + /** + * Default constructor + * only used by 'factory method' `extractFromReponse(...)` + */ + private PageInfo(int totalCountOfPages, int totalCountOfItems, int itemCountPerPage, int currentPageIndex) { + this.totalCountOfPages = totalCountOfPages; + this.totalCountOfItems = totalCountOfItems; + this.itemCountPerPage = itemCountPerPage; + this.currentPageIndex = currentPageIndex; + } - /** - * @return total count of pages or -1 if required header was not present - */ - public int getTotalCountOfPages() { - return totalCountOfPages; - } + /** + * Factory method to create a PageInfo by parsing the headers of a response which includes the required information + * + * @param apiResponse response object to parse + * @param <T> concrete response type + * @return PageInfo instance - may contain default fallback values see getters + */ + public static <T extends Response<?>> PageInfo extractFromResponse(T apiResponse) { + Headers headers = apiResponse.headers(); + int totalPages = extractFromHeaders(headers, TOTAL_PAGES_HEADER, -1); + int totalItemCount = extractFromHeaders(headers, TOTAL_ITEM_COUNT_HEADER, -1); + int itemCountPerPage = extractFromHeaders(headers, ITEM_COUNT_PER_PAGE_HEADER, -1); + int currentPageIndex = extractFromHeaders(headers, CURRENT_PAGE_INDEX_HEADER, -1); - /** - * @return total item count or -1 if required header was not present - */ - public int getTotalCountOfItems() { - return totalCountOfItems; - } + return new PageInfo(totalPages, totalItemCount, itemCountPerPage, currentPageIndex); + } - /** - * @return item count on every page or -1 if required header was not present - */ - public int getItemCountPerPage() { - return itemCountPerPage; - } + private static int extractFromHeaders(Headers headers, String headerName, int fallback) { + String headerValue = headers.get(headerName); + return headerValue == null ? fallback : Integer.parseInt(headerValue); + } - /** - * @return current page index or -1 if required header was not present - */ - public int getCurrentPageIndex() { - return currentPageIndex; - } + /** + * @return total count of pages or -1 if required header was not present + */ + public int getTotalCountOfPages() { + return totalCountOfPages; + } - /** - * Factory method to create a PageInfo by parsing the headers of a response which includes the required information - * - * @param apiResponse response object to parse - * @param <T> concrete response type - * @return PageInfo instance - may contain default fallback values see getters - */ - public static <T extends Response<?>> PageInfo extractFromResponse(T apiResponse) { - Headers headers = apiResponse.headers(); - int totalPages = extractFromHeaders(headers, TOTAL_PAGES_HEADER, -1); - int totalItemCount = extractFromHeaders(headers, TOTAL_ITEM_COUNT_HEADER, -1); - int itemCountPerPage = extractFromHeaders(headers, ITEM_COUNT_PER_PAGE_HEADER, -1); - int currentPageIndex = extractFromHeaders(headers, CURRENT_PAGE_INDEX_HEADER, -1); + /** + * @return total item count or -1 if required header was not present + */ + public int getTotalCountOfItems() { + return totalCountOfItems; + } - return new PageInfo(totalPages, totalItemCount, itemCountPerPage, currentPageIndex); - } + /** + * @return item count on every page or -1 if required header was not present + */ + public int getItemCountPerPage() { + return itemCountPerPage; + } - private static int extractFromHeaders(Headers headers, String headerName, int fallback) { - String headerValue = headers.get(headerName); - return headerValue == null ? fallback : Integer.parseInt(headerValue); - } + /** + * @return current page index or -1 if required header was not present + */ + public int getCurrentPageIndex() { + return currentPageIndex; + } } diff --git a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/State.java b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/State.java index 9febe811b2cc4e653df1de2400ea4b43c463a1a0..0eb236a76b8c5bf2ae8db1154c70cfb9551505ce 100644 --- a/src/main/java/de/thro/inf/prg3/a11/openmensa/model/State.java +++ b/src/main/java/de/thro/inf/prg3/a11/openmensa/model/State.java @@ -6,61 +6,62 @@ import org.apache.commons.lang3.builder.ToStringBuilder; /** * Data transfer object for a state of a canteen retrieved from the OpenMensaAPI + * * @author Peter Kurfer */ public final class State { - private String date; - private boolean closed = true; + private String date; + private boolean closed = true; - public State() { - date = ""; - } + public State() { + date = ""; + } - public String getDate() { - return date; - } + public String getDate() { + return date; + } - public void setDate(String date) { - this.date = date; - } + public void setDate(String date) { + this.date = date; + } - public boolean isClosed() { - return closed; - } + public boolean isClosed() { + return closed; + } - public void setClosed(boolean closed) { - this.closed = closed; - } + public void setClosed(boolean closed) { + this.closed = closed; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; + @Override + public boolean equals(Object o) { + if (this == o) return true; - if (!(o instanceof State)) return false; + if (!(o instanceof State)) return false; - State state = (State) o; + State state = (State) o; - return new EqualsBuilder() - .append(isClosed(), state.isClosed()) - .append(getDate(), state.getDate()) - .isEquals(); - } + return new EqualsBuilder() + .append(isClosed(), state.isClosed()) + .append(getDate(), state.getDate()) + .isEquals(); + } - @Override - public int hashCode() { - return new HashCodeBuilder(17, 37) - .append(getDate()) - .append(isClosed()) - .toHashCode(); - } + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(getDate()) + .append(isClosed()) + .toHashCode(); + } - @Override - public String toString() { - return new ToStringBuilder(this) - .append("date", date) - .append("closed", closed) - .toString(); - } + @Override + public String toString() { + return new ToStringBuilder(this) + .append("date", date) + .append("closed", closed) + .toString(); + } } diff --git a/src/test/java/de/thro/inf/prg3/a11/tests/OpenMensaApiTests.java b/src/test/java/de/thro/inf/prg3/a11/tests/OpenMensaApiTests.java index d52e90d7d025cdf7d009d58f96e4c8ca12b36e4f..6d546dffb2a411ced753972744495f808d5eb857 100644 --- a/src/test/java/de/thro/inf/prg3/a11/tests/OpenMensaApiTests.java +++ b/src/test/java/de/thro/inf/prg3/a11/tests/OpenMensaApiTests.java @@ -3,7 +3,10 @@ package de.thro.inf.prg3.a11.tests; import de.thro.inf.prg3.a11.openmensa.OpenMensaAPI; import de.thro.inf.prg3.a11.openmensa.OpenMensaAPIService; import de.thro.inf.prg3.a11.openmensa.model.PageInfo; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import retrofit2.HttpException; import java.text.SimpleDateFormat; @@ -16,72 +19,78 @@ import static org.junit.jupiter.api.Assertions.*; /** * @author Peter Kurfer */ - +@TestInstance(TestInstance.Lifecycle.PER_METHOD) class OpenMensaApiTests { - private static final int THRO_MENSA_ID = 229; - private static final String OPEN_MENSA_DATE_FORMAT = "yyyy-MM-dd"; - private final SimpleDateFormat dateFormat; - private final OpenMensaAPI openMensaAPI; - private final Calendar calendar; - - OpenMensaApiTests() { - dateFormat = new SimpleDateFormat(OPEN_MENSA_DATE_FORMAT, Locale.getDefault()); - openMensaAPI = OpenMensaAPIService.getInstance().getOpenMensaAPI(); - calendar = Calendar.getInstance(); - } - - @Test - void testGetFirstMensaPage() throws ExecutionException, InterruptedException { - final var canteensResponse = openMensaAPI.getCanteens().get(); - - assertNotNull(canteensResponse); - assertNotNull(canteensResponse.body()); - assertNotEquals(0, canteensResponse.body().size()); - - for (var c : canteensResponse.body()) { - System.out.println(c.getName()); - } - } - - @Test - void testExtractPageInfo() throws ExecutionException, InterruptedException { - final var canteensResponse = openMensaAPI.getCanteens().get(); - - final var pageInfo = PageInfo.extractFromResponse(canteensResponse); - - assertNotNull(pageInfo); - assertEquals(canteensResponse.body().size(), pageInfo.getItemCountPerPage()); - assertTrue(pageInfo.getTotalCountOfItems() > 0); - assertTrue(pageInfo.getTotalCountOfPages() > 0); - assertTrue(pageInfo.getCurrentPageIndex() > 0); - } - - @Test - void testGetCanteenState() throws InterruptedException { - try { - final var mensaState = openMensaAPI.getCanteenState(THRO_MENSA_ID, dateFormat.format(calendar.getTime())).get(); - assertNotNull(mensaState); - }catch (ExecutionException e) { - if(e.getCause() instanceof HttpException) { - System.out.println(String.format("HTTP error: %s", e.getCause().getMessage())); - } - } - } - - - @Test - void testGetMultiplePages() throws ExecutionException, InterruptedException { - final var firstPage = openMensaAPI.getCanteens().get(); - - assertNotNull(firstPage); - assertNotNull(firstPage.body()); - - final var pageInfo = PageInfo.extractFromResponse(firstPage); - for(var i = 2; i <= pageInfo.getTotalCountOfPages(); i++) { - var canteensPage = openMensaAPI.getCanteens(i).get(); - assertNotNull(canteensPage); - assertNotEquals(0, canteensPage.size()); - } - } + private static final Logger logger = LogManager.getLogger(OpenMensaApiTests.class); + private static final int THRO_MENSA_ID = 229; + private static final String OPEN_MENSA_DATE_FORMAT = "yyyy-MM-dd"; + private static final SimpleDateFormat dateFormat = new SimpleDateFormat(OPEN_MENSA_DATE_FORMAT, Locale.getDefault()); + + private final OpenMensaAPI openMensaAPI; + private final Calendar calendar; + + OpenMensaApiTests() { + openMensaAPI = OpenMensaAPIService + .getInstance() + .getOpenMensaAPI(); + + calendar = Calendar.getInstance(); + } + + @Test + void testGetFirstMensaPage() throws ExecutionException, InterruptedException { + final var canteensResponse = openMensaAPI.getCanteens().get(); + + assertNotNull(canteensResponse); + assertNotNull(canteensResponse.body()); + assertNotEquals(0, canteensResponse.body().size()); + + for (var c : canteensResponse.body()) { + logger.info(c.getName()); + } + } + + @Test + void testExtractPageInfo() throws ExecutionException, InterruptedException { + final var canteensResponse = openMensaAPI.getCanteens().get(); + + final var pageInfo = PageInfo.extractFromResponse(canteensResponse); + + assertNotNull(pageInfo); + assertEquals(canteensResponse.body().size(), pageInfo.getItemCountPerPage()); + assertTrue(pageInfo.getTotalCountOfItems() > 0); + assertTrue(pageInfo.getTotalCountOfPages() > 0); + assertTrue(pageInfo.getCurrentPageIndex() > 0); + } + + @Test + void testGetCanteenState() throws InterruptedException { + try { + var date = dateFormat.format(calendar.getTime()); + logger.info("Fetching canteen state for date {}", date); + final var mensaState = openMensaAPI.getCanteenState(THRO_MENSA_ID, date).get(); + assertNotNull(mensaState); + } catch (ExecutionException e) { + if (e.getCause() instanceof HttpException) { + logger.info("HTTP error: {}", e.getCause().getMessage()); + } + } + } + + + @Test + void testGetMultiplePages() throws ExecutionException, InterruptedException { + final var firstPage = openMensaAPI.getCanteens().get(); + + assertNotNull(firstPage); + assertNotNull(firstPage.body()); + + final var pageInfo = PageInfo.extractFromResponse(firstPage); + for (var i = 2; i <= pageInfo.getTotalCountOfPages(); i++) { + var canteensPage = openMensaAPI.getCanteens(i).get(); + assertNotNull(canteensPage); + assertNotEquals(0, canteensPage.size()); + } + } } diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..2628b03e42c67a69646b16714d6af9fd7b65f3e2 --- /dev/null +++ b/src/test/resources/log4j2.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration status="WARN"> + <Appenders> + <Console name="Console" target="SYSTEM_OUT"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> + </Console> + </Appenders> + <Loggers> + <Root level="all"> + <AppenderRef ref="Console"/> + </Root> + </Loggers> +</Configuration>