squash.booking.lambdas.GetBookingsLambda.java Source code

Java tutorial

Introduction

Here is the source code for squash.booking.lambdas.GetBookingsLambda.java

Source

/**
 * Copyright 2015-2017 Robin Steel
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package squash.booking.lambdas;

import squash.booking.lambdas.core.BookingManager;
import squash.booking.lambdas.core.IBookingManager;
import squash.booking.lambdas.core.ILifecycleManager;
import squash.booking.lambdas.core.LifecycleManager;
import squash.deployment.lambdas.utils.ExceptionUtils;

import org.apache.commons.lang3.tuple.ImmutablePair;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;

import java.security.InvalidParameterException;
import java.util.List;
import java.util.Optional;

/**
 * AWS Lambda function returning all bookings for a specified date.
 * 
 * <p>This is usually invoked by AWS Lambda.
 * 
 * @author robinsteel19@outlook.com (Robin Steel)
 */
public class GetBookingsLambda {
    private Optional<IBookingManager> bookingManager;
    private Optional<ILifecycleManager> lifecycleManager;

    /**
     *  Constructor.
     */
    public GetBookingsLambda() {
        bookingManager = Optional.empty();
        lifecycleManager = Optional.empty();
    }

    /**
     *  Returns all dates for which bookings can currently be made.
     *  
     *  @return all dates on which bookings can be made, in YYYY-MM-DD format.
     */
    protected List<String> getValidDates() {
        // Use a getter here so unit tests can substitute a different method.

        return new GetValidDatesLambda().getValidDates(new GetValidDatesLambdaRequest()).getDates();
    }

    /**
     *  Returns the {@link squash.booking.lambdas.core.BookingManager}.
     */
    protected IBookingManager getBookingManager(LambdaLogger logger) throws Exception {
        // Use a getter here so unit tests can substitute a mock manager
        if (!bookingManager.isPresent()) {
            bookingManager = Optional.of(new BookingManager());
            bookingManager.get().initialise(logger);
        }
        return bookingManager.get();
    }

    /**
     * Returns the {@link squash.booking.lambdas.core.ILifecycleManager}.
     */
    protected ILifecycleManager getLifecycleManager(LambdaLogger logger) throws Exception {
        // Use a getter here so unit tests can substitute a mock manager
        if (!lifecycleManager.isPresent()) {
            lifecycleManager = Optional.of(new LifecycleManager());
            lifecycleManager.get().initialise(logger);
        }
        return lifecycleManager.get();
    }

    /**
     * Returns all bookings for the specified date.
     * 
     * @param request specifying, e.g., the date for which to return bookings.
     * @param context provided by AWS Lambda.
     * @return response containing the bookings.
     * @throws AmazonServiceException when the method fails owing to an error in an AWS service.
     * @throws AmazonClientException when the method fails owing to a client error.
     * @throws Exception when the method fails for some other reason.
     */
    public GetBookingsLambdaResponse getBookings(GetBookingsLambdaRequest request, Context context)
            throws Exception {

        LambdaLogger logger = context.getLogger();
        String redirectUrl = request.getRedirectUrl();
        try {
            logger.log("ApiGateway request Id: " + request.getRequestId());

            // Validate the date that bookings are being requested for
            String requestedDate = request.getDate();
            logger.log("About to get bookings for date: " + requestedDate + ". Checking if date is valid...");
            if (!getValidDates().contains(requestedDate)) {
                logger.log("Date is not valid");
                throw new InvalidParameterException("The booking date is outside the valid range");
            }
            logger.log("Date is valid");

            // Query for bookings (if any) for the requested day
            logger.log("About to call booking manager to get bookings");
            GetBookingsLambdaResponse response = new GetBookingsLambdaResponse();
            IBookingManager bookingManager = getBookingManager(logger);
            response.setBookings(bookingManager.getBookings(requestedDate, true));
            response.setDate(request.getDate());
            ILifecycleManager lifecycleManager = getLifecycleManager(logger);
            ImmutablePair<ILifecycleManager.LifecycleState, Optional<String>> lifecycleState = lifecycleManager
                    .getLifecycleState();
            response.setLifecycleState(lifecycleState.left.name());
            // N.B. getBookings will have thrown already if state is RETIRED, but
            // fill in the url anyway.
            response.setForwardingUrl(lifecycleState.right.orElse(""));

            logger.log("Called booking manager to get bookings");
            return response;
        } catch (AmazonServiceException ase) {
            ExceptionUtils.logAmazonServiceException(ase, logger);
            throw new Exception("Apologies - something has gone wrong. Please try again." + redirectUrl, ase);
        } catch (AmazonClientException ace) {
            ExceptionUtils.logAmazonClientException(ace, logger);
            throw new Exception("Apologies - something has gone wrong. Please try again." + redirectUrl, ace);
        } catch (Exception e) {
            if ((e.getMessage() != null)
                    && e.getMessage().contains(
                            "Cannot access bookings or rules - there is an updated version of the booking service.")
                    && !e.getMessage().contains("UrlNotPresent")) {
                // In case where service is RETIRED and we have a valid forwarding url,
                // use that url instead of our generic redirectUrl. If we have no valid
                // forwarding url (which should never happen), we fall through to
                // showing the user a general error message.
                throw new Exception(e.getMessage().replace(" Forwarding Url:", ""), e);
            }

            switch (e.getMessage()) {
            // For now, we add the request.redirectUrl to the message. ApiGateway will
            // parse this out.
            case "The booking date is outside the valid range":
                throw new Exception("The booking date is outside the valid range. Please try again." + redirectUrl,
                        e);
            default:
                throw new Exception("Apologies - something has gone wrong. Please try again." + redirectUrl, e);
            }
        }
    }
}