com.comcast.locker.gateway.xgateway.service.CreatePurchaseForAssetController.java Source code

Java tutorial

Introduction

Here is the source code for com.comcast.locker.gateway.xgateway.service.CreatePurchaseForAssetController.java

Source

package com.comcast.locker.gateway.xgateway.service;

import static com.comcast.locker.gateway.xgateway.utils.XGatewayUtils.getPrice;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.comcast.common.Crn;
import com.comcast.config.Configuration;
import com.comcast.locker.api.account.AccountId;
import com.comcast.locker.api.asset.AssetId;
import com.comcast.locker.api.asset.Right;
import com.comcast.locker.api.service.LockerService;
import com.comcast.locker.api.tx.Transaction;
import com.comcast.locker.gateway.services.GatewayService;
import com.comcast.locker.gateway.services.UnuService;
import com.comcast.locker.gateway.xgateway.XGatewaySettings;
import com.comcast.locker.gateway.xgateway.domain.CreatePurchaseRequest;
import com.comcast.locker.gateway.xgateway.domain.CreatePurchaseResponse;
import com.comcast.locker.gateway.xgateway.utils.XGatewayUtils;
import com.comcast.title.Titles;
import com.comcast.title.encoding.Api.Title;
import com.comcast.title.encoding.Api.TitlePlayability;
import com.comcast.util.Pair;

/**
 * Implements the "create permanent buy transaction for XCAL" use case.
 *
 */
public class CreatePurchaseForAssetController {

    private static final Logger LOG = LoggerFactory.getLogger(CreatePurchaseForAssetController.class);

    private final GatewayService gatewayService;
    private final LockerService lockerService;
    private final String cempTransactionHandler;
    private final UnuService unuService;

    private final boolean awaitEvidenceOfPlay;

    public CreatePurchaseForAssetController(Configuration configuration, GatewayService gatewayService,
            LockerService lockerService, UnuService unuService) {
        checkNotNull(gatewayService, "The 'gatewayService' cannot be null.");
        checkNotNull(lockerService, "The 'lockerService' cannot be null.");
        checkNotNull(configuration, "The 'configuration' cannot be null.");
        checkNotNull(unuService, "The 'unuService' cannot be null.");

        this.gatewayService = gatewayService;
        this.lockerService = lockerService;
        this.unuService = unuService;

        this.cempTransactionHandler = configuration.get(XGatewaySettings.TRANSACTION_HANDLER_ID);

        awaitEvidenceOfPlay = configuration
                .getAsBoolean(XGatewaySettings.PURCHASE_AWAIT_EVIDENCE_OF_PLAY_BEFORE_BILLING);
    }

    /**
     * "Executes" the use case by:<ol>
     * <li>Resolving the account number given in the request to a Locker accountId</li>
     * <li>Resolving the title paid given in the request to a Locker assetId</li>
     * <li>Creating a full Locker {@link Transaction} with a single associated {@link Right}</li>
     * <li>Storing the transaction in the Locker</li>
     * </ol>
     *
     * @param purchaseRequest provides the Xgateway specific transaction information
     */
    public CreatePurchaseResponse executePurchaseTransaction(CreatePurchaseRequest purchaseRequest) {
        checkArgument(purchaseRequest != null, "The 'purchaseRequest' cannot be null.");

        AccountId accountId = gatewayService.resolveLockerAccountIdFromCRN(purchaseRequest.getAccountId());
        AssetId assetId = gatewayService.resolveLockerAssetIdFromCRN(purchaseRequest.getAssetId());

        TitlePlayability title = validateRequestInformation(purchaseRequest, accountId, assetId);

        Pair<Transaction, Date> pair = createPurchaseTransactionInLocker(purchaseRequest, title.getTitle(),
                accountId, assetId, Crn.fromRawCrn(purchaseRequest.getAssetId()),
                Crn.fromRawCrn(purchaseRequest.getAccountId()));

        Transaction tx = pair.getFirst();

        CreatePurchaseResponse res = new CreatePurchaseResponse(tx.getId().toString(), tx.getTransactionTime(),
                pair.getSecond(), tx.getPriceToPurchaser());
        return res;

    }

    private TitlePlayability validateRequestInformation(CreatePurchaseRequest purchaseRequest, AccountId accountId,
            AssetId assetId) {
        TitlePlayability playability = unuService.validatePlayEligibility(assetId, accountId,
                purchaseRequest.getClient());

        //we'll look at rentals if the title is a rental, but if it's a buy, we only care if we own it
        validateAssetIsNotAlreadyOwned(purchaseRequest.getAccountId(), purchaseRequest.getAssetId(), accountId,
                assetId, !Titles.titleIsElectronicSellThrough(playability.getTitle()), playability);
        validateAvailableAndTransaction(playability);
        Double requestPrice = purchaseRequest.getPrice();

        if (requestPrice != null) {

            if (requestPrice.compareTo(getPrice(playability.getTitle())) != 0) {
                throw PriceMismatchException.forTitle(requestPrice, getPrice(playability.getTitle()));
            }
        }
        return playability;
    }

    private void validateAvailableAndTransaction(TitlePlayability titlePlayability) {

        switch (titlePlayability.getDecision()) {
        case PLAYABLE_TITLE:
            //yippee!
            break;
        case PLAYABLE_PREVIEW:
            throw new AssetIsNotTransactionalException("Cannot purchase a preview asset.");
        case PLAYABLE_NDVR_TITLE:
            throw new AssetIsNotTransactionalException("Cannot purchase an NDVR asset.");
        case NOT_AVAILABLE_ON_VOD_SYSTEM:
            throw new AssetIsNotAvailableException("Asset not available on CCDN.");
        case NOT_IN_WINDOW:
            throw new AssetIsNotAvailableException("License window expired on %1$tm/%1$td/%1$tY.",
                    new Date(titlePlayability.getTitle().getLicenseWindow().getEnd()));
        case NOT_ENTITLED:
            throw new AssetIsNotTransactionalException("Cannot purchase a gated asset.");
        case NOT_ALLOWED_VIA_DL:
            throw new AssetIsNotAvailableException("Asset is restricted by distribution list.");
        case NOT_ALLOWED_VIA_MENU_ITEM:
            throw new AssetIsNotAvailableException("Asset is not available on the VOD menu.");
        case NOT_ALLOWED_FOR_CREDIT_HOLD:
            throw new AccountNotInGoodStandingException("Account on credit hold.");
        case NOT_ALLOWED_FOR_NO_CHARGES_ON_ACCOUNT:
            throw new AccountNotInGoodStandingException("No charges allowed on account");
        case NOT_ALLOWED_FOR_INVALID_HIBIT:
            throw new AccountNotInGoodStandingException("Account has invalid hibit.");

        case NOT_ALLOWED_REQUIRES_HDMI:
            throw new AssetIsNotAvailableException("Asset requires HDMI.");

        }

        if (titlePlayability.getTitle().hasService()) {
            throw new AssetIsNotTransactionalException("Cannot purchase a gated asset.");
        }
        if (StringUtils.containsOnly(titlePlayability.getTitle().getPrice(), "$0.")) {
            throw new AssetIsNotTransactionalException("Cannot purchase a free asset.");
        }

    }

    private void validateAssetIsNotAlreadyOwned(String accountCrn, String assetCrn, AccountId accountId,
            AssetId assetId, boolean checkRentals, TitlePlayability playability) {
        if (playability.getTitle().hasRight()) {
            //call this one first, for owned assets, if you own a higher quality one, you're entitled to 
            //the lower, so if the title comes back with a right for a higher quality asset, 
            //there's no reason to let them buy the lower quality one
            throw new AssetAlreadyOwnedException(accountCrn, assetCrn);
        }

        List<Right> existingRights = lockerService.getAssetRightsByAccountAndAsset(accountId, assetId);
        for (Right right : existingRights) {
            if (right.isPermanent() && right.isPlayable()) {
                throw new AssetAlreadyOwnedException(accountCrn, assetCrn);
            }
            if (checkRentals) {
                if (right.isInWindow() && right.isPlayable()) {
                    throw new AssetAlreadyOwnedException(accountCrn, assetCrn);
                }
            }
        }
    }

    private Pair<Transaction, Date> createPurchaseTransactionInLocker(CreatePurchaseRequest purchaseRequest,
            Title title, AccountId accountId, AssetId assetId, Crn assetCrn, Crn accountCrn) {

        Pair<Transaction, Date> trans = XGatewayUtils.createPurchaseTransactionForLocker(
                purchaseRequest.getClient(), cempTransactionHandler, purchaseRequest.getDeviceId(), title,
                accountId, assetId, assetCrn, accountCrn, awaitEvidenceOfPlay);

        Date expiration = trans.getSecond();
        Transaction lockerTrans = lockerService.createTransaction(trans.getFirst());

        return Pair.create(lockerTrans, expiration);
    }

}