Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>25</source>
<target>25</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
37 changes: 37 additions & 0 deletions src/main/java/com/example/Category.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example;

import java.util.HashMap;
import java.util.Map;

public final class Category {
private static final Map<String, Category> CACHE = new HashMap<>();
private final String name;

private Category(String name) {
this.name = name;
}

public static Category of(String name) {
if (name == null) {
throw new IllegalArgumentException("Category name can't be null");
}

if (name.isBlank()) {
throw new IllegalArgumentException("Category name can't be blank");
}

String trimmed = name.trim();

String normalized = trimmed.substring(0, 1).toUpperCase() + trimmed.substring(1).toLowerCase();

return CACHE.computeIfAbsent(normalized, Category::new);
}

public String name() {
return name;
}

public String getName() {
return name;
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/example/ElectronicsProduct.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.example;

import java.math.BigDecimal;
import java.util.UUID;

public class ElectronicsProduct extends Product implements Shippable {
private final int warrantyMonths;
private final BigDecimal weight;

public ElectronicsProduct(UUID id,
String name,
Category category,
BigDecimal price,
int warrantyMonths,
BigDecimal weight) {

super(id, name, category, price);

if (warrantyMonths < 0) {
throw new IllegalArgumentException("Warranty months cannot be negative.");
}

this.warrantyMonths = warrantyMonths;
this.weight = weight;
}

@Override
public String productDetails() {
return "Electronics: " + name() + ", Warranty: " + warrantyMonths + " months";
}

@Override
public BigDecimal calculateShippingCost() {
BigDecimal base = BigDecimal.valueOf(79);
if (weight.compareTo(BigDecimal.valueOf(5)) > 0) {
base = base.add(BigDecimal.valueOf(49));
}
return base;
}

@Override
public double weight() {
return weight.doubleValue();
}
}
55 changes: 55 additions & 0 deletions src/main/java/com/example/FoodProduct.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.example;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;

public class FoodProduct extends Product implements Perishable, Shippable {
private final LocalDate expirationDate;
private final BigDecimal weight;

public FoodProduct(UUID id,
String name,
Category category,
BigDecimal price,
LocalDate expirationDate,
BigDecimal weight) {

if (expirationDate == null) {
throw new IllegalArgumentException("Expiration Date cannot be null.");
}

if (price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Price cannot be negative.");
}

if (weight.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Weight cannot be negative.");
}

super(id, name, category, price);

this.expirationDate = expirationDate;
this.weight = weight;
}

@Override
public String productDetails() {
return "Food: " + name() + ", Expires: " + expirationDate;
}

@Override
public BigDecimal calculateShippingCost() {
return weight.multiply(BigDecimal.valueOf(50));
}

@Override
public LocalDate expirationDate() {
return expirationDate;
}

@Override
public double weight() {
return weight.doubleValue();
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/example/Perishable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example;

import java.time.LocalDate;

public interface Perishable {
LocalDate expirationDate();

default boolean isExpired() {
return expirationDate().isBefore(LocalDate.now());
}
}
40 changes: 40 additions & 0 deletions src/main/java/com/example/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.UUID;

public abstract class Product {
private final UUID id;
private final String name;
private final Category category;
private BigDecimal price;

protected Product(UUID id, String name, Category category, BigDecimal price) {
this.id = id;
this.name = name;
this.category = category;
this.price = price;
}

public UUID uuid() {
return id;
}

public String name() {
return name;
}

public Category category() {
return category;
}

public BigDecimal price() {
return price.setScale(2, RoundingMode.HALF_UP);
}

public void price(BigDecimal price) {
this.price = price;
}
public abstract String productDetails();
}
8 changes: 8 additions & 0 deletions src/main/java/com/example/Shippable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example;

import java.math.BigDecimal;

public interface Shippable {
BigDecimal calculateShippingCost();
double weight();
}
92 changes: 92 additions & 0 deletions src/main/java/com/example/Warehouse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.example;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class Warehouse {
private static final Map<String, Warehouse> INSTANCES = new HashMap<>();
private final Map<UUID, Product> products = new HashMap<>();
private final Set<Product> changedProducts = new HashSet<>();

private Warehouse(String name) {
}

public static Warehouse getInstance(String name) {
return INSTANCES.computeIfAbsent(name, Warehouse::new);
}

public void addProduct(Product product) {
if (product == null) {
throw new IllegalArgumentException("Product cannot be null.");
}
if (products.containsKey(product.uuid())) {
throw new IllegalArgumentException("Product with that id already exists, use updateProduct for updates.");
}
products.put(product.uuid(), product);
}

public List<Product> getProducts() {
return List.copyOf(products.values());
}

public Optional<Product> getProductById(UUID id) {
return Optional.ofNullable(products.get(id));
}

public void updateProductPrice(UUID id, BigDecimal newPrice) {
Product product = products.get(id);
if (product == null) {
throw new NoSuchElementException("Product not found with id: " + id);
}
product.price(newPrice);
changedProducts.add(product);
}

public List<FoodProduct> expiredProducts() {
List<FoodProduct> expired = new ArrayList<>();
for (Product p : products.values()) {
if (p instanceof FoodProduct foodProduct && foodProduct.isExpired()) {
expired.add(foodProduct);
}
}
return Collections.unmodifiableList(expired);
}

public List<Shippable> shippableProducts() {
List<Shippable> out = new ArrayList<>();
for (Product p : products.values()) {
if (p instanceof Shippable s) {
out.add(s);
}
}
return Collections.unmodifiableList(out);
}

public void remove(UUID id) {
Product removedProduct = products.remove(id);
if (removedProduct != null) {
changedProducts.remove(removedProduct);
}
}

public void clearProducts() {
products.clear();
changedProducts.clear();
}

public boolean isEmpty() {
return products.isEmpty();
}

public static Warehouse getInstance() {
return getInstance("Default");
}

public Map<Category, List<Product>> getProductsGroupedByCategories() {
return products.values()
.stream()
.collect(Collectors.groupingBy(Product :: category));
}

}
Loading
Loading