Functional Scope (In-Scope)
- Dynamic Room Booking: Book meeting rooms for standard dynamic time intervals (start/end timestamp epoch).
- Overlapping Check: Strict overlap check to prevent double-booking rooms.
- Search Availability: Return rooms matching minimum attendance size constraints that are free during requested slots.
- Concurrent Protection: Process concurrent booking calls gracefully, maintaining complete ticket/reservation consistency.
Explicit Boundaries (Out-of-Scope)
- No Dynamic Recurrence Logic: Recurring reservation rules (e.g. daily/weekly repeating meetings) are omitted to focus on structural interval scheduling.
- No Room Equipment Configuration: Ignores specific equipment requests (projectors, smart boards, audio accessories).
Clean reference designs showcasing operational patterns and thread-safety in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
class TimeSlot {
private final long start;
private final long end;
public TimeSlot(long start, long end) {
if (start >= end) {
throw new IllegalArgumentException("Start time must be strictly before end time.");
}
if (start < 0) {
throw new IllegalArgumentException("Time values cannot be negative.");
}
this.start = start;
this.end = end;
}
public long getStart() { return start; }
public long getEnd() { return end; }
public boolean overlaps(TimeSlot other) {
return this.start < other.end && other.start < this.end;
}
@Override
public String toString() {
return "[" + start + " - " + end + "]";
}
}
class Booking {
private final String id;
private final Room room;
private final TimeSlot timeSlot;
private final String organizer;
public Booking(String id, Room room, TimeSlot timeSlot, String organizer) {
this.id = Objects.requireNonNull(id);
this.room = Objects.requireNonNull(room);
this.timeSlot = Objects.requireNonNull(timeSlot);
this.organizer = Objects.requireNonNull(organizer);
}
public String getId() { return id; }
public Room getRoom() { return room; }
public TimeSlot getTimeSlot() { return timeSlot; }
public String getOrganizer() { return organizer; }
}
class Room {
private final String id;
private final int capacity;
private final List<Booking> bookings = new ArrayList<>();
private final ReentrantLock lock = new ReentrantLock();
public Room(String id, int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException("Capacity must be positive.");
}
this.id = Objects.requireNonNull(id);
this.capacity = capacity;
}
public String getId() { return id; }
public int getCapacity() { return capacity; }
public boolean isAvailable(TimeSlot slot) {
lock.lock();
try {
for (Booking existing : bookings) {
if (existing.getTimeSlot().overlaps(slot)) {
return false;
}
}
return true;
} finally {
lock.unlock();
}
}
public boolean book(Booking booking) {
lock.lock();
try {
for (Booking existing : bookings) {
if (existing.getTimeSlot().overlaps(booking.getTimeSlot())) {
return false;
}
}
bookings.add(booking);
return true;
} finally {
lock.unlock();
}
}
public List<Booking> getBookings() {
lock.lock();
try {
return new ArrayList<>(bookings);
} finally {
lock.unlock();
}
}
}
interface RoomSelectionStrategy {
Room selectRoom(List<Room> rooms, int attendees, TimeSlot slot);
}
class BestFitRoomSelectionStrategy implements RoomSelectionStrategy {
@Override
public Room selectRoom(List<Room> rooms, int attendees, TimeSlot slot) {
List<Room> candidateRooms = new ArrayList<>();
for (Room room : rooms) {
if (room.getCapacity() >= attendees) {
candidateRooms.add(room);
}
}
candidateRooms.sort(Comparator.comparingInt(Room::getCapacity));
for (Room room : candidateRooms) {
if (room.isAvailable(slot)) {
return room;
}
}
return null;
}
}
class FirstFitRoomSelectionStrategy implements RoomSelectionStrategy {
@Override
public Room selectRoom(List<Room> rooms, int attendees, TimeSlot slot) {
for (Room room : rooms) {
if (room.getCapacity() >= attendees && room.isAvailable(slot)) {
return room;
}
}
return null;
}
}
class MeetingScheduler {
private final List<Room> rooms = new CopyOnWriteArrayList<>();
private final RoomSelectionStrategy roomSelectionStrategy;
public MeetingScheduler(RoomSelectionStrategy strategy) {
this.roomSelectionStrategy = Objects.requireNonNull(strategy);
}
public void addRoom(Room room) {
rooms.add(Objects.requireNonNull(room));
}
public List<Room> findAvailableRooms(TimeSlot slot, int minCapacity) {
List<Room> available = new ArrayList<>();
for (Room room : rooms) {
if (room.getCapacity() >= minCapacity && room.isAvailable(slot)) {
available.add(room);
}
}
return available;
}
public Booking scheduleMeeting(String organizer, int attendees, TimeSlot slot) {
Room room = roomSelectionStrategy.selectRoom(rooms, attendees, slot);
if (room != null) {
String bookingId = "BKG-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
Booking booking = new Booking(bookingId, room, slot, organizer);
if (room.book(booking)) {
System.out.println("[Scheduler] Success: Room " + room.getId() + " booked for " + organizer + " " + slot);
return booking;
}
}
System.out.println("[Scheduler] Fail: No room available for " + organizer + " at slot " + slot + " for " + attendees + " attendees.");
return null;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
MeetingScheduler scheduler = new MeetingScheduler(new BestFitRoomSelectionStrategy());
scheduler.addRoom(new Room("Room-A", 5));
scheduler.addRoom(new Room("Room-B", 10));
scheduler.addRoom(new Room("Room-C", 15));
System.out.println("--- Starting Concurrent Meeting Booking Simulation ---");
ExecutorService executor = Executors.newFixedThreadPool(4);
TimeSlot slot1 = new TimeSlot(10, 12);
TimeSlot slot2 = new TimeSlot(11, 13); // Overlaps with slot1
// Task 1: Book Room for 4 people at 10-12
Runnable task1 = () -> scheduler.scheduleMeeting("Alice", 4, slot1);
// Task 2: Book Room for 8 people at 10-12 (should go to Room-B since Room-A is for 5)
Runnable task2 = () -> scheduler.scheduleMeeting("Bob", 8, slot1);
// Task 3: Book Room for 4 people at 11-13 (overlaps with slot1, should go to Room-C if A is taken)
Runnable task3 = () -> scheduler.scheduleMeeting("Charlie", 4, slot2);
// Task 4: Duplicate Alice's slot attempt by Dave (should fail if Alice gets Room-A first)
Runnable task4 = () -> scheduler.scheduleMeeting("Dave", 4, slot1);
executor.submit(task1);
executor.submit(task2);
executor.submit(task3);
executor.submit(task4);
executor.shutdown();
executor.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("--- Booking Simulation Completed ---");
}
}