src/com/vehiclerental/logicLayer/implementations/BookingServiceImpl.java
/**
     * Creates a booking according to the business rules
     * This method may involve cluster communication
     *
     * Important : The booking is ALWAYS created by the branch owning the vehicle booking in order to avoid latency between the availability check and the booking creation
     *
     * @param userId the user creating the booking
     * @param currentBranch the current branch
     * @param contract the booking parameters
     * @return The created booking, as a contract
     * @throws InvalidPropertyException if a property is invalid
     * @throws NotAuthorizedException if the user is not authorized for this operation (booking creation for himself OR for someone else)
     * @throws VehicleUnavailableException if the desired vehicle is unavailable
     * @throws ClusterCommunicatorException if the cluster communication fails
     * @throws InvalidDateException if the booking dates are invalid
     */
Creates a booking according to the business rules
This method may involve cluster communication

Important : The booking is ALWAYS created by the branch owning the vehicle booking in order to avoid latency between the availability check and the booking creation


Creates a booking according to the business rules This method may involve cluster communication Important : The booking is ALWAYS created by the branch owning the vehicle booking in order to avoid latency between the availability check and the booking creation
@Override
    public BookingContract createBooking(int userId, Branch currentBranch, CreateBookingContract contract) throws InvalidPropertyException, NotAuthorizedException, VehicleUnavailableException, ClusterCommunicatorException, InvalidDateException {
        if (currentBranch == null) {
            throw new InvalidPropertyException("Invalid branch");
        }
        if (contract.vehicleBranchId != currentBranch.getId()) {
            Branch vehicleBranch = NodeConfiguration.Current.branches.get(contract.vehicleBranchId);
            if (vehicleBranch == null) {
                throw new InvalidPropertyException("Invalid branch");
            }
            BranchRequestMessage<CreateBookingContract> forwardedMpiRequest = new BranchRequestMessage<CreateBookingContract>();
            forwardedMpiRequest.userId = userId;
            forwardedMpiRequest.object = contract;
            forwardedMpiRequest.operationCode = OperationCodes.BOOK_VEHICLE;
            NodeConfiguration.Current.clusterCommunicator.sendObject(
                    vehicleBranch.getClusterId(),
                    OperationCodes.BOOK_VEHICLE,
                    SerializationUtils.serialize(forwardedMpiRequest));
            ClusterCommunicationObject<String> rawMpiResponse = NodeConfiguration.Current.clusterCommunicator.receiveObject(
                    vehicleBranch.getClusterId(),
                    OperationCodes.BOOK_VEHICLE,
                    String.class);
            Type jsonType = new TypeToken<BranchResponseMessage<BookingContract>>() {}.getType();
            BranchResponseMessage<BookingContract> clusterBookingResponse = SerializationUtils.deserialize(rawMpiResponse.object, jsonType);
            return clusterBookingResponse.Object;
        } else {
            Calendar pickupDate = DateUtils.getCalendarFromIso8601String(contract.pickupDate);
            Calendar returnDate = DateUtils.getCalendarFromIso8601String(contract.returnDate);
            if(DateUtils.getBookingDays(pickupDate, returnDate) > 7) {
                throw new InvalidDateException("Bookings are only available for a maximum of 7 days");
            }
            Booking booking = new Booking();
            Branch bookingBranch = NodeConfiguration.Current.branches.get(contract.bookingBranchId);
            booking.setBranch(bookingBranch);
            booking.setPickUpDate(pickupDate.getTimeInMillis());
            booking.setReturnDate(returnDate.getTimeInMillis());
            Calendar realStart = pickupDate;
            Calendar realEnd = returnDate;
            VehicleMove move = null;
            if (bookingBranch.getId() != currentBranch.getId()) {
                move = new VehicleMove();
                Calendar moveStartDate = DateUtils.getCalendarFromIso8601String(contract.pickupDate);
                moveStartDate.add(Calendar.DAY_OF_YEAR, -1);
                Calendar moveReturnDate = DateUtils.getCalendarFromIso8601String(contract.returnDate);
                moveReturnDate.add(Calendar.DAY_OF_YEAR, 1);
                move.setVehicleMoveDate(moveStartDate.getTimeInMillis());
                realStart = moveStartDate;
                move.setVehicleReturnDate(moveReturnDate.getTimeInMillis());
                realEnd = moveReturnDate;
                move.setBooking(booking);
            }
            Calendar todayCalendar = DateUtils.getTodayCalendar();
            if (DateUtils.compareCalendar(todayCalendar, realStart) != DateUtils.DATE1_BEFORE_DATE2) {
                if (move == null) {
                    throw new InvalidDateException("Impossible to book a vehicle for the same day or before");
                } else {
                    throw new InvalidDateException("Impossible to book a vehicle on a distant branch for tomorrow or before");
                }
            }
            if (DateUtils.compareCalendar(realStart, realEnd) != DateUtils.DATE1_BEFORE_DATE2) {
                throw new InvalidDateException("The return date must be after the pick up date");
            }
            Vehicle vehicle = vehicleDao.getVehicleIfAvailable(currentBranch, contract.vehicleId, realStart, realEnd);
            if (vehicle == null) {
                throw new VehicleUnavailableException();
            }
            booking.setCreditCardCvcCodeEncrypted(contract.creditCardCvcCode);
            booking.setCreditCardExpirationMonthEncrypted(contract.creditCardExpirationMonth);
            booking.setCreditCardExpirationYearEncrypted(contract.creditCardExpirationYear);
            booking.setCreditCardNumberEncrypted(contract.creditCardNumber);
            try {
                booking.encrypt();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("ERROR: Encryption of payment informations failed");
            }
            User user = new User();
            if (contract.bookingOwnerUserId != null) {
                user = userService.getUser(contract.bookingOwnerUserId);
                if (user == null) {
                    throw new InvalidPropertyException("Invalid user");
                }
            } else {
                user.setId(userId);
            }
            booking.setUser(user);
            booking.setBookingValidated(true);
            booking.setVehicle(vehicle);
            booking.setDaysCount(DateUtils.getBookingDays(pickupDate, returnDate));
            booking.setPrice(Math.round(vehicle.getPoundsPerDay() * booking.getDaysCount() * 100.0) / 100.0);
            if (move != null) {
                booking.setVehicleMove(move);
                vehicleMoveDao.create(move);
            }
            booking = bookingDao.create(booking);
            if (move != null) {
                try {
                    move.setBooking(booking);
                    vehicleMoveDao.update(move);
                } catch (DatabaseUpdateFailedException e) {
                    e.printStackTrace();
                }
            }
            return new BookingContract(booking);
        }
    }
@ Override public BookingContract createBooking ( int userId , Branch currentBranch , CreateBookingContract contract ) throws InvalidPropertyException , NotAuthorizedException , VehicleUnavailableException , ClusterCommunicatorException , InvalidDateException { if ( currentBranch == null ) { throw new InvalidPropertyException ( "Invalid branch" ) ; } if ( contract . vehicleBranchId != currentBranch . getId ( ) ) { Branch vehicleBranch = NodeConfiguration . Current . branches . get ( contract . vehicleBranchId ) ; if ( vehicleBranch == null ) { throw new InvalidPropertyException ( "Invalid branch" ) ; } BranchRequestMessage < CreateBookingContract > forwardedMpiRequest = new BranchRequestMessage < CreateBookingContract > ( ) ; forwardedMpiRequest . userId = userId ; forwardedMpiRequest . object = contract ; forwardedMpiRequest . operationCode = OperationCodes . BOOK_VEHICLE ; NodeConfiguration . Current . clusterCommunicator . sendObject ( vehicleBranch . getClusterId ( ) , OperationCodes . BOOK_VEHICLE , SerializationUtils . serialize ( forwardedMpiRequest ) ) ; ClusterCommunicationObject < String > rawMpiResponse = NodeConfiguration . Current . clusterCommunicator . receiveObject ( vehicleBranch . getClusterId ( ) , OperationCodes . BOOK_VEHICLE , String . class ) ; Type jsonType = new TypeToken < BranchResponseMessage < BookingContract > > ( ) { } . getType ( ) ; BranchResponseMessage < BookingContract > clusterBookingResponse = SerializationUtils . deserialize ( rawMpiResponse . object , jsonType ) ; return clusterBookingResponse . Object ; } else { Calendar pickupDate = DateUtils . getCalendarFromIso8601String ( contract . pickupDate ) ; Calendar returnDate = DateUtils . getCalendarFromIso8601String ( contract . returnDate ) ; if ( DateUtils . getBookingDays ( pickupDate , returnDate ) > 7 ) { throw new InvalidDateException ( "Bookings are only available for a maximum of 7 days" ) ; } Booking booking = new Booking ( ) ; Branch bookingBranch = NodeConfiguration . Current . branches . get ( contract . bookingBranchId ) ; booking . setBranch ( bookingBranch ) ; booking . setPickUpDate ( pickupDate . getTimeInMillis ( ) ) ; booking . setReturnDate ( returnDate . getTimeInMillis ( ) ) ; Calendar realStart = pickupDate ; Calendar realEnd = returnDate ; VehicleMove move = null ; if ( bookingBranch . getId ( ) != currentBranch . getId ( ) ) { move = new VehicleMove ( ) ; Calendar moveStartDate = DateUtils . getCalendarFromIso8601String ( contract . pickupDate ) ; moveStartDate . add ( Calendar . DAY_OF_YEAR , - 1 ) ; Calendar moveReturnDate = DateUtils . getCalendarFromIso8601String ( contract . returnDate ) ; moveReturnDate . add ( Calendar . DAY_OF_YEAR , 1 ) ; move . setVehicleMoveDate ( moveStartDate . getTimeInMillis ( ) ) ; realStart = moveStartDate ; move . setVehicleReturnDate ( moveReturnDate . getTimeInMillis ( ) ) ; realEnd = moveReturnDate ; move . setBooking ( booking ) ; } Calendar todayCalendar = DateUtils . getTodayCalendar ( ) ; if ( DateUtils . compareCalendar ( todayCalendar , realStart ) != DateUtils . DATE1_BEFORE_DATE2 ) { if ( move == null ) { throw new InvalidDateException ( "Impossible to book a vehicle for the same day or before" ) ; } else { throw new InvalidDateException ( "Impossible to book a vehicle on a distant branch for tomorrow or before" ) ; } } if ( DateUtils . compareCalendar ( realStart , realEnd ) != DateUtils . DATE1_BEFORE_DATE2 ) { throw new InvalidDateException ( "The return date must be after the pick up date" ) ; } Vehicle vehicle = vehicleDao . getVehicleIfAvailable ( currentBranch , contract . vehicleId , realStart , realEnd ) ; if ( vehicle == null ) { throw new VehicleUnavailableException ( ) ; } booking . setCreditCardCvcCodeEncrypted ( contract . creditCardCvcCode ) ; booking . setCreditCardExpirationMonthEncrypted ( contract . creditCardExpirationMonth ) ; booking . setCreditCardExpirationYearEncrypted ( contract . creditCardExpirationYear ) ; booking . setCreditCardNumberEncrypted ( contract . creditCardNumber ) ; try { booking . encrypt ( ) ; } catch ( Exception e ) { e . printStackTrace ( ) ; System . out . println ( "ERROR: Encryption of payment informations failed" ) ; } User user = new User ( ) ; if ( contract . bookingOwnerUserId != null ) { user = userService . getUser ( contract . bookingOwnerUserId ) ; if ( user == null ) { throw new InvalidPropertyException ( "Invalid user" ) ; } } else { user . setId ( userId ) ; } booking . setUser ( user ) ; booking . setBookingValidated ( true ) ; booking . setVehicle ( vehicle ) ; booking . setDaysCount ( DateUtils . getBookingDays ( pickupDate , returnDate ) ) ; booking . setPrice ( Math . round ( vehicle . getPoundsPerDay ( ) * booking . getDaysCount ( ) * 100.0 ) / 100.0 ) ; if ( move != null ) { booking . setVehicleMove ( move ) ; vehicleMoveDao . create ( move ) ; } booking = bookingDao . create ( booking ) ; if ( move != null ) { try { move . setBooking ( booking ) ; vehicleMoveDao . update ( move ) ; } catch ( DatabaseUpdateFailedException e ) { e . printStackTrace ( ) ; } } return new BookingContract ( booking ) ; } }
Creates a booking according to the business rules
 This method may involve cluster communication
Creates a booking according to the business rules This method may involve cluster communication
// If the booking concerns a vehicle on another branch, we need to forward the request to this branch //Parse MPI response //We are now on the vehicle branch, we can create the booking //Contains the real start/end values for the database search //Do we need a move ? //The move start is one day before the user pickup //The move return is one day after the user return //If the booking concerns this branch, we create it //Making a booking for someone else //Update booking reference in vehiclemoves