Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Movie Booking System #5

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/com/showbooking/Client.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.showbooking;

import com.showbooking.bookings.Booking;
import com.showbooking.bookings.BookingService;
import com.showbooking.events.EventService;
import com.showbooking.events.Show;
import com.showbooking.payments.Payable;
import com.showbooking.payments.PaymentService;
import com.showbooking.repository.BookingRepository;
import com.showbooking.repository.EventRepository;

import java.util.List;
import java.util.Map;

public class Client {
EventRepository eventRepository;
BookingRepository bookingRepository;
Payable paymentService;

public Client() {
eventRepository = EventRepository.getInstance();
bookingRepository = BookingRepository.getInstance();
paymentService = new PaymentService();
}
public List<Show> fetchEvents(Map<String, String> filter){
return EventService.fetchShows(eventRepository, filter);
}

public Boolean addOrUpdateEvents(List<Map<String, Object>> events){
for(Map<String, Object> event: events) {
if(!EventService.addOrUpdateEvent(eventRepository, event))
return false;
}

return true;
}

public Boolean addLayout(Boolean[][] layout, Long screenId) {
return EventService.addScreenLayout(eventRepository, screenId, layout);
}

public Boolean[][] fetchEventSeatLayout(Long eventId) {
return EventService.fetchEventSeatLayout(eventRepository, eventId);
}

public Long bookEvent(List<Long> seatIds, Long eventId, Long screenId, Long userId) {
return BookingService.bookEvent(paymentService, bookingRepository, eventRepository, userId, eventId,
screenId, seatIds);
}

public Booking fetchBooking(Long bookingId) {
return BookingService.fetchBooking(bookingRepository, bookingId);
}

public Boolean cancelBooking(Long bookingId) {
return BookingService.cancelBooking(paymentService, bookingRepository, bookingId);
}
}
60 changes: 60 additions & 0 deletions src/com/showbooking/bookings/Booking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.showbooking.bookings;

import com.showbooking.events.Show;
import com.showbooking.payments.Payment;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Booking {
Show show;
Payment payment;

Long id;
Long userId;
Boolean isActive;
List<Long> seatIds;
private final Lock lock = new ReentrantLock();

Booking(Long userId, Show show, Payment payment, List<Long> bookedSeatIds) {
Random rand = new Random();

this.id = rand.nextLong();
this.isActive = true;
this.userId = userId;
this.show = show;
this.seatIds = new ArrayList<>(bookedSeatIds);
this.payment = payment;
}

public Long getId(){
return this.id;
}

public Lock getLock() {
return this.lock;
}

public Boolean getIsActive(){
return this.isActive;
}

public Show getShow() {
return this.show;
}

public Payment getPayment() {
return this.payment;
}

public List<Long> getSeatIds() {
return this.seatIds;
}

public void setIsActiveFalse() {
this.isActive = false;
}
}
68 changes: 68 additions & 0 deletions src/com/showbooking/bookings/BookingService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.showbooking.bookings;

import com.showbooking.bookings.exception.SeatUnavailableException;
import com.showbooking.payments.Payable;
import com.showbooking.events.Show;
import com.showbooking.payments.Payment;
import com.showbooking.payments.PaymentStatus;
import com.showbooking.payments.exception.PaymentFailedException;
import com.showbooking.repository.BookingRepository;
import com.showbooking.repository.EventRepository;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class BookingService {
public static Long bookEvent(Payable paymentService, BookingRepository bookingRepository, EventRepository eventRepository,
Long userId, Long eventId, Long screenId, List<Long> seatIds) {
List<Show> availableShows = eventRepository.fetchAllShows(eventId).stream().filter(
show -> show.getScreenId().equals(screenId)).collect(Collectors.toList());
Show selectedShow = Collections.min(availableShows, Comparator.comparing(Show::getId));

Collections.sort(seatIds);
try {
selectedShow.bookSeats(seatIds);
Payment payment = paymentService.makePayment(userId, selectedShow.getPrice());
if(payment.getStatus().equals(PaymentStatus.SUCCESS)) {
Booking booking = bookingRepository.addBooking(new Booking(userId, selectedShow, payment, seatIds));
return booking.getId();
} else {
throw new PaymentFailedException();
}
} catch (SeatUnavailableException exc) {
System.out.println("Selected seat no longer available.");
return null;
} catch (PaymentFailedException exc) {
selectedShow.unBookSeats(seatIds);
return null;
}
}

public static Boolean cancelBooking(Payable paymentService, BookingRepository bookingRepository, Long bookingId) {
Booking booking = bookingRepository.fetchBooking(bookingId);
if(!booking.getIsActive()) {
return false;
}

List<Long> bookedSeats = booking.getSeatIds();
Show bookedShow = booking.getShow();
booking.getLock().lock();
try {
if (booking.getIsActive()) {
paymentService.refundPayment(booking.getPayment());
bookedShow.unBookSeats(bookedSeats);
booking.setIsActiveFalse();
return true;
}
return false;
} finally {
booking.getLock().unlock();
}
}

public static Booking fetchBooking(BookingRepository bookingRepository, long bookingId) {
return bookingRepository.fetchBooking(bookingId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.showbooking.bookings.exception;

public class SeatUnavailableException extends Exception {
public SeatUnavailableException() {
super("Selected seat not available!");
}
}
12 changes: 12 additions & 0 deletions src/com/showbooking/events/Event.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.showbooking.events;

public interface Event {
void setTitle(String title);
void setGenre(String genre);
void setLanguage(String genre);

Long getEventId();
String getEventTitle();
String getEventGenre();
String getEventLanguage();
}
80 changes: 80 additions & 0 deletions src/com/showbooking/events/EventService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.showbooking.events;

import com.showbooking.repository.EventRepository;

import java.util.*;

public class EventService {
public static Boolean addOrUpdateEvent(EventRepository repository, Map<String, Object> data) {
try {
Event event = repository.fetchMovie((Long) data.get("eventId"));
Screen screen = repository.fetchScreen((Long) data.get("screenId"));
if (screen == null) {
screen = repository.addScreen(new Screen((Long) data.get("screenId")));
}

if (event == null) {
event = repository.addMovie(new Movie((Long) data.get("eventId"), (String) data.get("title"),
(String) data.get("genre"), (String) data.get("language")));
} else {
event.setTitle((String) data.get("title"));
event.setGenre((String) data.get("genre"));
event.setLanguage((String) data.get("language"));
repository.updateMovie(event);
}

repository.removeShows(event, screen);
List<Object> showDetails = (List<Object>) data.get("showTimePriceMap");
for (Object showDetail : showDetails) {
Map<String, Object> detail = (Map<String, Object>) showDetail;
repository.addShow(new Show(event, screen, (Integer) detail.get("time"), (Integer) detail.get("price")));
}
} catch (Exception exc) {
System.out.println("Failed adding/updating event, due to: " + exc.getMessage());
return false;
}
return true;
}

public static List<Show> fetchShows(EventRepository repository, Map<String, String> filter) {
List<Event> allEvents = repository.fetchAllMovies();

Filter filterObj = new Filter(filter.getOrDefault("title", null),
filter.getOrDefault("genre", null),
filter.getOrDefault("language", null),
filter.getOrDefault("price", null));
List<Event> filteredEvents = FilterService.filterEvents(allEvents, filterObj);

List<Show> eventShows = new ArrayList<Show>();
for(Event event: filteredEvents) {
eventShows.addAll(repository.fetchAllShows(event.getEventId()));
}

List<Show> filteredShows = FilterService.filterShows(eventShows, filterObj);
return filteredShows;
}

public static Boolean addScreenLayout(EventRepository repository, Long screenId, Boolean[][] layout) {
try {
Screen screen = repository.fetchScreen(screenId);
screen.addLayout(layout);
repository.updateScreen(screen);
} catch(Exception exc) {
System.out.println("Unable to add screen layout");
return false;
}

return true;
}

public static Boolean[][] fetchEventSeatLayout(EventRepository repository, Long eventId) {
Event event = repository.fetchMovie(eventId);
List<Show> shows = repository.fetchAllShows(event.getEventId());
if(shows.isEmpty())
return null;

Show selectedShow = Collections.min(shows, Comparator.comparing(Show::getId));
Screen screen = repository.fetchScreen(selectedShow.getScreenId());
return selectedShow.getSeatingLayout(screen);
}
}
46 changes: 46 additions & 0 deletions src/com/showbooking/events/Filter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.showbooking.events;

public class Filter {
String title;
String genre;
String language;
Integer minPrice;
Integer maxPrice;

Filter(String title, String genre, String language, String price) {
if(title != null)
this.title = title;
if(genre != null)
this.genre = genre;
if(language != null)
this.language = language;

if(price != null) {
String[] prices = price.split(":", 2);
if(!prices[0].isEmpty())
this.minPrice = Integer.valueOf(prices[0]);
if(!prices[1].isEmpty())
this.maxPrice = Integer.valueOf(prices[1]);
}
}

public String getTitle() {
return this.title;
}

public String getGenre() {
return this.genre;
}

public String getLanguage() {
return this.language;
}

public Integer getMinPrice() {
return this.minPrice;
}

public Integer getMaxPrice() {
return this.maxPrice;
}
}
35 changes: 35 additions & 0 deletions src/com/showbooking/events/FilterService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.showbooking.events;

import java.util.ArrayList;
import java.util.List;

public class FilterService {
public static List<Event> filterEvents(List<Event> events, Filter filter) {
List<Event> result = new ArrayList<Event>(events);

if(filter.getTitle() != null) {
result.removeIf(event -> !event.getEventTitle().equalsIgnoreCase(filter.getTitle()));
}
if(filter.getGenre() != null) {
result.removeIf(event -> !event.getEventGenre().equalsIgnoreCase(filter.getGenre()));
}
if(filter.getLanguage() != null) {
result.removeIf(event -> !event.getEventLanguage().equalsIgnoreCase(filter.getLanguage()));
}

return result;
}

public static List<Show> filterShows(List<Show> shows, Filter filter) {
List<Show> result = new ArrayList<Show>(shows);

if(filter.getMinPrice() != null) {
result.removeIf(show -> show.getPrice() < filter.getMinPrice());
}
if(filter.getMaxPrice() != null) {
result.removeIf(show -> show.getPrice() > filter.getMaxPrice());
}

return result;
}
}
Loading