A Java console application that simulates a smart home controller managing multiple device types (lights, thermostats, and locks). The application intentionally contains bugs and missing features that you must implement across four tasks.
- Java 21+
- Maven 3.8+
mvn compile exec:java -Dexec.mainClass="com.bootcamp.smarthome.Main"src/main/java/com/bootcamp/smarthome/
├── Main.java # Entry point and demo scenarios
├── controller/
│ ├── CommandParser.java # Parses command strings
│ └── HomeController.java # Manages registered devices
└── device/
├── Device.java # Abstract base class
├── SmartLight.java # Dimmable light bulb
├── SmartThermostat.java # Programmable thermostat
└── SmartLock.java # PIN-protected door lock
Create the following exception classes in a new package com.bootcamp.smarthome.exception:
| Class | Type | Extends |
|---|---|---|
HomeAutomationException |
checked | Exception |
DeviceOfflineException |
checked | HomeAutomationException |
InvalidCommandException |
checked | HomeAutomationException |
DeviceNotFoundException |
unchecked | RuntimeException |
InvalidValueException |
checked | HomeAutomationException |
InvalidValueException must provide a constructor with the following signature:
public InvalidValueException(String field, Object value, String constraint)No changes to Main are required for this task.
Add validation and proper exception throwing to the following methods:
SmartLight.setBrightness(int level)— throwInvalidValueExceptionwhenlevelis outside[0, 100]SmartThermostat.setTemperature(double temp)— throwInvalidValueExceptionwhentempis outside[10.0, 35.0]SmartLock.validatePin(String pin)— throwInvalidCommandExceptionwhen the PIN isnullor does not matchHomeController.sendCommand(String fullCommand)— wrap the method body intry-catch-finally:- Catch
HomeAutomationException, then throw a newHomeAutomationExceptionwhose message includes thedeviceIdand the originalfullCommandstring (e.g."Command '" + fullCommand + "' failed for device '" + deviceId + "'") and pass the caught exception as thecauseargument — do not re-throw the original exception unchanged - The
finallyblock must always print:Command processing ended for device [id]
- Catch
Update Main to handle or declare all checked exceptions where needed.
- Add a
private static final Loggerfield toHomeControllerandSmartLock— use SLF4J (org.slf4j.Logger/org.slf4j.LoggerFactory):private static final Logger logger = LoggerFactory.getLogger(ClassName.class); - Log the following events in
HomeController:DEBUG— a command is received (include device ID and raw command)INFO— a command executed successfullyWARN— the target device is offline and the command is skippedERROR— an exception is caught during command processing
- Replace the corresponding
System.out.printlnstatements inHomeController.sendCommandwith these logger calls; remove the old print statements rather than keeping both SmartLockmust log atERRORevery failed unlock attempt (security audit trail) — replace the existingSystem.out.println("SECURITY ALERT: ...")line with the logger call- In
logback.xml, uncomment theFILEappender and register it in the root logger - Demonstration: change the root logger level to
WARN, run the app, and observe which log lines no longer appear in the output
The codebase contains four deliberate bugs. Use the debugger and stack traces to find and fix each one.
Run Main and read the exception output to locate the exact line:
NullPointerExceptioninSmartLock.validatePin()— triggered by scenario 6 (null PIN passed in)ArrayIndexOutOfBoundsExceptioninHomeController.findDevice()— triggered by scenario 7 (array is full, device not found)
Fix bug 1 first; bug 2 only becomes reachable after bug 1 is resolved.
The application does not crash, but produces incorrect output. Use breakpoints and the Variables / Watch panel to find the mistake:
SmartThermostat.setTemperature()silently accepts values outside the valid range — triggered by scenario 3 (temperature99.0should be rejected)CommandParser.extractCommand()drops the value part of commands that have one — triggered by scenario 2 (brightness should be set to80, not50)