commit f8a4952127dab7fcfd166f0f5fa67e3f39a6a61f Author: mms37 Date: Fri Jul 29 11:30:15 2022 -0700 initial diff --git a/a4.pdf b/a4.pdf new file mode 100644 index 0000000..6f9d85e Binary files /dev/null and b/a4.pdf differ diff --git a/assignment4/.idea/.gitignore b/assignment4/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/assignment4/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/assignment4/.idea/libraries/github_lgooddatepicker_LGoodDatePicker.xml b/assignment4/.idea/libraries/github_lgooddatepicker_LGoodDatePicker.xml new file mode 100644 index 0000000..e807631 --- /dev/null +++ b/assignment4/.idea/libraries/github_lgooddatepicker_LGoodDatePicker.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/assignment4/.idea/libraries/google_code_gson.xml b/assignment4/.idea/libraries/google_code_gson.xml new file mode 100644 index 0000000..b8c8e54 --- /dev/null +++ b/assignment4/.idea/libraries/google_code_gson.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/assignment4/.idea/misc.xml b/assignment4/.idea/misc.xml new file mode 100644 index 0000000..a346fd7 --- /dev/null +++ b/assignment4/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assignment4/.idea/modules.xml b/assignment4/.idea/modules.xml new file mode 100644 index 0000000..8ec0827 --- /dev/null +++ b/assignment4/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/assignment4/.idea/uiDesigner.xml b/assignment4/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/assignment4/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assignment4/.idea/vcs.xml b/assignment4/.idea/vcs.xml new file mode 100644 index 0000000..4fce1d8 --- /dev/null +++ b/assignment4/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assignment4/assignment4.iml b/assignment4/assignment4.iml new file mode 100644 index 0000000..0140e85 --- /dev/null +++ b/assignment4/assignment4.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assignment4/list.json b/assignment4/list.json new file mode 100644 index 0000000..7cab810 --- /dev/null +++ b/assignment4/list.json @@ -0,0 +1 @@ +[{"author":"test","name":"test","note":"","price":12.0,"weight":12.0,"expectedDate":"2022-07-29T12:01","delivered":false,"type":"book"}] \ No newline at end of file diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/Main.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/Main.class new file mode 100644 index 0000000..0c61cd1 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/Main.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$1.class new file mode 100644 index 0000000..5e84cea Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$2.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$2.class new file mode 100644 index 0000000..7972855 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker$2.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.class new file mode 100644 index 0000000..30bd6ed Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$1.class new file mode 100644 index 0000000..067ff04 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$2.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$2.class new file mode 100644 index 0000000..8ac17c6 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$2.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$3.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$3.class new file mode 100644 index 0000000..516a9bf Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType$3.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType.class new file mode 100644 index 0000000..c2ccfaf Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory$PackageType.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.class new file mode 100644 index 0000000..84858d3 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory$1.class new file mode 100644 index 0000000..dd36b30 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.class new file mode 100644 index 0000000..c669e81 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.class new file mode 100644 index 0000000..5dffbe1 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.class new file mode 100644 index 0000000..bd0723f Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.class new file mode 100644 index 0000000..474d288 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.class new file mode 100644 index 0000000..8ec5e79 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1$1.class new file mode 100644 index 0000000..f6df2cd Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1.class new file mode 100644 index 0000000..49966f9 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input.class new file mode 100644 index 0000000..3c6c280 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/Input.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$1.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$1.class new file mode 100644 index 0000000..f50722e Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$1.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$2.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$2.class new file mode 100644 index 0000000..9dca741 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$2.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$3.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$3.class new file mode 100644 index 0000000..a4f1977 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$3.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$4.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$4.class new file mode 100644 index 0000000..9ae04d0 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$4.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$PACKAGE_FILTER_OPTION.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$PACKAGE_FILTER_OPTION.class new file mode 100644 index 0000000..aaee344 Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI$PACKAGE_FILTER_OPTION.class differ diff --git a/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.class b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.class new file mode 100644 index 0000000..de8ca7b Binary files /dev/null and b/assignment4/out/production/assignment4/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.class differ diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/Main.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/Main.java new file mode 100644 index 0000000..a280543 --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/Main.java @@ -0,0 +1,15 @@ +package cmpt213.assignment4.packagedeliveries.client; + +import cmpt213.assignment4.packagedeliveries.client.view.JavaSwingUI; + +import javax.swing.*; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + SwingUtilities.invokeLater(() -> { + JavaSwingUI ui = new JavaSwingUI(); + ui.displayMainPage(); + }); + } +} diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.java new file mode 100644 index 0000000..4211ee8 --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageDeliveriesTracker.java @@ -0,0 +1,206 @@ +package cmpt213.assignment4.packagedeliveries.client.control; + +import cmpt213.assignment4.packagedeliveries.client.gson.extras.RuntimeTypeAdapterFactory; +import cmpt213.assignment4.packagedeliveries.client.model.BookPackage; +import cmpt213.assignment4.packagedeliveries.client.model.ElectronicPackage; +import cmpt213.assignment4.packagedeliveries.client.model.PackageInfo; +import cmpt213.assignment4.packagedeliveries.client.model.PerishablePackage; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.*; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; + +/** + * It's a class that contains a main method that creates a TextMenu object, loads a list of packages + * from a file, and then loops through a menu of options until the user chooses to quit + */ +public class PackageDeliveriesTracker { + private static final String fileName = "list.json"; + private static final RuntimeTypeAdapterFactory r = RuntimeTypeAdapterFactory.of(PackageInfo.class, "type") + .registerSubtype(BookPackage.class, "book") + .registerSubtype(PerishablePackage.class, "perishable") + .registerSubtype(ElectronicPackage.class, "electronic"); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, + new TypeAdapter() { + @Override + public void write(JsonWriter jsonWriter, + LocalDateTime localDateTime) throws IOException { + jsonWriter.value(localDateTime.toString()); + } + + @Override + public LocalDateTime read(JsonReader jsonReader) throws IOException { + return LocalDateTime.parse(jsonReader.nextString()); + } + }).registerTypeAdapterFactory(r).create(); + private static ArrayList packageList = new ArrayList<>(); + + private static PackageDeliveriesTracker instance; + + public static PackageDeliveriesTracker getInstance() { + if (instance == null) { + instance = new PackageDeliveriesTracker(); + } + return instance; + } + + public void addPackage(PackageInfo p) { + packageList.add(p); + Collections.sort(packageList); + } + + /** + * It saves the packageList to a file. + */ + public void save() { + try { + Writer w = new FileWriter(fileName); + gson.toJson(packageList, w); + w.flush(); + w.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * It reads the json file, converts it to a list of PackageInfo objects, and then sets the type of + * each object to the appropriate type + */ + public void load() { + //File file = new File(fileName); + try { + String json = Files.readString(Paths.get(fileName)); + Type lType = new TypeToken>() { + }.getType(); + packageList = gson.fromJson(json, lType); + for (PackageInfo p : packageList) { + if (p instanceof BookPackage) { + p.setType("book"); + } else if (p instanceof PerishablePackage) { + p.setType("perishable"); + } else if (p instanceof ElectronicPackage) { + p.setType("electronic"); + } + } + System.out.println("packages loaded"); + } catch (FileNotFoundException e) { + System.out.println("no packages to load"); + } catch (NoSuchFileException e) { + createFile(); + //throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void createFile() { + System.out.println("CreateFile"); + try { + File packages = new File(fileName); + if(packages.createNewFile()) { + System.out.println("New file list.json created"); + } + } + catch (IOException e) { + System.out.println("No file exists, creating a new file"); + e.printStackTrace(); + } + } + + public ArrayList getAllPackages() { + ArrayList b = new ArrayList<>(); + if (packageList.size() == 0) { + b.add("No packages to show"); + } else { + Collections.sort(packageList); + for (int i = 0; i < packageList.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + packageList.get(i) + "\n\n"; + b.add(bString); + } + } + return b; + } + + /** + * This function takes in a list of packages, a boolean for whether or not the user wants to see + * packages that are due, and a boolean for whether or not the user wants to see all packages. It + * then returns a list of packages that are sorted by their expected delivery date + * + * @param pList the list of packages to be sorted + * @param due true if you want to sort the list by due date, false if you want to sort the list by + * expected date + * @return An ArrayList of PackageInfo objects. + */ + //due=true returns overdue packages, else upcoming packages + public ArrayList sortList(ArrayList pList, boolean due) { + ArrayList sortedList = new ArrayList<>(); + LocalDateTime today = LocalDateTime.now(); + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + today.format(format); + for (int i = 0; i < pList.size(); i++) { + PackageInfo p = pList.get(i); + if (!p.getDelivered()) { + if (due && today.isAfter(p.getExpectedDate())) { + sortedList.add(p); + } else if (!due && today.isBefore(p.getExpectedDate())) { + sortedList.add(p); + } + } + } + Collections.sort(sortedList); + return sortedList; + } + + public ArrayList overDuePackages() { + ArrayList b = new ArrayList<>(); + ArrayList overdue = sortList(packageList, true); + if (overdue.size() == 0) { + b.add("no overdue packages to show"); + } + for (int i = 0; i < overdue.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + overdue.get(i) + "\n\n"; + b.add(bString); + } + return b; + } + + public ArrayList upcomingPackages() { + ArrayList b = new ArrayList<>(); + ArrayList upcoming = sortList(packageList, false); + if (upcoming.size() == 0) { + b.add("no upcoming packages to show"); + } + for (int i = 0; i < upcoming.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + upcoming.get(i) + "\n\n"; + b.add(bString); + } + return b; + } + + public void removePcakage(int i) { + packageList.remove(i); + } + + public boolean isDelivered(int i) { + return packageList.get(i).getDelivered(); + } + + public void setDelivered(int i) { + packageList.get(i).setDelivered(true); + } + +} + diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.java new file mode 100644 index 0000000..e656809 --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/control/PackageFactory.java @@ -0,0 +1,73 @@ +package cmpt213.assignment4.packagedeliveries.client.control; + +import cmpt213.assignment4.packagedeliveries.client.model.BookPackage; +import cmpt213.assignment4.packagedeliveries.client.model.ElectronicPackage; +import cmpt213.assignment4.packagedeliveries.client.model.PackageInfo; +import cmpt213.assignment4.packagedeliveries.client.model.PerishablePackage; + +import java.time.LocalDateTime; + +/** + * The PackageFactory class is a factory class that creates a package object based on the type of + * package that is passed in + */ +public class PackageFactory { + /** + * > This function creates a new package object based on the package type + * + * @param type The type of package. + * @param name The name of the package. + * @param notes A string of notes about the package. + * @param price The price of the package + * @param weight The weight of the package in kilograms + * @param delivered Whether or not the package has been delivered + * @param expectDate The date the package is expected to be delivered. + * @param author The author of the book. + * @param expiryDate The date the package expires. + * @param handlingFee The handling fee for the package. + * @return A new instance of the package type. + */ + + public static PackageInfo create(PackageType type, String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectDate, String author, LocalDateTime expiryDate, double handlingFee) { + return type.getInstance(name, notes, price, weight, delivered, expectDate, author, expiryDate, handlingFee); + } + + // Creating an enum called PackageType. + public enum PackageType { + Book { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new BookPackage(name, notes, price, weight, delivered, expectedDate, author); + } + }, + + Perishable { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new PerishablePackage(name, notes, price, weight, delivered, expectedDate, expiryDate); + } + }, + + Electronic { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new ElectronicPackage(name, notes, price, weight, delivered, expectedDate, handlingFee); + } + }; + + /** + * It returns a PackageInfo object. + * + * @param name The name of the package. + * @param notes a string that describes the package + * @param price The price of the package + * @param weight the weight of the package in kg + * @param delivered true if the package has been delivered, false otherwise + * @param expectedDate The date the package is expected to be delivered. + * @param author The name of the author of the book. + * @param expiryDate The date when the package expires. + * @param handlingFee The handling fee for the package. + * @return A package object + */ + + public abstract PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee); + } + +} \ No newline at end of file diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..cf6d6fe --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/gson/extras/RuntimeTypeAdapterFactory.java @@ -0,0 +1,256 @@ +package cmpt213.assignment4.packagedeliveries.client.gson.extras; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ * + *

Serialization and deserialization

+ * In order to serialize and deserialize a polymorphic object, + * you must specify the base type explicitly. + *
   {@code
+ *   Diamond diamond = new Diamond();
+ *   String json = gson.toJson(diamond, Shape.class);
+ * }
+ * And then: + *
   {@code
+ *   Shape shape = gson.fromJson(json, Shape.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap<>(); + private final Map, String> subtypeToLabel = new LinkedHashMap<>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory<>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final TypeAdapter jsonElementAdapter = gson.getAdapter(JsonElement.class); + final Map> labelToDelegate = new LinkedHashMap<>(); + final Map, TypeAdapter> subtypeToDelegate = new LinkedHashMap<>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = jsonElementAdapter.read(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + jsonElementAdapter.write(out, jsonObject); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + jsonElementAdapter.write(out, clone); + } + }.nullSafe(); + } +} \ No newline at end of file diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.java new file mode 100644 index 0000000..faaf61d --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/BookPackage.java @@ -0,0 +1,23 @@ +package cmpt213.assignment4.packagedeliveries.client.model; + +import java.time.LocalDateTime; + +/** + * It's a subclass of PackageInfo that adds an author field + */ +public class BookPackage extends PackageInfo { + String author; + + public BookPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) { + + super(name, note, price, weight, delivered, expectedDate); + this.author = author; + this.setType("book"); + } + + @Override + public String toString() { + return super.toString() + "\nAuthor: " + author; + } +} + diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.java new file mode 100644 index 0000000..11711a9 --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/ElectronicPackage.java @@ -0,0 +1,21 @@ +package cmpt213.assignment4.packagedeliveries.client.model; + +import java.time.LocalDateTime; + +/** + * ElectronicPackage is a subclass of PackageInfo that adds a handlingFee attribute + */ +public class ElectronicPackage extends PackageInfo { + double handlingFee; + + public ElectronicPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee) { + super(name, note, price, weight, delivered, expectedDate); + this.handlingFee = handlingFee; + this.setType("electronic"); + } + + @Override + public String toString() { + return super.toString() + "\nHandling fee: " + handlingFee; + } +} diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.java new file mode 100644 index 0000000..682abf1 --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PackageInfo.java @@ -0,0 +1,85 @@ +package cmpt213.assignment4.packagedeliveries.client.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import static java.lang.Math.abs; + +/** + * PackageInfo is a class that contains information about a package + */ + +public class PackageInfo implements Comparable { + private final String name; + private final String note; + private final double price; + private final double weight; + private final LocalDateTime expectedDate; + private boolean delivered; + private String type; + + public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) { + this.name = name; + this.note = note; + this.price = price; + this.weight = weight; + this.delivered = delivered; + this.expectedDate = expectedDate; + } + + /** + * This function returns the name of the person. + * + * @return The name of the person. + */ + public String getName() { + return name; + } + + + public boolean getDelivered() { + return delivered; + } + + /** + * This function sets the value of the delivered variable to the value of the delivered parameter. + * + * @param delivered This is a boolean value that indicates whether the message has been delivered + * to the recipient. + */ + public void setDelivered(boolean delivered) { + this.delivered = delivered; + } + + public LocalDateTime getExpectedDate() { + return expectedDate; + } + + /** + * This function sets the type of the object to the type passed in as a parameter + * + * @param type The type of the event. + */ + public void setType(String type) { + this.type = type; + } + + // Comparing the expected date of the package to the expected date of the package passed in as a + // parameter. + @Override + public int compareTo(PackageInfo p) { + return this.expectedDate.compareTo(p.getExpectedDate()); + } + + // Overriding the toString method. + @Override + public String toString() { + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + LocalDateTime today = LocalDateTime.now(); + today.format(format); + long diff = ChronoUnit.DAYS.between(today, expectedDate); + String isDelivered = delivered ? "yes" : "no"; + return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: $" + price + "\n" + "Weight: " + weight + " kg" + "\n" + "Expected Delivery Date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expectedDate) + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue"); + } +} diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.java new file mode 100644 index 0000000..aac171e --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/model/PerishablePackage.java @@ -0,0 +1,24 @@ +package cmpt213.assignment4.packagedeliveries.client.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * It's a subclass of PackageInfo that adds an expiry date + */ +public class PerishablePackage extends PackageInfo { + LocalDateTime expiryDate; + + // It's a constructor that initializes the object with the given parameters. + public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) { + super(name, note, price, weight, delivered, expectedDate); + this.expiryDate = expiryDate; + this.setType("perishable"); + } + + // It's a method that returns a string representation of the object. + @Override + public String toString() { + return super.toString() + "\nExpiry date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expiryDate); + } +} diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/Input.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/Input.java new file mode 100644 index 0000000..7eade3b --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/Input.java @@ -0,0 +1,238 @@ +package cmpt213.assignment4.packagedeliveries.client.view; + + +import cmpt213.assignment4.packagedeliveries.client.control.PackageDeliveriesTracker; +import cmpt213.assignment4.packagedeliveries.client.control.PackageFactory; +import cmpt213.assignment4.packagedeliveries.client.model.PackageInfo; +import com.github.lgooddatepicker.components.DateTimePicker; +import com.github.lgooddatepicker.optionalusertools.DateTimeChangeListener; +import com.github.lgooddatepicker.zinternaltools.DateTimeChangeEvent; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.time.LocalDateTime; + +public class Input extends JDialog implements ActionListener, DateTimeChangeListener { + private final PackageDeliveriesTracker pInstance = PackageDeliveriesTracker.getInstance(); + private final JLabel typeLabel; + private final JPanel typePanel; + private final JTextField typeTf; + private final DateTimePicker dd; + private final DateTimePicker ed; + private LocalDateTime deliveryDate, expiryDate; + private final JTextField nameField; + private final JTextField noteField; + private final JTextField priceField; + private final JTextField weightField; + private final JTextField dateField; + private int pType; + + public Input(Frame main) { + super(main, "add a package", true); + JPanel p = new JPanel(); + p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); + String[] type = {"book", "perishable", "electronic"}; + + JComboBox packageType = new JComboBox<>(type); + packageType.setPreferredSize(new Dimension(300, 30)); + packageType.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String p = (String) packageType.getSelectedItem(); + switch (p) { + case "book": + typeTf.setVisible(true); + ed.setVisible(false); + typeLabel.setText("author name"); + pType = 0; + break; + case "perishable": + typeTf.setVisible(false); + ed.setVisible(true); + ed.addDateTimeChangeListener(new DateTimeChangeListener() { + @Override + public void dateOrTimeChanged(DateTimeChangeEvent dateTimeChangeEvent) { + expiryDate = ed.getDateTimePermissive(); + } + }); + typePanel.add(ed); + typeLabel.setText("expiry date"); + pType = 1; + break; + case "electronic": + typeTf.setVisible(true); + ed.setVisible(false); + typeLabel.setText("handling fee"); + pType = 2; + } + } + }); + // Panel for package name + nameField = new JTextField(); + JPanel name = new JPanel(); + JLabel nameLabel = new JLabel(); + name.setLayout(new BoxLayout(name, BoxLayout.X_AXIS)); + nameLabel.setText("name:"); + nameLabel.setPreferredSize(new Dimension(50, 25)); + name.add(nameLabel); + name.add(nameField); + name.setPreferredSize(new Dimension(200, 50)); + + p.add(packageType); + p.add(name); + JPanel note = new JPanel(); + JLabel noteLabel = new JLabel(); + noteField = new JTextField(); + note.setLayout(new BoxLayout(note, BoxLayout.X_AXIS)); + noteLabel.setText("note:"); + noteLabel.setPreferredSize(new Dimension(50, 25)); + note.add(noteLabel); + note.add(noteField); + note.setPreferredSize(new Dimension(200, 50)); + p.add(note); + + JPanel price = new JPanel(); + JLabel priceLabel = new JLabel(); + priceField = new JTextField(); + price.setLayout(new BoxLayout(price, BoxLayout.X_AXIS)); + priceLabel.setText("price:"); + priceLabel.setPreferredSize(new Dimension(50, 25)); + price.add(priceLabel); + price.add(priceField); + price.setPreferredSize(new Dimension(200, 50)); + p.add(price); + + JPanel weight = new JPanel(); + JLabel weightLabel = new JLabel(); + weightField = new JTextField(); + weight.setLayout(new BoxLayout(weight, BoxLayout.X_AXIS)); + weightLabel.setText("weight:"); + weightLabel.setPreferredSize(new Dimension(50, 25)); + weight.add(weightLabel); + weight.add(weightField); + weight.setPreferredSize(new Dimension(200, 50)); + p.add(weight); + + JPanel date = new JPanel(); + JLabel dateLabel = new JLabel(); + dateField = new JTextField(); + date.setLayout(new BoxLayout(date, BoxLayout.X_AXIS)); + dateLabel.setText("date:"); + dateLabel.setPreferredSize(new Dimension(50, 25)); + dd = new DateTimePicker(); + dd.addDateTimeChangeListener(this); + date.add(dateLabel); + date.add(dd); + date.setPreferredSize(new Dimension(200, 50)); + p.add(date); + + typePanel = new JPanel(); + typePanel.setLayout(new BoxLayout(typePanel, BoxLayout.X_AXIS)); + typeLabel = new JLabel(); + typeLabel.setText("author:"); + typeLabel.setPreferredSize(new Dimension(50, 25)); + typeTf = new JTextField(); + typePanel.add(typeLabel); + typePanel.add(typeTf); + typePanel.setPreferredSize(new Dimension(200, 50)); + ed = new DateTimePicker(); + p.add(typePanel); + + JPanel actionButton = new JPanel(); + actionButton.setLayout(new BoxLayout(actionButton, BoxLayout.X_AXIS)); + JButton ok = new JButton("ok"); + JButton cancel = new JButton("cancel"); + ok.addActionListener(this); + cancel.addActionListener(this); + actionButton.add(ok); + actionButton.add(cancel); + p.add(actionButton); + // Dialog box dimensions + getContentPane().setSize(500, 500); + getContentPane().add(p); + pack(); + this.setVisible(true); + } + + @Override + public void dateOrTimeChanged(DateTimeChangeEvent dateTimeChangeEvent) { + deliveryDate = dd.getDateTimePermissive(); + } + + @Override + public void actionPerformed(ActionEvent e) { + String actionString = e.getActionCommand(); + switch (actionString) { + case "ok": + addPackage(); + break; + case "cancel": + this.dispose(); + break; + } + } + + private void addPackage() { + try { + PackageFactory.PackageType type = PackageFactory.PackageType.Book; + String pName = nameField.getText(); + String pNote = noteField.getText(); + double pPrice = 0.0; + pPrice = Double.parseDouble(priceField.getText()); + if (pPrice < 0) { + JOptionPane.showMessageDialog(this, + "price cannot be less than 0", + "error", + JOptionPane.WARNING_MESSAGE); + } + double pWeight = 0.0; + pWeight = Double.parseDouble(weightField.getText()); + if (pWeight < 0) { + JOptionPane.showMessageDialog(this, + "weight cannot be less than 0", + "error", + JOptionPane.WARNING_MESSAGE); + } + String pAuthor = ""; + double pHandlingFee = 0.0; + if (pType == 0) { + pAuthor = typeTf.getText(); + if (pAuthor.equals("")) { + JOptionPane.showMessageDialog(this, + "author name can not be empty", + "error", + JOptionPane.WARNING_MESSAGE); + return; + } + } else if (pType == 1) { + type = PackageFactory.PackageType.Electronic; + pHandlingFee = Double.parseDouble(typeTf.getText()); + if (pHandlingFee < 0) { + JOptionPane.showMessageDialog(this, + "Handling fee cannot be less than 0", + "error", + JOptionPane.WARNING_MESSAGE); + } + } else { + type = PackageFactory.PackageType.Perishable; + } + if (pName.equals("")) { + JOptionPane.showMessageDialog(this, + "name cannot be empty", + "error", + JOptionPane.WARNING_MESSAGE); + return; + } + PackageInfo p = PackageFactory.create(type, pName, pNote, pPrice, pWeight, false, deliveryDate, pAuthor, expiryDate, pHandlingFee); + pInstance.addPackage(p); + dispose(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "error in input, please check again", + "error", + JOptionPane.WARNING_MESSAGE); + } + } +} diff --git a/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.java b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.java new file mode 100644 index 0000000..e198ecc --- /dev/null +++ b/assignment4/src/cmpt213/assignment4/packagedeliveries/client/view/JavaSwingUI.java @@ -0,0 +1,176 @@ +package cmpt213.assignment4.packagedeliveries.client.view; + +import cmpt213.assignment4.packagedeliveries.client.control.PackageDeliveriesTracker; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; + +public class JavaSwingUI implements ActionListener { + private final PackageDeliveriesTracker pTracker = PackageDeliveriesTracker.getInstance(); + JFrame uiFrame; + JPanel uiPanel; + JScrollPane scrollView; + PACKAGE_FILTER_OPTION option = PACKAGE_FILTER_OPTION.ALL; + + ; + + public void displayMainPage() { + pTracker.load(); + uiFrame = new JFrame("Package deliveries tracker"); + uiFrame.setSize(500, 500); + uiFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + uiFrame.setLayout(new BoxLayout(uiFrame.getContentPane(), BoxLayout.Y_AXIS)); + uiFrame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + pTracker.save(); + super.windowClosing(e); + uiFrame.dispose(); + } + }); + uiFrame.setVisible(true); + dsplayOptionButtons(); + addButtons(); + setupScrollPane(); + refreshPackageList(); + } + + private void setupScrollPane() { + uiPanel = new JPanel(); + scrollView = new JScrollPane(uiPanel); + + uiPanel.setLayout(new BoxLayout(uiPanel, BoxLayout.Y_AXIS)); + scrollView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + uiPanel.add(Box.createVerticalGlue()); + uiFrame.getContentPane().add(scrollView); + uiFrame.pack(); + } + + private void displayPackages(ArrayList packages) { + uiPanel.removeAll(); + uiPanel.setLayout(new BoxLayout(uiPanel, BoxLayout.Y_AXIS)); + scrollView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + uiPanel.add(Box.createVerticalGlue()); + uiFrame.getContentPane().add(scrollView); + System.out.println(packages); + if (packages.get(0) != "No packages to show") { + for (int i = 0; i < packages.size(); i++) { + JPanel p = new JPanel(); + JTextPane pkgPane = new JTextPane(); + pkgPane.setEditable(false); + pkgPane.setText(packages.get(i)); + p.add(pkgPane); + if (option == PACKAGE_FILTER_OPTION.ALL) { + JButton remove = new JButton(); + int finalI = i; + remove.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + pTracker.removePcakage(finalI); + refreshPackageList(); + } + }); + remove.setText("Remove"); + p.add(remove); + + JCheckBox delivered = new JCheckBox("Delivered?"); + delivered.setBounds(100, 100, 50, 50); + delivered.setSelected(pTracker.isDelivered(i)); + int finalI1 = i; + delivered.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + delivered.setSelected(true); + pTracker.setDelivered(finalI1); + refreshPackageList(); + } + }); + p.add(delivered); + } + uiPanel.add(p); + } + } + uiFrame.validate(); + uiFrame.pack(); + } + + private void addButtons() { + JButton add = new JButton("Add a package"); + JPanel addPanel = new JPanel(); + addPanel.setLayout(new BoxLayout(addPanel, BoxLayout.X_AXIS)); + addPanel.add(add); + addPanel.setPreferredSize(new Dimension(500, 50)); + uiFrame.add(addPanel); + add.addActionListener(this); + } + + private void dsplayOptionButtons() { + JButton btnAll = new JButton("All"); + JButton btnOverdue = new JButton("Overdue"); + JButton btnUpcoming = new JButton("Upcoming"); + + btnAll.addActionListener(this); + btnOverdue.addActionListener(this); + btnUpcoming.addActionListener(this); + + JPanel btnPanel = new JPanel(); + btnPanel.setLayout(new BoxLayout(btnPanel, BoxLayout.X_AXIS)); + btnPanel.add(btnAll); + btnPanel.add(btnOverdue); + btnPanel.add(btnUpcoming); + btnPanel.setPreferredSize(new Dimension(500, 50)); + uiFrame.add(btnPanel); + } + + @Override + public void actionPerformed(ActionEvent e) { + String actionString = e.getActionCommand(); + switch (actionString) { + case "Add a package": + addPackage(); + break; + case "All": + option = PACKAGE_FILTER_OPTION.ALL; + refreshPackageList(); + break; + case "Overdue": + option = PACKAGE_FILTER_OPTION.OVERDUE; + refreshPackageList(); + break; + case "Upcoming": + option = PACKAGE_FILTER_OPTION.UPCOMING; + refreshPackageList(); + break; + } + + } + + private void addPackage() { + new Input(uiFrame); + refreshPackageList(); + } + + private void refreshPackageList() { + switch (option) { + case ALL: + ArrayList allPackages = pTracker.getAllPackages(); + displayPackages(allPackages); + break; + case OVERDUE: + ArrayList overDuePkg = pTracker.overDuePackages(); + displayPackages(overDuePkg); + break; + case UPCOMING: + ArrayList upcomingPkg = pTracker.upcomingPackages(); + displayPackages(upcomingPkg); + break; + } + } + + enum PACKAGE_FILTER_OPTION {ALL, OVERDUE, UPCOMING} +} diff --git a/webappserver/.gitignore b/webappserver/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/webappserver/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/webappserver/.mvn/wrapper/maven-wrapper.jar b/webappserver/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..c1dd12f Binary files /dev/null and b/webappserver/.mvn/wrapper/maven-wrapper.jar differ diff --git a/webappserver/.mvn/wrapper/maven-wrapper.properties b/webappserver/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..b74bf7f --- /dev/null +++ b/webappserver/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/webappserver/docs/curlCommands.txt b/webappserver/docs/curlCommands.txt new file mode 100644 index 0000000..41fbd48 --- /dev/null +++ b/webappserver/docs/curlCommands.txt @@ -0,0 +1,7 @@ +CURL COMMANDS: + +GET /ping +command : curl -i -X GET localhost:8080 +Returns a message "system is up". + +GET /listAll \ No newline at end of file diff --git a/webappserver/list.json b/webappserver/list.json new file mode 100644 index 0000000..7cab810 --- /dev/null +++ b/webappserver/list.json @@ -0,0 +1 @@ +[{"author":"test","name":"test","note":"","price":12.0,"weight":12.0,"expectedDate":"2022-07-29T12:01","delivered":false,"type":"book"}] \ No newline at end of file diff --git a/webappserver/mvnw b/webappserver/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/webappserver/mvnw @@ -0,0 +1,316 @@ +#!/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 +# +# https://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 /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + 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="`\\unset -f command; \\command -v 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/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.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" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$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 \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/webappserver/mvnw.cmd b/webappserver/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/webappserver/mvnw.cmd @@ -0,0 +1,188 @@ +@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 https://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 "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\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/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq 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%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.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 "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\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% + +cmd /C exit /B %ERROR_CODE% diff --git a/webappserver/pom.xml b/webappserver/pom.xml new file mode 100644 index 0000000..881dd04 --- /dev/null +++ b/webappserver/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.2 + + + cmpt213.assignment4.packagedeliveries + webappserver + 0.0.1-SNAPSHOT + WebAppServer + web server side of the assignment + + 18 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplication.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplication.java new file mode 100644 index 0000000..7f4cc58 --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplication.java @@ -0,0 +1,15 @@ +package cmpt213.assignment4.packagedeliveries.webappserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class WebAppServerApplication { + + public static void main(String[] args) { + SpringApplication.run(WebAppServerApplication.class, args); + } +} diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/control/PackageManager.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/control/PackageManager.java new file mode 100644 index 0000000..e44ab52 --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/control/PackageManager.java @@ -0,0 +1,213 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.control; + +import cmpt213.assignment4.packagedeliveries.webappserver.gson.extras.RuntimeTypeAdapterFactory; +import cmpt213.assignment4.packagedeliveries.webappserver.model.BookPackage; +import cmpt213.assignment4.packagedeliveries.webappserver.model.ElectronicPackage; +import cmpt213.assignment4.packagedeliveries.webappserver.model.PackageInfo; +import cmpt213.assignment4.packagedeliveries.webappserver.model.PerishablePackage; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.*; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; + +/** + * It's a class that contains a main method that creates a TextMenu object, loads a list of packages + * from a file, and then loops through a menu of options until the user chooses to quit + */ +public class PackageManager { + private static final String fileName = "list.json"; + private static final RuntimeTypeAdapterFactory r = RuntimeTypeAdapterFactory.of(PackageInfo.class, "type") + .registerSubtype(BookPackage.class, "book") + .registerSubtype(PerishablePackage.class, "perishable") + .registerSubtype(ElectronicPackage.class, "electronic"); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, + new TypeAdapter() { + @Override + public void write(JsonWriter jsonWriter, + LocalDateTime localDateTime) throws IOException { + jsonWriter.value(localDateTime.toString()); + } + + @Override + public LocalDateTime read(JsonReader jsonReader) throws IOException { + return LocalDateTime.parse(jsonReader.nextString()); + } + }).registerTypeAdapterFactory(r).create(); + private static ArrayList packageList = new ArrayList<>(); + + private static PackageManager instance; + + public static PackageManager getInstance() { + if (instance == null) { + instance = new PackageManager(); + } + return instance; + } + + public void addPackage(PackageInfo p) { + packageList.add(p); + Collections.sort(packageList); + } + + /** + * It saves the packageList to a file. + */ + public void save() { + try { + Writer w = new FileWriter(fileName); + gson.toJson(packageList, w); + w.flush(); + w.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * It reads the json file, converts it to a list of PackageInfo objects, and then sets the type of + * each object to the appropriate type + */ + public void load() { + //File file = new File(fileName); + try { + String json = Files.readString(Paths.get(fileName)); + Type lType = new TypeToken>() { + }.getType(); + packageList = gson.fromJson(json, lType); + for (PackageInfo p : packageList) { + if (p instanceof BookPackage) { + p.setType("book"); + } else if (p instanceof PerishablePackage) { + p.setType("perishable"); + } else if (p instanceof ElectronicPackage) { + p.setType("electronic"); + } + } + System.out.println("packages loaded"); + } catch (FileNotFoundException e) { + System.out.println("no packages to load"); + } catch (NoSuchFileException e) { + createFile(); + //throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void createFile() { + System.out.println("CreateFile"); + try { + File packages = new File(fileName); + if(packages.createNewFile()) { + System.out.println("New file list.json created"); + } + } + catch (IOException e) { + System.out.println("No file exists, creating a new file"); + e.printStackTrace(); + } + } + + public ArrayList getAllPackages() { + ArrayList b = new ArrayList<>(); + if (packageList.size() == 0) { + b.add("No packages to show"); + } else { + Collections.sort(packageList); + for (int i = 0; i < packageList.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + packageList.get(i) + "\n\n"; + b.add(bString); + } + } + return b; + } + + /** + * This function takes in a list of packages, a boolean for whether or not the user wants to see + * packages that are due, and a boolean for whether or not the user wants to see all packages. It + * then returns a list of packages that are sorted by their expected delivery date + * + * @param pList the list of packages to be sorted + * @param due true if you want to sort the list by due date, false if you want to sort the list by + * expected date + * @return An ArrayList of PackageInfo objects. + */ + //due=true returns overdue packages, else upcoming packages + public ArrayList sortList(ArrayList pList, boolean due) { + ArrayList sortedList = new ArrayList<>(); + LocalDateTime today = LocalDateTime.now(); + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + today.format(format); + for (int i = 0; i < pList.size(); i++) { + PackageInfo p = pList.get(i); + if (!p.getDelivered()) { + if (due && today.isAfter(p.getExpectedDate())) { + sortedList.add(p); + } else if (!due && today.isBefore(p.getExpectedDate())) { + sortedList.add(p); + } + } + } + Collections.sort(sortedList); + return sortedList; + } + + public ArrayList overDuePackages() { + ArrayList b = new ArrayList<>(); + ArrayList overdue = sortList(packageList, true); + if (overdue.size() == 0) { + b.add("no overdue packages to show"); + } + for (int i = 0; i < overdue.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + overdue.get(i) + "\n\n"; + b.add(bString); + } + return b; + } + + public ArrayList upcomingPackages() { + ArrayList b = new ArrayList<>(); + ArrayList upcoming = sortList(packageList, false); + if (upcoming.size() == 0) { + b.add("no upcoming packages to show"); + } + for (int i = 0; i < upcoming.size(); i++) { + String bString = ("Package #" + (i + 1)) + "\n" + upcoming.get(i) + "\n\n"; + b.add(bString); + } + return b; + } + + public void removePcakage(int i) { + packageList.remove(i); + } + + public boolean isDelivered(int i) { + return packageList.get(i).getDelivered(); + } + + public void setDelivered(int i) { + packageList.get(i).setDelivered(true); + } + +public PackageInfo deserializePackage(String packageGson){ + Type lType = new TypeToken>() { + }.getType(); +PackageInfo newPackage=gson.fromJson(packageGson, lType); + System.out.println(newPackage.toString() + "-------> newPackage"); + return newPackage; +} +} + diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/controllers/PackageController.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/controllers/PackageController.java new file mode 100644 index 0000000..ccf25f2 --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/controllers/PackageController.java @@ -0,0 +1,44 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.controllers; + +import cmpt213.assignment4.packagedeliveries.webappserver.control.PackageManager; +import cmpt213.assignment4.packagedeliveries.webappserver.model.PackageInfo; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; + +@RestController +public class PackageController { + @GetMapping("/ping") + @ResponseStatus(HttpStatus.OK) + public String ping(){ + return "system is up"; + } + + PackageManager manager=PackageManager.getInstance(); + @GetMapping("/listAll") + @ResponseStatus(HttpStatus.OK) + public ArrayList getAllPackages(){ + return manager.getAllPackages(); + } + + @PostMapping("/addBook") + @ResponseStatus(HttpStatus.CREATED) + public void addBook(@RequestBody String bookString){ + System.out.println(bookString+"----------------->bookString"); + PackageInfo p=manager.deserializePackage(bookString); + manager.addPackage(p); + } + + @PostMapping("/addPerishable") + @ResponseStatus(HttpStatus.CREATED) + public void addPerishable(@RequestBody String perishableString){ + PackageInfo p=manager.deserializePackage(perishableString); + } + + @PostMapping("/addElectronic") + @ResponseStatus(HttpStatus.CREATED) + public void addElectronic(@RequestBody String electronicString){ + PackageInfo p=manager.deserializePackage(electronicString); + } +} diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/gson/extras/RuntimeTypeAdapterFactory.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/gson/extras/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..45fb444 --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/gson/extras/RuntimeTypeAdapterFactory.java @@ -0,0 +1,258 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.gson.extras; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Adapts values whose runtime + * + * type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ * + *

Serialization and deserialization

+ * In order to serialize and deserialize a polymorphic object, + * you must specify the base type explicitly. + *
   {@code
+ *   Diamond diamond = new Diamond();
+ *   String json = gson.toJson(diamond, Shape.class);
+ * }
+ * And then: + *
   {@code
+ *   Shape shape = gson.fromJson(json, Shape.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap<>(); + private final Map, String> subtypeToLabel = new LinkedHashMap<>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory<>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final TypeAdapter jsonElementAdapter = gson.getAdapter(JsonElement.class); + final Map> labelToDelegate = new LinkedHashMap<>(); + final Map, TypeAdapter> subtypeToDelegate = new LinkedHashMap<>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = jsonElementAdapter.read(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + jsonElementAdapter.write(out, jsonObject); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + jsonElementAdapter.write(out, clone); + } + }.nullSafe(); + } +} \ No newline at end of file diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/BookPackage.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/BookPackage.java new file mode 100644 index 0000000..896ab5c --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/BookPackage.java @@ -0,0 +1,23 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.model; + +import java.time.LocalDateTime; + +/** + * It's a subclass of PackageInfo that adds an author field + */ +public class BookPackage extends PackageInfo { + String author; + + public BookPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) { + + super(name, note, price, weight, delivered, expectedDate); + this.author = author; + this.setType("book"); + } + + @Override + public String toString() { + return super.toString() + "\nAuthor: " + author; + } +} + diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/ElectronicPackage.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/ElectronicPackage.java new file mode 100644 index 0000000..2b25ee8 --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/ElectronicPackage.java @@ -0,0 +1,21 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.model; + +import java.time.LocalDateTime; + +/** + * ElectronicPackage is a subclass of PackageInfo that adds a handlingFee attribute + */ +public class ElectronicPackage extends PackageInfo { + double handlingFee; + + public ElectronicPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee) { + super(name, note, price, weight, delivered, expectedDate); + this.handlingFee = handlingFee; + this.setType("electronic"); + } + + @Override + public String toString() { + return super.toString() + "\nHandling fee: " + handlingFee; + } +} diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PackageInfo.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PackageInfo.java new file mode 100644 index 0000000..517d9fc --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PackageInfo.java @@ -0,0 +1,85 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import static java.lang.Math.abs; + +/** + * PackageInfo is a class that contains information about a package + */ + +public class PackageInfo implements Comparable { + private final String name; + private final String note; + private final double price; + private final double weight; + private final LocalDateTime expectedDate; + private boolean delivered; + private String type; + + public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) { + this.name = name; + this.note = note; + this.price = price; + this.weight = weight; + this.delivered = delivered; + this.expectedDate = expectedDate; + } + + /** + * This function returns the name of the person. + * + * @return The name of the person. + */ + public String getName() { + return name; + } + + + public boolean getDelivered() { + return delivered; + } + + /** + * This function sets the value of the delivered variable to the value of the delivered parameter. + * + * @param delivered This is a boolean value that indicates whether the message has been delivered + * to the recipient. + */ + public void setDelivered(boolean delivered) { + this.delivered = delivered; + } + + public LocalDateTime getExpectedDate() { + return expectedDate; + } + + /** + * This function sets the type of the object to the type passed in as a parameter + * + * @param type The type of the event. + */ + public void setType(String type) { + this.type = type; + } + + // Comparing the expected date of the package to the expected date of the package passed in as a + // parameter. + @Override + public int compareTo(PackageInfo p) { + return this.expectedDate.compareTo(p.getExpectedDate()); + } + + // Overriding the toString method. + @Override + public String toString() { + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + LocalDateTime today = LocalDateTime.now(); + today.format(format); + long diff = ChronoUnit.DAYS.between(today, expectedDate); + String isDelivered = delivered ? "yes" : "no"; + return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: $" + price + "\n" + "Weight: " + weight + " kg" + "\n" + "Expected Delivery Date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expectedDate) + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue"); + } +} diff --git a/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PerishablePackage.java b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PerishablePackage.java new file mode 100644 index 0000000..91d033e --- /dev/null +++ b/webappserver/src/main/java/cmpt213/assignment4/packagedeliveries/webappserver/model/PerishablePackage.java @@ -0,0 +1,25 @@ +package cmpt213.assignment4.packagedeliveries.webappserver.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * It's a subclass of PackageInfo that adds an expiry date + */ +public class PerishablePackage extends PackageInfo { + LocalDateTime expiryDate; + + // It's a constructor that initializes the object with the given parameters. + public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) { + super(name, note, price, weight, delivered, expectedDate); + this.expiryDate = expiryDate; + this.setType("perishable"); + } + + // It's a method that returns a string representation of the object. + @Override + public String toString() { + return super.toString() + "\nExpiry date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expiryDate); + } +} + diff --git a/webappserver/src/main/resources/application.properties b/webappserver/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/webappserver/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/webappserver/src/test/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplicationTests.java b/webappserver/src/test/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplicationTests.java new file mode 100644 index 0000000..092b241 --- /dev/null +++ b/webappserver/src/test/java/cmpt213/assignment4/packagedeliveries/webappserver/WebAppServerApplicationTests.java @@ -0,0 +1,13 @@ +package cmpt213.assignment4.packagedeliveries.webappserver; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class WebAppServerApplicationTests { + + @Test + void contextLoads() { + } + +}