MaterialService.java
package com.university.bookstore.service;
import java.util.List;
import java.util.Optional;
import com.university.bookstore.model.Material;
import com.university.bookstore.repository.MaterialRepository;
/**
* Domain service that orchestrates business logic for material management.
* Demonstrates hexagonal architecture by coordinating between domain logic and infrastructure.
*
* <p>This service encapsulates business rules and coordinates between the domain layer
* and the repository layer, maintaining clean separation of concerns.</p>
*
* @author Navid Mohaghegh
* @version 3.0
* @since 2024-09-15
*/
public class MaterialService {
private final MaterialRepository repository;
/**
* Creates a new material service with the specified repository.
*
* @param repository the material repository to use
*/
public MaterialService(MaterialRepository repository) {
this.repository = repository;
}
/**
* Adds a material to the system with business logic validation.
*
* @param material the material to add
* @throws InvalidMaterialException if the material is invalid
*/
public void addMaterial(Material material) {
validateMaterial(material);
repository.save(material);
}
/**
* Updates an existing material with business logic validation.
*
* @param material the material to update
* @throws InvalidMaterialException if the material is invalid
* @throws MaterialNotFoundException if the material doesn't exist
*/
public void updateMaterial(Material material) {
validateMaterial(material);
if (!repository.exists(material.getId())) {
throw new MaterialNotFoundException("Material not found: " + material.getId());
}
repository.save(material);
}
/**
* Finds a material by its ID.
*
* @param id the material ID
* @return the material if found
* @throws MaterialNotFoundException if the material doesn't exist
*/
public Material findMaterial(String id) {
return repository.findById(id)
.orElseThrow(() -> new MaterialNotFoundException("Material not found: " + id));
}
/**
* Finds a material by its ID, returning Optional.
*
* @param id the material ID
* @return Optional containing the material if found
*/
public Optional<Material> findMaterialOptional(String id) {
return repository.findById(id);
}
/**
* Gets all materials in the system.
*
* @return list of all materials
*/
public List<Material> getAllMaterials() {
return repository.findAll();
}
/**
* Removes a material from the system.
*
* @param id the material ID to remove
* @return true if the material was removed, false if not found
*/
public boolean removeMaterial(String id) {
return repository.delete(id);
}
/**
* Checks if a material exists in the system.
*
* @param id the material ID
* @return true if the material exists
*/
public boolean materialExists(String id) {
return repository.exists(id);
}
/**
* Gets the total number of materials in the system.
*
* @return the material count
*/
public long getMaterialCount() {
return repository.count();
}
/**
* Clears all materials from the system.
*/
public void clearAllMaterials() {
repository.deleteAll();
}
/**
* Validates a material according to business rules.
*
* @param material the material to validate
* @throws InvalidMaterialException if validation fails
*/
private void validateMaterial(Material material) {
if (material == null) {
throw new InvalidMaterialException("Material cannot be null");
}
if (material.getId() == null || material.getId().trim().isEmpty()) {
throw new InvalidMaterialException("Material ID cannot be null or empty");
}
if (material.getTitle() == null || material.getTitle().trim().isEmpty()) {
throw new InvalidMaterialException("Material title cannot be null or empty");
}
if (material.getCreator() == null || material.getCreator().trim().isEmpty()) {
throw new InvalidMaterialException("Material creator cannot be null or empty");
}
if (material.getPrice() < 0) {
throw new InvalidMaterialException("Material price cannot be negative: " + material.getPrice());
}
if (material.getYear() < 1000 || material.getYear() > 2100) {
throw new InvalidMaterialException("Material year must be between 1000 and 2100: " + material.getYear());
}
}
/**
* Exception thrown when a material is invalid according to business rules.
*/
public static class InvalidMaterialException extends RuntimeException {
private static final long serialVersionUID = 1L;
public InvalidMaterialException(String message) {
super(message);
}
public InvalidMaterialException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* Exception thrown when a requested material is not found.
*/
public static class MaterialNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MaterialNotFoundException(String message) {
super(message);
}
public MaterialNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
}