A Java application for managing cars and tracking fuel consumption, built with plain Java, embedded Jetty server, and manual servlet implementation.
car-management/
├── pom.xml (parent)
├── backend/
│ ├── pom.xml
│ └── src/main/java/com/codehills/carmanagement/
│ ├── Server.java (main class)
│ ├── domain/
│ │ ├── Car.java
│ │ ├── FuelEntry.java
│ │ └── FuelStats.java
│ ├── repository/
│ │ ├── CarRepository.java
│ │ └── FuelRepository.java
│ ├── service/
│ │ ├── CarService.java
│ │ └── FuelService.java
│ ├── servlet/
│ │ ├── CarServlet.java
│ │ ├── FuelServlet.java
│ │ └── FuelStatsServlet.java
│ ├── exception/
│ │ ├── CarNotFoundException.java
│ │ └── InvalidInputException.java
│ └── util/
│ ├── JsonUtil.java
│ └── ServiceLocator.java
└── cli/
├── pom.xml
└── src/main/java/com/codehills/cli/
├── CarManagementCli.java
├── client/
│ └── ApiClient.java
└── parser/
└── CommandParser.java
- Java 11 or higher
- Maven 3.6 or higher
Build all modules:
mvn clean installThis will:
- Compile all modules
- Create executable JARs in
backend/target/andcli/target/
After building, run:
cd backend
java -jar target/backend-1.0-SNAPSHOT.jarThe server will start on port 8080 by default. You can specify a custom port:
java -jar target/backend-1.0-SNAPSHOT.jar 9090cd backend
mvn exec:java -Dexec.mainClass=com.codehills.carmanagement.ServerAfter building, run:
cd cli
java -jar target/cli-1.0-SNAPSHOT.jar <command> [options]cd cli
mvn exec:java -Dexec.mainClass=com.codehills.cli.CarManagementCli -Dexec.args="create-car --brand Toyota --model Corolla --year 2018"create-car --brand <brand> --model <model> --year <year>Example:
java -jar target/cli-1.0-SNAPSHOT.jar create-car --brand Toyota --model Corolla --year 2018add-fuel --carId <id> --liters <liters> --price <price> --odometer <odometer>Note: The price parameter represents the total cost for this fill-up, not price per liter.
Example:
java -jar target/cli-1.0-SNAPSHOT.jar add-fuel --carId 1 --liters 40 --price 50.0 --odometer 43125
java -jar target/cli-1.0-SNAPSHOT.jar add-fuel --carId 1 --liters 40 --price 52.5 --odometer 44000
java -jar target/cli-1.0-SNAPSHOT.jar add-fuel --carId 1 --liters 40 --price 52.5 --odometer 45000fuel-stats --carId <id>Example:
java -jar target/cli-1.0-SNAPSHOT.jar fuel-stats --carId 1Expected Output:
Total fuel: 120.0 L
Total cost: 155.00
Average consumption: 6.4 L/100km
POST /api/cars
Request Body:
{
"brand": "Toyota",
"model": "Corolla",
"year": 2018
}Response: 201 Created
{
"id": 1,
"brand": "Toyota",
"model": "Corolla",
"year": 2018
}GET /api/cars
Response: 200 OK
[
{
"id": 1,
"brand": "Toyota",
"model": "Corolla",
"year": 2018
}
]POST /api/cars/{id}/fuel
Request Body:
{
"liters": 40,
"price": 52.5,
"odometer": 45000
}Note: The price field represents the total cost for this fill-up, not price per liter.
Response: 201 Created
{
"id": 1,
"carId": 1,
"liters": 40.0,
"price": 52.5,
"odometer": 45000,
"timestamp": "2024-01-01T10:00:00"
}GET /api/cars/{id}/fuel/stats
Response: 200 OK
{
"totalFuel": 120.0,
"totalCost": 155.0,
"averageConsumption": 6.4
}GET /servlet/fuel-stats?carId={id}
This endpoint demonstrates manual servlet implementation with:
- Manual query parameter parsing
- Explicit content type setting
- Manual status code handling
Response: 200 OK
{
"totalFuel": 120.0,
"totalCost": 155.0,
"averageConsumption": 6.4
}- Total Fuel: Sum of all liters from fuel entries
- Total Cost: Sum of all prices (total cost per fill-up)
- Average Consumption:
(Total Fuel / Total Distance) * 100in L/100km- Requires at least 2 fuel entries
- Total Distance = maxOdometer - minOdometer
The API returns appropriate HTTP status codes:
- 200 OK: Successful GET request
- 201 Created: Successful POST request
- 400 Bad Request: Invalid input or validation error
- 404 Not Found: Car not found
- 500 Internal Server Error: Server error
Error responses follow this format:
{
"error": "Error message",
"status": 400
}- Backend: Plain Java 11+ with embedded Jetty server
- Dependencies:
- Jetty Server & Servlet API (embedded)
- Jackson (for JSON)
- SLF4J + Logback (logging)
- CLI: Plain Java with
java.net.http.HttpClient - Build: Maven multi-module
- ✅ In-memory storage (thread-safe using ConcurrentHashMap)
- ✅ Manual servlet implementation (demonstrates servlet lifecycle knowledge)
- ✅ RESTful API endpoints
- ✅ CLI client using HttpClient
- ✅ Comprehensive error handling
- ✅ Proper HTTP status codes
- ✅ JSON serialization/deserialization
-
Start the server:
cd backend java -jar target/backend-1.0-SNAPSHOT.jar -
Create a car:
curl -X POST http://localhost:8080/api/cars \ -H "Content-Type: application/json" \ -d '{"brand":"Toyota","model":"Corolla","year":2018}'
-
Add fuel entries:
curl -X POST http://localhost:8080/api/cars/1/fuel \ -H "Content-Type: application/json" \ -d '{"liters":40,"price":52.5,"odometer":45000}'
-
Get fuel statistics:
curl http://localhost:8080/api/cars/1/fuel/stats
-
Ensure the backend server is running
-
Create a car:
cd cli java -jar target/cli-1.0-SNAPSHOT.jar create-car --brand Toyota --model Corolla --year 2018 -
Add fuel entries:
java -jar target/cli-1.0-SNAPSHOT.jar add-fuel --carId 1 --liters 40 --price 52.5 --odometer 45000
-
Get fuel statistics:
java -jar target/cli-1.0-SNAPSHOT.jar fuel-stats --carId 1
- The
pricefield in fuel entries represents the total cost for the fill-up, not price per liter - Fuel consumption calculation requires at least 2 fuel entries
- All data is stored in-memory and will be lost when the server stops
- The server runs on port 8080 by default
This project is part of a technical assignment.