diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..06fab23769d781a3c7233bc0c51a68aba5993c5c --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Eclipse +.classpath +.project +.settings/ + +# Intellij +.idea/ +*.iml +*.iws + +# Mac +.DS_Store + +# Maven +log/ +target/ + +db/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f81e798564af7e7beadf3c2903c0fda576abecdd --- /dev/null +++ b/pom.xml @@ -0,0 +1,150 @@ +<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 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>cz.vsb.fei.java2</groupId> + <artifactId>lab06</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <name>lab06</name> + + <packaging>jar</packaging> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.release>21</maven.compiler.release> + <JavaFX.version>22-ea+16</JavaFX.version> + <JUnit.version>5.10.1</JUnit.version> + <log4j.version>2.22.1</log4j.version> + <lombok.version>1.18.30</lombok.version> + </properties> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> + <version>${JUnit.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.openjfx</groupId> + <artifactId>javafx-controls</artifactId> + <version>${JavaFX.version}</version> + </dependency> + <dependency> + <groupId>org.openjfx</groupId> + <artifactId>javafx-fxml</artifactId> + <version>${JavaFX.version}</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>provided</scope> + </dependency> + + <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-core</artifactId> + <version>6.4.4.Final</version> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-jpamodelgen</artifactId> + <scope>provided</scope> + <version>6.4.4.Final</version> + </dependency> + + <!-- https://mvnrepository.com/artifact/com.h2database/h2 --> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>2.2.224</version> + </dependency> + + <!-- + https://mvnrepository.com/artifact/jakarta.persistence/jakarta.persistence-api --> + <dependency> + <groupId>jakarta.persistence</groupId> + <artifactId>jakarta.persistence-api</artifactId> + <version>3.1.0</version> + </dependency> + + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.12.1</version> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + <path> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-jpamodelgen</artifactId> + <version>6.4.4.Final</version> + </path> + </annotationProcessorPaths> + </configuration> + <executions> + <execution> + <id>process</id> + <phase>generate-sources</phase> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>3.5.0</version> + <configuration> + <sources> + <source>target/generated-sources/annotations</source> + </sources> + </configuration> + <executions> + <execution> + <id>add-source</id> + <phase>process-resources</phase> + <goals> + <goal>add-source</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>3.2.1</version> + </plugin> + </plugins> + </build> + +</project> diff --git a/src/main/java/cz/vsb/fei/java2/lab06/App.java b/src/main/java/cz/vsb/fei/java2/lab06/App.java new file mode 100644 index 0000000000000000000000000000000000000000..9f04b573bed73a7106e381bfb15d50389fd8c6c9 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/App.java @@ -0,0 +1,78 @@ +package cz.vsb.fei.java2.lab06; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import org.h2.tools.Server; + +import cz.vsb.fei.java2.lab06.entities.Car; +import cz.vsb.fei.java2.lab06.entities.LegalPerson; +import cz.vsb.fei.java2.lab06.entities.Route; +import cz.vsb.fei.java2.lab06.entities.Vehicle; +import cz.vsb.fei.java2.lab06.repositories.PersonRepsository; +import cz.vsb.fei.java2.lab06.repositories.RouteRepsository; +import cz.vsb.fei.java2.lab06.repositories.VehicleRepsository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; +import lombok.extern.log4j.Log4j2; + +/** + * Class <b>App</b> - extends class Application and it is an entry point of the + * program + * + * @author Java I + */ +@Log4j2 +public class App { + + public static void main(String[] args) { + log.info("Launching Java application."); + + EntityManagerFactory emf = Persistence.createEntityManagerFactory("java2"); + EntityManager em = emf.createEntityManager(); + + + //TODO: Create repositories + + //TODO: generate vehicles and persons + + //TODO: add existing person to existing vehicle as owner + + //TODO: generate new vehicle with new owner + + //TODO: generate routes and assign vehicles + // clear entity manager cache - start again with clear cache + em.clear(); + + //TODO: list routes, persons and vehicles + + em.close(); + startDBWebServerAndWait(); + } + + private static void startDBWebServerAndWait() { + // Start HTTP server for access H2 DB for look inside + try { + Server server = Server.createWebServer(); + log.info(server.getURL()); + server.start(); + log.info("Waitnig for Key press (ENTER)"); + waitForKeyPress(); + log.info("Ending DB web server BYE."); + server.stop(); + } catch (SQLException e) { + log.error("Cannot create DB web server.", e); + } + } + + private static void waitForKeyPress() { + try { + System.in.read(); + } catch (IOException e) { + log.error("Cannot read input from keyboard.", e); + } + } + +} \ No newline at end of file diff --git a/src/main/java/cz/vsb/fei/java2/lab06/Tools.java b/src/main/java/cz/vsb/fei/java2/lab06/Tools.java new file mode 100644 index 0000000000000000000000000000000000000000..3ae8635991c4824769817efeed41477d99e4fb2a --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/Tools.java @@ -0,0 +1,83 @@ +package cz.vsb.fei.java2.lab06; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class Tools { + + public static final Random RANDOM = new Random(); + + public static final List<String> FIRST_NAMES = Collections + .unmodifiableList(Arrays.asList("Petr", "Marie", "Jan", "Jana", "Tomáš", "KateĹ™ina", "Lukáš", "Tereza", + "Martin", "Veronika", "David", "Eva", "Jakub", "Lucie", "Michal", "Anna", "Adam", "Monika", "Tom", + "Klára", "Robert", "KristĂ˝na", "Marek", "Simona", "Filip", "Petra", "OndĹ™ej", "Lenka", "MatÄ›j", + "MarkĂ©ta", "Pavel", "Hana", "Jakub", "AdĂ©la", "Daniel", "Barbora", "Lukáš", "Eliška", "Josef")); + public static final List<String> LAST_NAMES = Collections.unmodifiableList(Arrays.asList("Novák", "Svoboda", + "NovotnĂ˝", "Dvořák", "ÄŚernĂ˝", "Procházková", "KuÄŤera", "VeselĂ˝", "Horák", "NÄ›mec", "PokornĂ˝", "Mareš", + "PospĂšilová", "Hájek", "JelĂnek", "Král", "RĹŻĹľiÄŤka", "Beneš", "Fiala", "Sedláček", "KĹ™ĂĹľ", "NÄ›mcová", + "VlÄŤek", "Kolář", "Bartoš", "BĂlĂ˝", "Veselá", "KovaĹ™Ăk", "Havelka", "MalĂ˝", "Urban", "KopeckĂ˝", "Vlach", + "Ĺ imek", "KoneÄŤnĂ˝", "DoleĹľal", "Ĺ ĹĄastnĂ˝", "KopeÄŤná", "Holub", "PospĂchal")); + + public static final List<String> STREETS = Collections.unmodifiableList( + Arrays.asList("Panská", "HlavnĂ", "Ulice Nová", "NámÄ›stĂ Svobody", "HĹ™bitovnĂ", "RevoluÄŤnĂ", "Sadová", + "Jiráskova", "Ĺ kolnĂ", "Vinohradská", "KomenskĂ©ho", "MĂrová", "KĹ™ĂĹľová", "Masarykova", + "TĹ™Ăda Svobody", "Karlova", "Dlouhá", "Ĺ˝iĹľkova", "PurkyĹova", "Rybářská", "Sokolská", "RybnĂÄŤek", + "VrchlickĂ©ho", "Ĺ tefánikova", "Veselá", "Lipová", "Na Hrázi", "Výšinná", "Nová Cesta", "ÄŚeská")); + public static final List<String> CITIES = Collections.unmodifiableList( + Arrays.asList("Praha", "Brno", "Ostrava", "PlzeĹ", "Liberec", "Olomouc", "ÄŚeskĂ© BudÄ›jovice", + "Hradec KrálovĂ©", "ĂšstĂ nad Labem", "Pardubice", "ZlĂn", "Karlovy Vary", "Jihlava", "Tábor", + "HavĂĹ™ov", "ÄŚeskĂ˝ TěšĂn", "Mladá Boleslav", "Trutnov", "PĹ™erov", "Kladno", "Opava", "FrĂ˝dek-MĂstek", + "DěčĂn", "Karviná", "Jablonec nad Nisou", "TĹ™ebĂÄŤ", "Žďár nad Sázavou", "KolĂn", "UherskĂ© HradištÄ›", + "Znojmo", "ProstÄ›jov", "Litoměřice", "KroměřĂĹľ", "Chomutov", "PĹ™Ăbram", "PĹ™Ăbram", "Cheb", + "Teplice", "UherskĂ˝ Brod", "Sokolov", "BĹ™eclav", "LitvĂnov", "Klatovy", "VsetĂn", "NovĂ˝ JiÄŤĂn")); + + public static final List<String> POST_NUMBER = Collections + .unmodifiableList(Arrays.asList("10000", "11000", "12000", "13000", "14000", "15000", "16000", "17000", + "18000", "19000", "20000", "21000", "22000", "23000", "24000", "25000", "26000", "27000", "28000", + "29000", "30000", "31000", "32000", "33000", "34000", "35000", "36000", "37000", "38000", "39000")); + + public static final List<String> COMPANY_NAMES = Collections.unmodifiableList(Arrays.asList("Inova", "Sprint", + "Polaris", "Forte", "Nexus", "Vertex", "Synergie", "Horizon", "Astra", "Axiom", "Optima", "Integra", + "Evolve", "Apex", "Dynasty", "Eclipse", "Paragon", "Fusion", "Oasis", "Equinox", "Voyage", "Genesis", + "Zenith", "Elite", "Harmony", "Stratos", "Aurora", "Quantum", "Spectrum")); + + public static String generateCompanyName() { + StringBuilder name = new StringBuilder(); + int numberOfWords = RANDOM.nextInt(2) + 1; + for (int j = 0; j < numberOfWords; j++) { + name.append(randomElementFrom(COMPANY_NAMES)); + if (j < numberOfWords - 1) { + name.append(" "); + } + } + return name.toString(); + } + + public static String generateAddress() { + return String.format("%s %d, %s, %s", randomElementFrom(STREETS), RANDOM.nextInt(99) + 1, + randomElementFrom(CITIES), randomElementFrom(POST_NUMBER)); + } + + public static <T> T randomElementFrom(List<T> list) { + return randomElementFrom(list, RANDOM); + } + + public static <T> T randomElementFrom(List<T> list, Random r) { + if (list.isEmpty()) { + return null; + } + return list.get(r.nextInt(list.size())); + } + + public static LocalDate generatePreviousDate() { + return LocalDate.of(LocalDate.now().getYear() - RANDOM.nextInt(80), RANDOM.nextInt(12) + 1, 1) + .plusDays(RANDOM.nextInt(31)); + } + + private Tools() { + /* hide public one - nothing to do */ + } +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/BaseEntity.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/BaseEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..1156a706f76fe20e0ee378a2046142c6689ae62f --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/BaseEntity.java @@ -0,0 +1,26 @@ +package cz.vsb.fei.java2.lab06.entities; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +/** + * Implementation of design pattern layer supertype + * https://martinfowler.com/eaaCatalog/layerSupertype.html + */ +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@ToString +@MappedSuperclass +public abstract class BaseEntity { + + @EqualsAndHashCode.Include + @Getter + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/Car.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/Car.java new file mode 100644 index 0000000000000000000000000000000000000000..9d021181387dfbd4c28422e9908da69554644b2f --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/Car.java @@ -0,0 +1,68 @@ +package cz.vsb.fei.java2.lab06.entities; + +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.DESTINATION; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.START; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.stream.Collectors; + +import cz.vsb.fei.java2.lab06.Tools; +import cz.vsb.fei.java2.lab06.entities.Route.RoutePartType; +import jakarta.persistence.Entity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class Car extends Vehicle { + + private static final List<String> COLORS = Collections.unmodifiableList((Arrays.asList("ÄŚerná perla", + "Diamantová bĂlá", "LunárnĂ stĹ™Ăbro", "Kosmická šedá", "Azure modrá", "Rubinová ÄŤervená", + "SmaragdovÄ› zelená", "Kávová krĂ©mová", "SluneÄŤnĂ oranĹľová", "Zlatá svĂtilna", "Ametystová fialová", + "RĹŻĹľová sváteÄŤnĂ", "Temná oceánská modĹ™", "MÄ›sĂÄŤnÄ› šedá", "ŽárivÄ› rudá", "Lesklá zelená", + "Hluboká ÄŤokoládová", "MyslĂnská oranĹľová", "SluneÄŤnĂ Ĺľlutá", "Ĺ eĹ™ĂkovÄ› fialová"))); + + private int numberOfSeats; + private String color; + + @Override + public String planeRoute(String start, String destination) { + List<RoutePartType> route = new ArrayList<>(); + Random r = new Random(Objects.hash(start, destination)); + int count = r.nextInt(20) + 5; + route.add(START); + List<RoutePartType> parts = new ArrayList<>(Arrays.asList(RoutePartType.values())); + parts.remove(START); + parts.remove(DESTINATION); + for (int i = 0; i < count; i++) { + route.add(parts.get(r.nextInt(parts.size()))); + } + route.add(DESTINATION); + return route.stream().map(RoutePartType::getSign).collect(Collectors.joining()); + } + + @Override + public boolean isRouteAcceptable(String routeDescription) { + return true; + } + + public Car(String registartionNumber, int maxSpeed, String producerName, int numberOfSeats, String color) { + super(registartionNumber, maxSpeed, producerName); + this.numberOfSeats = numberOfSeats; + this.color = color; + } + + public static Car generate() { + return new Car(generateRegistrationNumber(), Tools.RANDOM.nextInt(100) + 120, + Tools.randomElementFrom(PRODUCERS), Tools.RANDOM.nextInt(5) + 2, Tools.randomElementFrom(COLORS)); + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/JuridicalPerson.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/JuridicalPerson.java new file mode 100644 index 0000000000000000000000000000000000000000..67bf5d793df970ea417c0c67c09723a6982b80fb --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/JuridicalPerson.java @@ -0,0 +1,46 @@ +package cz.vsb.fei.java2.lab06.entities; + +import java.util.Arrays; + +import cz.vsb.fei.java2.lab06.Tools; +import jakarta.persistence.Entity; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class JuridicalPerson extends LegalPerson { + + private String companyName; + private CompanyType type; + + public JuridicalPerson(String companyName, String address, CompanyType type) { + super(address); + this.companyName = companyName; + this.type = type; + } + + @AllArgsConstructor + @Getter + public enum CompanyType { + SPOLECNOST_S_RUCENIM_OMEYENZM("s.r.o."), AKCIOVA_SPOLECNOST("a.s."), ZAPSANY_SPOLEK("z.s."), + KOMANDITNI_SPOLECNOST("k.s."), VEREJNA_OBCHODNI_SPOLECNOST("v.o.s."), EVROPSKA_AKCIOVA_SPOLECNOST("SE"); + + private String description; + } + + @Override + public String getFullName() { + return String.format("%s %s", getCompanyName(), getType().getDescription()); + } + + public static JuridicalPerson generate() { + return new JuridicalPerson(Tools.generateCompanyName(), Tools.generateAddress(), + Tools.randomElementFrom(Arrays.asList(CompanyType.values()))); + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/LegalPerson.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/LegalPerson.java new file mode 100644 index 0000000000000000000000000000000000000000..c35daad7566fe46493bb4bd19894e7a7e6374df7 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/LegalPerson.java @@ -0,0 +1,36 @@ +package cz.vsb.fei.java2.lab06.entities; + +import java.util.Set; + +import cz.vsb.fei.java2.lab06.Tools; +import jakarta.persistence.Entity; +import jakarta.persistence.OneToMany; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public abstract class LegalPerson extends BaseEntity { + + private String address; + + @ToString.Exclude + private Set<Vehicle> ownedVewhicles; + + protected LegalPerson(String address) { + this.address = address; + } + + public abstract String getFullName(); + + public static LegalPerson generate() { + if (Tools.RANDOM.nextBoolean()) { + return JuridicalPerson.generate(); + } else { + return NaturalPerson.generate(); + } + } +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/Motorbike.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/Motorbike.java new file mode 100644 index 0000000000000000000000000000000000000000..14d6074425409da3a81c84c3d4b5cc2d76353825 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/Motorbike.java @@ -0,0 +1,71 @@ +package cz.vsb.fei.java2.lab06.entities; + +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.CROSSROAD; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.DESTINATION; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.SPEED_UP; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.*; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.START; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.STRAIGHT; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.TURN_LEFT; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.TURN_RIGHT; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +import cz.vsb.fei.java2.lab06.Tools; +import cz.vsb.fei.java2.lab06.entities.Route.RoutePartType; +import jakarta.persistence.Entity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class Motorbike extends Vehicle { + + private boolean storageBox; + + private static Set<RoutePartType> allowedRouteParts = Collections.unmodifiableSet(new HashSet<>(Arrays + .asList(SLOW_DOWN, SPEED_UP, ROUNDABOUT, CROSSROAD, DESTINATION, START, STRAIGHT, TURN_LEFT, TURN_RIGHT))); + + public Motorbike(String registartionNumber, int maxSpeed, String producerName, boolean storageBox) { + super(registartionNumber, maxSpeed, producerName); + this.storageBox = storageBox; + } + + @Override + public String planeRoute(String start, String destination) { + List<RoutePartType> route = new ArrayList<>(); + Random r = new Random(Objects.hash(start, destination)); + int count = r.nextInt(30) + 8; + route.add(START); + List<RoutePartType> parts = Arrays.asList(CROSSROAD, SPEED_UP, SPEED_UP, SPEED_UP, SPEED_UP, SPEED_UP, SPEED_UP, + SPEED_UP, SPEED_UP, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, + STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, TURN_LEFT, TURN_RIGHT); + for (int i = 0; i < count; i++) { + route.add(Tools.randomElementFrom(parts, r)); + } + route.add(DESTINATION); + return route.stream().map(RoutePartType::getSign).collect(Collectors.joining()); + } + + @Override + public boolean isRouteAcceptable(String routeDescription) { + return RoutePartType.parse(routeDescription).stream().allMatch(part -> allowedRouteParts.contains(part)); + } + + public static Motorbike generateMotorbike() { + return new Motorbike(generateRegistrationNumber(), Tools.RANDOM.nextInt(150) + 180, + Tools.randomElementFrom(PRODUCERS), Tools.RANDOM.nextBoolean()); + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/NaturalPerson.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/NaturalPerson.java new file mode 100644 index 0000000000000000000000000000000000000000..4f4cc520786b8d40f560bcf5251a536f4a2cf8ea --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/NaturalPerson.java @@ -0,0 +1,42 @@ +package cz.vsb.fei.java2.lab06.entities; + +import java.time.LocalDate; + +import cz.vsb.fei.java2.lab06.Tools; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class NaturalPerson extends LegalPerson { + + @Column(nullable = false) + private String firstName; + @Column(nullable = false) + private String lastName; + + private LocalDate dayOfBirth; + + public NaturalPerson(String firstName, String lastName, String address, LocalDate dayOfBirth) { + super(address); + this.firstName = firstName; + this.lastName = lastName; + this.dayOfBirth = dayOfBirth; + } + + @Override + public String getFullName() { + return String.format("%s %s", getFirstName(), getLastName()); + } + + public static NaturalPerson generate() { + return new NaturalPerson(Tools.randomElementFrom(Tools.FIRST_NAMES), Tools.randomElementFrom(Tools.LAST_NAMES), + Tools.generateAddress(), Tools.generatePreviousDate()); + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/Route.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/Route.java new file mode 100644 index 0000000000000000000000000000000000000000..d9d126790a04b9b4f8a7cef2772ad86b3acc57a4 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/Route.java @@ -0,0 +1,60 @@ +package cz.vsb.fei.java2.lab06.entities; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import cz.vsb.fei.java2.lab06.Tools; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToMany; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@AllArgsConstructor +@ToString(callSuper = true) +public class Route extends BaseEntity { + + private String start; + private String destination; + private String description; + + private List<Vehicle> assignedCars; + + public static Route generate() { + return new Route(Tools.randomElementFrom(Tools.CITIES), Tools.randomElementFrom(Tools.CITIES), null, + new ArrayList<Vehicle>()); + } + + @AllArgsConstructor + @Getter + public enum RoutePartType { + START("↦"), STRAIGHT("âž™"), TURN_LEFT("⬏"), TURN_RIGHT("↴"), U_TURN("⮌"), CROSSROAD("⤨"), ROUNDABOUT("âĄ"), + SLOW_DOWN("⇝"), SPEED_UP("↠"), DESTINATION("⇥"); + + private String sign; + + public static RoutePartType of(String part) { + for (RoutePartType type : values()) { + if (Objects.equals(type.getSign(), part)) { + return type; + } + } + return null; + } + + public static List<RoutePartType> parse(String s) { + List<RoutePartType> result = new ArrayList<>(s.length()); + for (int i = 0; i < s.length(); i++) { + result.add(of(String.valueOf(s.charAt(i)))); + } + return result; + } + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/Truck.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/Truck.java new file mode 100644 index 0000000000000000000000000000000000000000..913d58770c1709610df701673d4e92122fcd80f4 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/Truck.java @@ -0,0 +1,71 @@ +package cz.vsb.fei.java2.lab06.entities; + +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.CROSSROAD; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.DESTINATION; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.SLOW_DOWN; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.START; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.STRAIGHT; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.TURN_LEFT; +import static cz.vsb.fei.java2.lab06.entities.Route.RoutePartType.TURN_RIGHT; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +import cz.vsb.fei.java2.lab06.Tools; +import cz.vsb.fei.java2.lab06.entities.Route.RoutePartType; +import jakarta.persistence.Entity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class Truck extends Vehicle { + + private static Set<RoutePartType> allowedRouteParts = Collections.unmodifiableSet( + new HashSet<>(Arrays.asList(SLOW_DOWN, CROSSROAD, DESTINATION, START, STRAIGHT, TURN_LEFT, TURN_RIGHT))); + + private int maxLoadVolume; + private int maxLoadWeight; + + public Truck(String registartionNumber, int maxSpeed, String producerName, int maxLoadVolume, int maxLoadWeight) { + super(registartionNumber, maxSpeed, producerName); + this.maxLoadVolume = maxLoadVolume; + this.maxLoadWeight = maxLoadWeight; + } + + @Override + public String planeRoute(String start, String destination) { + List<RoutePartType> route = new ArrayList<>(); + Random r = new Random(Objects.hash(start, destination)); + int count = r.nextInt(30) + 8; + route.add(START); + List<RoutePartType> parts = Arrays.asList(CROSSROAD, SLOW_DOWN, STRAIGHT, STRAIGHT, STRAIGHT, STRAIGHT, + STRAIGHT, TURN_LEFT, TURN_LEFT, TURN_LEFT, TURN_RIGHT, TURN_RIGHT, TURN_RIGHT); + for (int i = 0; i < count; i++) { + route.add(Tools.randomElementFrom(parts, r)); + } + route.add(DESTINATION); + return route.stream().map(RoutePartType::getSign).collect(Collectors.joining()); + } + + @Override + public boolean isRouteAcceptable(String routeDescription) { + return RoutePartType.parse(routeDescription).stream().allMatch(part -> allowedRouteParts.contains(part)); + } + + public static Truck generate() { + return new Truck(generateRegistrationNumber(), Tools.RANDOM.nextInt(100) + 80, + Tools.randomElementFrom(PRODUCERS), Tools.RANDOM.nextInt(500), Tools.RANDOM.nextInt(1000)); + } + +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/entities/Vehicle.java b/src/main/java/cz/vsb/fei/java2/lab06/entities/Vehicle.java new file mode 100644 index 0000000000000000000000000000000000000000..b8b0c7485d2bf0e93393857dcddd575b5f0c2938 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/entities/Vehicle.java @@ -0,0 +1,68 @@ +package cz.vsb.fei.java2.lab06.entities; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import cz.vsb.fei.java2.lab06.Tools; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public abstract class Vehicle extends BaseEntity { + + protected static final List<String> PRODUCERS = Collections.unmodifiableList(Arrays.asList("Toyota", "Volkswagen", + "BMW", "Mercedes-Benz", "Ford", "Audi", "Honda", "Chevrolet", "Nissan", "Hyundai", "Kia", "Tesla", "Subaru", + "Mazda", "Fiat", "Volvo", "Peugeot", "Renault", "Porsche", "Jaguar", "Land Rover", "Mitsubishi", "Suzuki", + "CitroĂ«n", "Dodge", "Jeep", "Chrysler", "Lexus", "Infiniti", "Acura", "Buick", "Cadillac", "Lincoln", "GMC", + "Alfa Romeo", "Mini", "Smart", "Dacia", "Seat", "Ĺ koda")); + + protected String registartionNumber; + + private int maxSpeed; + + private String producerName; + + private LegalPerson owner; + + @ToString.Exclude + private List<Route> planedRoute; + + protected Vehicle(String registartionNumber, int maxSpeed, String producerName) { + super(); + this.registartionNumber = registartionNumber; + this.maxSpeed = maxSpeed; + this.producerName = producerName; + } + + public abstract String planeRoute(String start, String destination); + + public abstract boolean isRouteAcceptable(String routeDescription); + + public static String generateRegistrationNumber() { + return String.format("%d%c%d-%04d", Tools.RANDOM.nextInt(9) + 1, Tools.RANDOM.nextInt('Z' - 'A') + 'A', + Tools.RANDOM.nextInt(9) + 1, Tools.RANDOM.nextInt(9999) + 1); + } + + public static Vehicle generate() { + switch (Tools.RANDOM.nextInt(3)) { + case 0: + return Car.generate(); + case 1: + return Truck.generate(); + case 2: + return Motorbike.generateMotorbike(); + default: + return null; + } + } +} diff --git a/src/main/java/cz/vsb/fei/java2/lab06/repositories/BaseRepository.java b/src/main/java/cz/vsb/fei/java2/lab06/repositories/BaseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..42e64c115cb74c6674372f15a0713367040613a2 --- /dev/null +++ b/src/main/java/cz/vsb/fei/java2/lab06/repositories/BaseRepository.java @@ -0,0 +1,51 @@ +package cz.vsb.fei.java2.lab06.repositories; + +import java.util.List; + +import cz.vsb.fei.java2.lab06.entities.BaseEntity; +import jakarta.persistence.EntityManager; + +public class BaseRepository<T extends BaseEntity> { + + protected EntityManager em; + private Class<T> clazz; + + public BaseRepository(EntityManager em, Class<T> clazz) { + this.em = em; + this.clazz = clazz; + } + + public T find(Long id) { + return em.find(clazz, id); + } + + public List<T> findAll() { + return em.createQuery(String.format("SELECT e FROM %s e", clazz.getName()), clazz).getResultList(); + } + + public T saveInTranasction(T entity) { + em.getTransaction().begin(); + entity = save(entity); + em.getTransaction().commit(); + return entity; + } + + public T save(T entity) { + if (entity.getId() == null || entity.getId() == 0) { + em.persist(entity); + } else { + entity = em.merge(entity); + } + return entity; + } + + public void remove(T entity) { + em.remove(entity); + } + + public void removeInTransaction(T entity) { + em.getTransaction().begin(); + remove(entity); + em.getTransaction().commit(); + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..d7baa2d08767ddf0ae7031cdf9f10e312da876e5 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,15 @@ +module cz.vsb.fei.java2.lab05 { + requires transitive javafx.controls; + requires javafx.fxml; + opens cz.vsb.fei.java2.lab06 to javafx.fxml; + exports cz.vsb.fei.java2.lab06; + + requires static lombok; + requires org.apache.logging.log4j; + + requires jakarta.persistence; + requires jakarta.annotation; + requires com.h2database; + opens cz.vsb.fei.java2.lab06.entities; + requires org.hibernate.orm.core; +} \ No newline at end of file diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000000000000000000000000000000000..010c3ffcca548866c2185ec1c96eaaf19b264c5c --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- JBoss, Home of Professional Open Source Copyright 2013, Red Hat, Inc. + and/or its affiliates, and individual contributors by the @authors tag. See + the copyright.txt in the distribution for a full listing of individual contributors. + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required + by applicable law or agreed to in writing, software distributed under the + License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + OF ANY KIND, either express or implied. See the License for the specific + language governing permissions and limitations under the License. --> +<persistence version="2.0" + xmlns="http://java.sun.com/xml/ns/persistence" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://java.sun.com/xml/ns/persistence + http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> + <persistence-unit name="java2" + transaction-type="RESOURCE_LOCAL"> + <!-- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> --> + + <!-- If you are running in a production environment, add a managed data + source, this example data source is just for development and testing! --> + <properties> + <!-- Properties for JPA (for any provider) --> + <!-- DB Apache Derby <property name="jakarta.persistence.jdbc.url" value="jdbc:derby:db/lab05;create=true" + /> <property name="jakarta.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" + /> --> + + <property name="jakarta.persistence.jdbc.url" + value="jdbc:h2:file:./db/java2" /> + <!-- In memory DB no store to disk <property name="jakarta.persistence.jdbc.url" + value="jdbc:h2:mem:java2" /> --> + <property name="jakarta.persistence.jdbc.driver" + value="org.h2.Driver" /> + + <property name="jakarta.persistence.jdbc.user" value="app" /> + <property name="jakarta.persistence.jdbc.password" + value="app" /> + <property + name="jakarta.persistence.schema-generation.database.action" + value="create"></property> + + <!-- Properties for Hibernate --> + <!-- property name="hibernate.enable_lazy_load_no_trans" + value="true" /--> + <property name="hibernate.show_sql" value="false" /> + <property name="hibernate.format_sql" value="true" /> + <!-- <property name="hibernate.hbm2ddl.auto" value="update" /> --> + + </properties> + </persistence-unit> + +</persistence> diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..acb3514078f6fb73f4f09ffd7a172b47f184e961 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ +<Configuration> + <Appenders> + <Console name="Console"> + <PatternLayout + pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> + </Console> + </Appenders> + <Loggers> + <Root level="info"> + <AppenderRef ref="Console"></AppenderRef> + </Root> + </Loggers> +</Configuration> diff --git a/src/test/java/cz/vsb/fei/java2/lab06/AppTest.java b/src/test/java/cz/vsb/fei/java2/lab06/AppTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7203982548d688f8fee68e8cefa3a55be91cfb9b --- /dev/null +++ b/src/test/java/cz/vsb/fei/java2/lab06/AppTest.java @@ -0,0 +1,19 @@ +package cz.vsb.fei.java2.lab06; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +class AppTest { + + /** + * Rigorous Test :-) + */ + @Test + void shouldAnswerWithTrue() { + assertTrue(true); + } +}