Functional Scope (In-Scope)
- Room Search & Filters: Fetch available room items matching active date ranges and type selections.
- Overlap Interval Checker: Accurately verify check-in check-out ranges to avoid booking collisions.
- Concurrent Booking Prevents: Optimistically or pessimistically lock rooms during reservation pipelines using fine-grained locks to prevent double-booking.
- Structured Cancellation Strategy: Tiered cancellation refund strategies matching flexible vs non-refundable structures.
Explicit Boundaries (Out-of-Scope)
- No Hardware Access Key Integration: Ignores physical card key printing interfaces or lock hardware.
- No Dynamic flight/cab Combos: Strictly manages room logs rather than third-party inventory.
Practical reference designs showing booking security in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
enum RoomType { SINGLE, DOUBLE, SUITE }
interface CancellationStrategy {
double calculateRefund(double paidAmount, long checkInTime, long cancelTime);
}
class FlexibleCancellationStrategy implements CancellationStrategy {
@Override
public double calculateRefund(double paidAmount, long checkInTime, long cancelTime) {
long hoursToCheckIn = (checkInTime - cancelTime) / (1000 * 60 * 60);
if (hoursToCheckIn >= 48) {
return paidAmount; // 100% refund
} else if (hoursToCheckIn >= 24) {
return paidAmount * 0.5; // 50% refund
}
return 0.0; // No refund
}
}
class NonRefundableCancellationStrategy implements CancellationStrategy {
@Override
public double calculateRefund(double paidAmount, long checkInTime, long cancelTime) {
return 0.0; // Always 0% refund
}
}
class Room {
private final String id;
private final RoomType type;
private final double basePrice;
private final ReentrantLock lock = new ReentrantLock();
public Room(String id, RoomType type, double basePrice) {
this.id = id;
this.type = type;
this.basePrice = basePrice;
}
public String getId() { return id; }
public RoomType getType() { return type; }
public double getBasePrice() { return basePrice; }
public ReentrantLock getLock() { return lock; }
}
class Reservation {
private final String id;
private final String guestName;
private final Room room;
private final long checkIn;
private final long checkOut;
private final double cost;
private volatile boolean cancelled = false;
public Reservation(String id, String guest, Room room, long in, long out, double cost) {
this.id = id;
this.guestName = guest;
this.room = room;
this.checkIn = in;
this.checkOut = out;
this.cost = cost;
}
public String getId() { return id; }
public Room getRoom() { return room; }
public long getCheckIn() { return checkIn; }
public long getCheckOut() { return checkOut; }
public double getCost() { return cost; }
public boolean isCancelled() { return cancelled; }
public void cancel() { this.cancelled = true; }
public boolean overlaps(long start, long end) {
return !cancelled && checkIn < end && start < checkOut;
}
}
class HotelBookingService {
private final Map<String, Room> rooms = new ConcurrentHashMap<>();
private final List<Reservation> reservations = new CopyOnWriteArrayList<>();
private final CancellationStrategy cancellationStrategy;
public HotelBookingService(CancellationStrategy cancellationStrategy) {
this.cancellationStrategy = cancellationStrategy;
}
public void addRoom(Room r) { rooms.put(r.getId(), r); }
public List<Room> findAvailableRooms(long checkIn, long checkOut, RoomType type) {
List<Room> available = new ArrayList<>();
for (Room room : rooms.values()) {
if (room.getType() != type) continue;
boolean isFree = true;
for (Reservation res : reservations) {
if (res.getRoom().getId().equals(room.getId()) && res.overlaps(checkIn, checkOut)) {
isFree = false;
break;
}
}
if (isFree) {
available.add(room);
}
}
return available;
}
public Reservation bookRoom(String guest, String roomId, long checkIn, long checkOut) {
Room room = rooms.get(roomId);
if (room == null) return null;
// Fine-grained lock per room ensures high throughput compared to global locking
room.getLock().lock();
try {
// Double check availability (Check-then-Act)
for (Reservation res : reservations) {
if (res.getRoom().getId().equals(roomId) && res.overlaps(checkIn, checkOut)) {
System.out.println("[Booking Error] Room " + roomId + " is already booked for these dates!");
return null;
}
}
long days = Math.max(1, (checkOut - checkIn) / (1000 * 60 * 60 * 24));
double totalCost = days * room.getBasePrice();
String resId = "RES-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
Reservation reservation = new Reservation(resId, guest, room, checkIn, checkOut, totalCost);
reservations.add(reservation);
System.out.println("[Booking Success] Guest " + guest + " booked room " + roomId + " (Cost: $" + totalCost + ")");
return reservation;
} finally {
room.getLock().unlock();
}
}
public double cancelReservation(String reservationId, long cancelTime) {
for (Reservation res : reservations) {
if (res.getId().equals(reservationId)) {
res.getRoom().getLock().lock();
try {
if (res.isCancelled()) {
System.out.println("[Cancellation Error] Reservation already cancelled.");
return 0.0;
}
res.cancel();
double refund = cancellationStrategy.calculateRefund(res.getCost(), res.getCheckIn(), cancelTime);
System.out.println("[Cancellation Success] Refund processed: $" + refund + " for reservation " + reservationId);
return refund;
} finally {
res.getRoom().getLock().unlock();
}
}
}
System.out.println("[Cancellation Error] Reservation not found.");
return 0.0;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== HOTEL CONCURRENT SIMULATION DRIVER ===");
CancellationStrategy strategy = new FlexibleCancellationStrategy();
HotelBookingService hotel = new HotelBookingService(strategy);
Room r1 = new Room("SUITE-101", RoomType.SUITE, 250.0);
hotel.addRoom(r1);
long now = System.currentTimeMillis();
long in = now + (3 * 24 * 60 * 60 * 1000); // 3 days from now
long out = now + (5 * 24 * 60 * 60 * 1000); // 5 days from now
ExecutorService threadPool = Executors.newFixedThreadPool(2);
// Spawn 2 parallel concurrent booking attempts for the SAME room
threadPool.submit(() -> hotel.bookRoom("Alice", "SUITE-101", in, out));
threadPool.submit(() -> hotel.bookRoom("Bob", "SUITE-101", in, out));
threadPool.shutdown();
threadPool.awaitTermination(1, TimeUnit.SECONDS);
}
}