InventoryObserver.java
package com.university.bookstore.observer;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.university.bookstore.model.Material;
/**
* Observer that tracks inventory changes for materials.
* Maintains counts and statistics for materials in the system.
*
* @author Navid Mohaghegh
* @version 3.0
* @since 2024-09-15
*/
public class InventoryObserver implements MaterialObserver {
private static final Logger LOGGER = LoggerFactory.getLogger(InventoryObserver.class);
private final Map<String, Integer> inventoryCounts;
private final Map<String, Double> totalValue;
private int totalEvents;
/**
* Creates a new inventory observer.
*/
public InventoryObserver() {
this.inventoryCounts = new HashMap<>();
this.totalValue = new HashMap<>();
this.totalEvents = 0;
}
@Override
public void onEvent(MaterialEvent event) {
totalEvents++;
switch (event.getEventType()) {
case "MATERIAL_ADDED":
handleMaterialAdded(event);
break;
case "PRICE_CHANGED":
handlePriceChanged(event);
break;
default:
// Handle other event types if needed
break;
}
}
/**
* Handles material added events.
*/
private void handleMaterialAdded(MaterialEvent event) {
Material material = event.getMaterial();
String materialId = material.getId();
// Update inventory count
inventoryCounts.merge(materialId, 1, Integer::sum);
// Update total value
totalValue.merge(materialId, material.getPrice(), Double::sum);
LOGGER.info("Inventory updated: {} count: {}",
materialId, inventoryCounts.get(materialId));
}
/**
* Handles price changed events.
*/
private void handlePriceChanged(MaterialEvent event) {
if (event instanceof PriceChangedEvent) {
PriceChangedEvent priceEvent = (PriceChangedEvent) event;
Material material = event.getMaterial();
String materialId = material.getId();
// Update total value with the price change
double priceChange = priceEvent.getPriceChange();
totalValue.merge(materialId, priceChange, Double::sum);
LOGGER.info("Price changed for {}: ${} -> ${}",
material.getTitle(), priceEvent.getOldPrice(), priceEvent.getNewPrice());
}
}
/**
* Gets the inventory count for a specific material.
*
* @param materialId the material ID
* @return the inventory count
*/
public int getInventoryCount(String materialId) {
return inventoryCounts.getOrDefault(materialId, 0);
}
/**
* Gets the total value for a specific material.
*
* @param materialId the material ID
* @return the total value
*/
public double getTotalValue(String materialId) {
return totalValue.getOrDefault(materialId, 0.0);
}
/**
* Gets the total number of materials in inventory.
*
* @return the total count
*/
public int getTotalInventoryCount() {
return inventoryCounts.values().stream()
.mapToInt(Integer::intValue)
.sum();
}
/**
* Gets the total value of all materials in inventory.
*
* @return the total value
*/
public double getTotalInventoryValue() {
return totalValue.values().stream()
.mapToDouble(Double::doubleValue)
.sum();
}
/**
* Gets the number of unique materials in inventory.
*
* @return the unique material count
*/
public int getUniqueMaterialCount() {
return inventoryCounts.size();
}
/**
* Gets the total number of events processed.
*
* @return the event count
*/
public int getTotalEvents() {
return totalEvents;
}
/**
* Gets all inventory counts.
*
* @return map of material ID to count
*/
public Map<String, Integer> getAllInventoryCounts() {
return new HashMap<>(inventoryCounts);
}
/**
* Gets all total values.
*
* @return map of material ID to total value
*/
public Map<String, Double> getAllTotalValues() {
return new HashMap<>(totalValue);
}
/**
* Clears all inventory data.
*/
public void clear() {
inventoryCounts.clear();
totalValue.clear();
totalEvents = 0;
}
@Override
public String getObserverName() {
return "InventoryObserver";
}
@Override
public String toString() {
return String.format("InventoryObserver[Materials=%d, TotalCount=%d, TotalValue=$%.2f, Events=%d]",
getUniqueMaterialCount(), getTotalInventoryCount(), getTotalInventoryValue(), getTotalEvents());
}
}