diff --git a/.github/workflows/build-gradle.yml b/.github/workflows/build-gradle.yml new file mode 100644 index 0000000..06bfe16 --- /dev/null +++ b/.github/workflows/build-gradle.yml @@ -0,0 +1,18 @@ +name: Build with Gradle and run +on: [push, workflow_dispatch] + +jobs: + build_with_gradle: + runs-on: ubuntu-latest + steps: + - name: Get Repo + uses: actions/checkout@v4.1.5 + - name: Setup Java + uses: actions/setup-java@v4.2.1 + with: + java-version: 21 + distribution: 'temurin' + - name: Build Project with Gradle + run: gradle clean build + - name: Run Application + run: java -jar build/libs/java-trainee-edu-1.0-SNAPSHOT.jar diff --git a/.github/workflows/build-maven.yml b/.github/workflows/build-maven.yml new file mode 100644 index 0000000..73d92f2 --- /dev/null +++ b/.github/workflows/build-maven.yml @@ -0,0 +1,19 @@ +name: Build with Maven and run +on: [push, workflow_dispatch] + +jobs: + build_with_maven: + runs-on: ubuntu-latest + steps: + - name: Get Repo + uses: actions/checkout@v4.1.5 + - name: Setup Java + uses: actions/setup-java@v4.2.1 + with: + java-version: 21 + distribution: 'temurin' + cache: 'maven' + - name: Build Project with Maven + run: mvn clean package + - name: Run Application + run: java -jar java-trainee-edu/target/java-trainee-edu-1.0-SNAPSHOT.jar \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7eba534 --- /dev/null +++ b/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'java' + id 'application' +} + +group 'com.rtemi' +version '1.0-SNAPSHOT' + +java{ + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.1' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1' +} + +application { + mainClassName = 'com.rtemi.services.CustomDataStructures' +} + +jar { + manifest { + attributes( + 'Main-Class': 'com.rtemi.services.CustomDataStructures' + ) + } + +} diff --git a/pom.xml b/pom.xml index 0ab8a7a..899653e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.rtemi - trainee-edu-hw2 + java-trainee-edu 1.0-SNAPSHOT @@ -13,6 +13,34 @@ 21 UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + com.rtemi.services.CustomDataStructures + + + + + + + com.fasterxml.jackson.core diff --git a/screenshot/Screenshot_4.png b/screenshot/Screenshot_4.png deleted file mode 100644 index ab8a1f1..0000000 Binary files a/screenshot/Screenshot_4.png and /dev/null differ diff --git a/screenshot/busticketvalidator.png b/screenshot/busticketvalidator.png deleted file mode 100644 index a113e91..0000000 Binary files a/screenshot/busticketvalidator.png and /dev/null differ diff --git a/src/main/java/com/rtemi/model/ConcertTicket.java b/src/main/java/com/rtemi/model/ConcertTicket.java index 42b92f5..03bf02a 100644 --- a/src/main/java/com/rtemi/model/ConcertTicket.java +++ b/src/main/java/com/rtemi/model/ConcertTicket.java @@ -18,7 +18,7 @@ public class ConcertTicket extends TicketUID implements Printable, Shareable { private static final int WEIGHT_PRECISION = 3; private String concertTicketId; - @NullableWarning(key = "Variable [concertHall] is null in [Ticket]!”") + @NullableWarning(key = "Variable [concertHall] is null in [Ticket]!") private String concertHall; private int eventCode; private long ticketPurchaseTime; @@ -88,8 +88,7 @@ public String toString() { ", isPromo - " + isPromo + ", sector - " + sector + ", maxWeight - " + maxWeight.setScale(WEIGHT_PRECISION,RoundingMode.HALF_UP) + - ", ticketPrice - " + ticketPrice.setScale(PRICE_PRECISION,RoundingMode.HALF_UP) + - '}'; + ", ticketPrice - " + ticketPrice.setScale(PRICE_PRECISION,RoundingMode.HALF_UP); } @Override diff --git a/src/main/java/com/rtemi/model/CustomArrayList.java b/src/main/java/com/rtemi/model/CustomArrayList.java new file mode 100644 index 0000000..11d6e3c --- /dev/null +++ b/src/main/java/com/rtemi/model/CustomArrayList.java @@ -0,0 +1,77 @@ +package com.rtemi.model; +import java.util.Arrays; +import java.util.Arrays; + +/** + * Custom implementation of an ArrayList. + */ +public class CustomArrayList { + private static final int DEFAULT_CAPACITY = 10; + private Object[] elements; + private int size = 0; + + public CustomArrayList() { + elements = new Object[DEFAULT_CAPACITY]; + } + + /** + * Adds an element to the list. + * @param element The element to add. + */ + public void put(T element) { + if (size == elements.length) { + resize(); + } + elements[size++] = element; + } + + /** + * Gets an element by its index. + * @param index The index of the element. + * @return The element at the specified index. + * @throws IndexOutOfBoundsException if the index is out of range. + */ + @SuppressWarnings("unchecked") + public T get(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + return (T) elements[index]; + } + + /** + * Removes an element by its index. + * @param index The index of the element to remove. + * @return The removed element. + * @throws IndexOutOfBoundsException if the index is out of range. + */ + @SuppressWarnings("unchecked") + public T delete(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + T element = (T) elements[index]; + int numMoved = size - index - 1; + if (numMoved > 0) { + System.arraycopy(elements, index + 1, elements, index, numMoved); + } + elements[--size] = null; // clear to let GC do its work + return element; + } + + /** + * Returns the size of the list. + * @return The size of the list. + */ + public int size() { + return size; + } + + /** + * Resizes the internal array to accommodate more elements. + */ + private void resize() { + int newSize = elements.length * 2; + elements = Arrays.copyOf(elements, newSize); + } +} diff --git a/src/main/java/com/rtemi/model/CustomHashSet.java b/src/main/java/com/rtemi/model/CustomHashSet.java new file mode 100644 index 0000000..d5f61cc --- /dev/null +++ b/src/main/java/com/rtemi/model/CustomHashSet.java @@ -0,0 +1,121 @@ +package com.rtemi.model; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * Custom implementation of a HashSet. + */ +public class CustomHashSet implements Iterable { + private static final int DEFAULT_CAPACITY = 16; + private static final float LOAD_FACTOR = 0.75f; + private LinkedList[] buckets; + private int size = 0; + + public CustomHashSet() { + buckets = new LinkedList[DEFAULT_CAPACITY]; + } + + /** + * Adds an element to the set. + * @param element The element to add. + */ + public void put(T element) { + if (contains(element)) { + return; + } + if (size + 1 > LOAD_FACTOR * buckets.length) { + resize(); + } + int index = getIndex(element); + if (buckets[index] == null) { + buckets[index] = new LinkedList<>(); + } + buckets[index].add(element); + size++; + } + + /** + * Checks if the set contains the specified element. + * @param element The element to check. + * @return True if the set contains the element, false otherwise. + */ + public boolean contains(T element) { + int index = getIndex(element); + LinkedList bucket = buckets[index]; + return bucket != null && bucket.contains(element); + } + + /** + * Removes an element from the set. + * @param element The element to remove. + * @return True if the element was removed, false otherwise. + */ + public boolean remove(T element) { + int index = getIndex(element); + LinkedList bucket = buckets[index]; + if (bucket != null && bucket.remove(element)) { + size--; + return true; + } + return false; + } + + /** + * Returns the size of the set. + * @return The size of the set. + */ + public int size() { + return size; + } + + /** + * Returns an iterator over the elements in the set. + * @return An iterator. + */ + @Override + public Iterator iterator() { + return new Iterator() { + private int bucketIndex = 0; + private Iterator bucketIterator = buckets[bucketIndex] == null ? null : buckets[bucketIndex].iterator(); + + @Override + public boolean hasNext() { + while ((bucketIterator == null || !bucketIterator.hasNext()) && bucketIndex < buckets.length - 1) { + bucketIndex++; + bucketIterator = buckets[bucketIndex] == null ? null : buckets[bucketIndex].iterator(); + } + return bucketIterator != null && bucketIterator.hasNext(); + } + + @Override + public T next() { + return bucketIterator.next(); + } + }; + } + + /** + * Gets the index of the bucket for the specified element. + * @param element The element. + * @return The index of the bucket. + */ + private int getIndex(T element) { + return element == null ? 0 : Math.abs(element.hashCode() % buckets.length); + } + + /** + * Resizes the internal array to accommodate more elements. + */ + private void resize() { + LinkedList[] oldBuckets = buckets; + buckets = new LinkedList[oldBuckets.length * 2]; + size = 0; + for (LinkedList bucket : oldBuckets) { + if (bucket != null) { + for (T element : bucket) { + put(element); + } + } + } + } +} diff --git a/src/main/java/com/rtemi/services/BusTicketService.java b/src/main/java/com/rtemi/services/BusTicketService.java new file mode 100644 index 0000000..18a8a05 --- /dev/null +++ b/src/main/java/com/rtemi/services/BusTicketService.java @@ -0,0 +1,91 @@ +package com.rtemi.services; + +import com.rtemi.interfaces.Printable; +import com.rtemi.model.BusTicket; +import com.rtemi.model.TicketUID; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * Service class to manage bus tickets. + * Provides functionalities to create, store, remove, and search bus tickets. + */ +public class BusTicketService extends TicketUID implements Printable { + private static List ticketList = new ArrayList<>(); + private static AtomicInteger idCounter = new AtomicInteger(); + /** + * Creates a new bus ticket and stores it in memory. + * @param ticketClass The class of the ticket (e.g., Standard, VIP, Super). + * @param ticketType The type of the ticket (e.g., Month, Year, Daily). + * @param startDate The start date of the ticket. + * @param price The price of the ticket. + * @return The created BusTicket. + */ + public BusTicket createBusTicket(String ticketClass, String ticketType, String startDate, BigDecimal price) { + BusTicket ticket = new BusTicket(startDate, ticketType, ticketClass, price); + ticket.setTicketUid(idCounter.incrementAndGet()); + ticketList.add(ticket); + return ticket; + } + + public boolean removeBusTicketById(int ticketUID) { + return ticketList.removeIf(ticket -> ticket.getTicketUid() == ticketUID); + } + + public BusTicket getTicketById(int ticketUID) { + Optional ticket = ticketList.stream() + .filter(t -> t.getTicketUid() == ticketUID) + .findFirst(); + return ticket.orElse(null); + } + /** + * Searches for bus tickets by type and price range. + * @param ticketType The type of the ticket. + * @param minPrice The minimum price. + * @param maxPrice The maximum price. + * @return A list of matching BusTickets. + */ + public static List searchTicketsByTypeAndPrice(String ticketType, BigDecimal minPrice, BigDecimal maxPrice) { + return ticketList.stream() + .filter(ticket -> ticket.getTicketType().equalsIgnoreCase(ticketType) + && ticket.getPrice().compareTo(minPrice) >= 0 + && ticket.getPrice().compareTo(maxPrice) <= 0) + .collect(Collectors.toList()); + } + + public static void main(String[] args) { + BusTicketService service = new BusTicketService(); + + System.out.println(service.createBusTicket("STD", "MONTH", "2024-06-27", BigDecimal.valueOf(100))); + System.out.println(service.createBusTicket("SUP", "YEAR", "2024-06-28", BigDecimal.valueOf(500))); + System.out.println(service.createBusTicket("VIP", "DAY", "2024-06-29", BigDecimal.valueOf(1000))); + + for (int i = 0; i < ticketList.size(); i++) { + System.out.println(ticketList.get(i).getTicketUid() +" "+ ticketList.get(i) ); + } + + // Get and print a ticket by ID + BusTicket ticket = service.getTicketById(1); + if (ticket != null) { + ticket.toString(); + } + + // Search and print tickets by type and price range + List searchedTickets = service.searchTicketsByTypeAndPrice("Economy", new BigDecimal("10.00"), new BigDecimal("16.00")); + searchedTickets.forEach(ticket1 -> System.out.println(ticket1)); + + // Remove a ticket by ID + boolean removed = service.removeBusTicketById(1); + System.out.println("Ticket with ID 1 removed: " + removed); + + for (int i = 0; i < ticketList.size(); i++) { + System.out.println(ticketList.get(i).getTicketUid() +" "+ ticketList.get(i) ); + } + } + +} diff --git a/src/main/java/com/rtemi/services/CustomDataStructures.java b/src/main/java/com/rtemi/services/CustomDataStructures.java new file mode 100644 index 0000000..88c761f --- /dev/null +++ b/src/main/java/com/rtemi/services/CustomDataStructures.java @@ -0,0 +1,32 @@ +package com.rtemi.services; + +import com.rtemi.model.CustomArrayList; +import com.rtemi.model.CustomHashSet; + +public class CustomDataStructures { + public static void main(String[] args) { + CustomArrayList customArrayList = new CustomArrayList<>(); + customArrayList.put(1); + customArrayList.put(2); + customArrayList.put(3); + System.out.println("ArrayList size: " + customArrayList.size()); + System.out.println("Element at index 1: " + customArrayList.get(1)); + customArrayList.delete(1); + System.out.println("Element at index 1 after removing: " + customArrayList.get(1)); + + + CustomHashSet customHashSet = new CustomHashSet<>(); + customHashSet.put("a"); + customHashSet.put("b"); + customHashSet.put("c"); + System.out.println("HashSet size: " + customHashSet.size()); + System.out.println("Contains 'a': " + customHashSet.contains("a")); + customHashSet.remove("a"); + System.out.println("Contains 'a' after removal: " + customHashSet.contains("a")); + + System.out.println("Iterating over CustomHashSet:"); + for (String s : customHashSet) { + System.out.println(s); + } + } +}