commit
f8a4952127
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="github.lgooddatepicker.LGoodDatePicker" type="repository">
|
||||
<properties maven-id="com.github.lgooddatepicker:LGoodDatePicker:11.2.1" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/lgooddatepicker/LGoodDatePicker/11.2.1/LGoodDatePicker-11.2.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="google.code.gson" type="repository">
|
||||
<properties maven-id="com.google.code.gson:gson:2.9.0" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.9.0/gson-2.9.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_18" default="true" project-jdk-name="18" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/assignment4.iml" filepath="$PROJECT_DIR$/assignment4.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../../../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="google.code.gson" level="project" />
|
||||
<orderEntry type="library" name="github.lgooddatepicker.LGoodDatePicker" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1 @@
|
||||
[{"author":"test","name":"test","note":"","price":12.0,"weight":12.0,"expectedDate":"2022-07-29T12:01","delivered":false,"type":"book"}]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
@ -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<PackageInfo> 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<LocalDateTime>() {
|
||||
@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<PackageInfo> 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<ArrayList<PackageInfo>>() {
|
||||
}.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<String> getAllPackages() {
|
||||
ArrayList<String> 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<PackageInfo> sortList(ArrayList<PackageInfo> pList, boolean due) {
|
||||
ArrayList<PackageInfo> 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<String> overDuePackages() {
|
||||
ArrayList<String> b = new ArrayList<>();
|
||||
ArrayList<PackageInfo> 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<String> upcomingPackages() {
|
||||
ArrayList<String> b = new ArrayList<>();
|
||||
ArrayList<PackageInfo> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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:
|
||||
* <pre> {@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;
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>Without additional type information, the serialized JSON is ambiguous. Is
|
||||
* the bottom shape in this drawing a rectangle or a diamond? <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* This class addresses this problem by adding type information to the
|
||||
* serialized JSON and honoring that type information when the JSON is
|
||||
* deserialized: <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "type": "Diamond",
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "type": "Circle",
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* Both the type field name ({@code "type"}) and the type labels ({@code
|
||||
* "Rectangle"}) are configurable.
|
||||
*
|
||||
* <h3>Registering Types</h3>
|
||||
* 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. <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
|
||||
* = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
|
||||
* }</pre>
|
||||
* 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.
|
||||
* <pre> {@code
|
||||
* shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
|
||||
* shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
|
||||
* shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
|
||||
* }</pre>
|
||||
* Finally, register the type adapter factory in your application's GSON builder:
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapterFactory(shapeAdapterFactory)
|
||||
* .create();
|
||||
* }</pre>
|
||||
* Like {@code GsonBuilder}, this API supports chaining: <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
|
||||
* .registerSubtype(Rectangle.class)
|
||||
* .registerSubtype(Circle.class)
|
||||
* .registerSubtype(Diamond.class);
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Serialization and deserialization</h3>
|
||||
* In order to serialize and deserialize a polymorphic object,
|
||||
* you must specify the base type explicitly.
|
||||
* <pre> {@code
|
||||
* Diamond diamond = new Diamond();
|
||||
* String json = gson.toJson(diamond, Shape.class);
|
||||
* }</pre>
|
||||
* And then:
|
||||
* <pre> {@code
|
||||
* Shape shape = gson.fromJson(json, Shape.class);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
|
||||
private final Class<?> baseType;
|
||||
private final String typeFieldName;
|
||||
private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<>();
|
||||
private final Map<Class<?>, 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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<T> registerSubtype(Class<? extends T> 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<T> registerSubtype(Class<? extends T> type) {
|
||||
return registerSubtype(type, type.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
|
||||
if (type.getRawType() != baseType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
|
||||
final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>();
|
||||
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Class<?>> 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<R>() {
|
||||
@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<R> delegate = (TypeAdapter<R>) 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<R> delegate = (TypeAdapter<R>) 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<String, JsonElement> e : jsonObject.entrySet()) {
|
||||
clone.add(e.getKey(), e.getValue());
|
||||
}
|
||||
jsonElementAdapter.write(out, clone);
|
||||
}
|
||||
}.nullSafe();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<PackageInfo> {
|
||||
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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String> 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<String> allPackages = pTracker.getAllPackages();
|
||||
displayPackages(allPackages);
|
||||
break;
|
||||
case OVERDUE:
|
||||
ArrayList<String> overDuePkg = pTracker.overDuePackages();
|
||||
displayPackages(overDuePkg);
|
||||
break;
|
||||
case UPCOMING:
|
||||
ArrayList<String> upcomingPkg = pTracker.upcomingPackages();
|
||||
displayPackages(upcomingPkg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum PACKAGE_FILTER_OPTION {ALL, OVERDUE, UPCOMING}
|
||||
}
|
@ -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/
|
Binary file not shown.
@ -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
|
@ -0,0 +1,7 @@
|
||||
CURL COMMANDS:
|
||||
|
||||
GET /ping
|
||||
command : curl -i -X GET localhost:8080
|
||||
Returns a message "system is up".
|
||||
|
||||
GET /listAll
|
@ -0,0 +1 @@
|
||||
[{"author":"test","name":"test","note":"","price":12.0,"weight":12.0,"expectedDate":"2022-07-29T12:01","delivered":false,"type":"book"}]
|
@ -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 "$@"
|
@ -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%
|
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>cmpt213.assignment4.packagedeliveries</groupId>
|
||||
<artifactId>webappserver</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>WebAppServer</name>
|
||||
<description>web server side of the assignment</description>
|
||||
<properties>
|
||||
<java.version>18</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<PackageInfo> 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<LocalDateTime>() {
|
||||
@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<PackageInfo> 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<ArrayList<PackageInfo>>() {
|
||||
}.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<String> getAllPackages() {
|
||||
ArrayList<String> 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<PackageInfo> sortList(ArrayList<PackageInfo> pList, boolean due) {
|
||||
ArrayList<PackageInfo> 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<String> overDuePackages() {
|
||||
ArrayList<String> b = new ArrayList<>();
|
||||
ArrayList<PackageInfo> 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<String> upcomingPackages() {
|
||||
ArrayList<String> b = new ArrayList<>();
|
||||
ArrayList<PackageInfo> 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<ArrayList<PackageInfo>>() {
|
||||
}.getType();
|
||||
PackageInfo newPackage=gson.fromJson(packageGson, lType);
|
||||
System.out.println(newPackage.toString() + "-------> newPackage");
|
||||
return newPackage;
|
||||
}
|
||||
}
|
||||
|
@ -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<String> 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);
|
||||
}
|
||||
}
|
@ -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:
|
||||
* <pre> {@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;
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>Without additional type information, the serialized JSON is ambiguous. Is
|
||||
* the bottom shape in this drawing a rectangle or a diamond? <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* This class addresses this problem by adding type information to the
|
||||
* serialized JSON and honoring that type information when the JSON is
|
||||
* deserialized: <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "type": "Diamond",
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "type": "Circle",
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* Both the type field name ({@code "type"}) and the type labels ({@code
|
||||
* "Rectangle"}) are configurable.
|
||||
*
|
||||
* <h3>Registering Types</h3>
|
||||
* 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. <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
|
||||
* = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
|
||||
* }</pre>
|
||||
* 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.
|
||||
* <pre> {@code
|
||||
* shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
|
||||
* shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
|
||||
* shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
|
||||
* }</pre>
|
||||
* Finally, register the type adapter factory in your application's GSON builder:
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapterFactory(shapeAdapterFactory)
|
||||
* .create();
|
||||
* }</pre>
|
||||
* Like {@code GsonBuilder}, this API supports chaining: <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
|
||||
* .registerSubtype(Rectangle.class)
|
||||
* .registerSubtype(Circle.class)
|
||||
* .registerSubtype(Diamond.class);
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Serialization and deserialization</h3>
|
||||
* In order to serialize and deserialize a polymorphic object,
|
||||
* you must specify the base type explicitly.
|
||||
* <pre> {@code
|
||||
* Diamond diamond = new Diamond();
|
||||
* String json = gson.toJson(diamond, Shape.class);
|
||||
* }</pre>
|
||||
* And then:
|
||||
* <pre> {@code
|
||||
* Shape shape = gson.fromJson(json, Shape.class);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
|
||||
private final Class<?> baseType;
|
||||
private final String typeFieldName;
|
||||
private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<>();
|
||||
private final Map<Class<?>, 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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 <T> RuntimeTypeAdapterFactory<T> of(Class<T> 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<T> registerSubtype(Class<? extends T> 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<T> registerSubtype(Class<? extends T> type) {
|
||||
return registerSubtype(type, type.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
|
||||
if (type.getRawType() != baseType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
|
||||
final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>();
|
||||
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Class<?>> 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<R>() {
|
||||
@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<R> delegate = (TypeAdapter<R>) 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<R> delegate = (TypeAdapter<R>) 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<String, JsonElement> e : jsonObject.entrySet()) {
|
||||
clone.add(e.getKey(), e.getValue());
|
||||
}
|
||||
jsonElementAdapter.write(out, clone);
|
||||
}
|
||||
}.nullSafe();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<PackageInfo> {
|
||||
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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue