com.appdirect.connector.autodesk.service.AutodeskServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.appdirect.connector.autodesk.service.AutodeskServiceImpl.java

Source

package com.appdirect.connector.autodesk.service;

import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.appdirect.connector.autodesk.entity.AutodeskOrder;
import com.appdirect.connector.autodesk.exception.AutodeskAPIException;
import com.appdirect.connector.autodesk.exception.AutodeskRetryServiceException;
import com.appdirect.connector.autodesk.exception.AutodeskServiceException;
import com.appdirect.connector.autodesk.respository.AutodeskOrderRepository;
import com.appdirect.connector.autodesk.rest.converter.DefaultConverter;
import com.appdirect.connector.autodesk.rest.converter.OrderDetailsConverter;
import com.appdirect.connector.autodesk.rest.model.AutodeskResponse;
import com.appdirect.connector.autodesk.rest.model.order.common.RevokeResponse;
import com.appdirect.connector.autodesk.rest.model.order.cancel.CancelOrderRequest;
import com.appdirect.connector.autodesk.rest.model.order.details.OrderDetailsResponse;
import com.appdirect.connector.autodesk.rest.model.order.details.OrderItemsArray;
import com.appdirect.connector.autodesk.rest.model.order.place.PlaceOrderRequest;
import com.appdirect.connector.autodesk.rest.model.order.place.PlaceOrderResponse;
import com.appdirect.connector.autodesk.rest.model.order.status.OrderStatusResponse;
import com.appdirect.connector.autodesk.rest.model.products.add.AddProductsRequest;
import com.appdirect.connector.autodesk.rest.model.products.add.AddProductsResponse;
import com.appdirect.connector.autodesk.rest.model.products.price.Price;
import com.appdirect.connector.autodesk.rest.model.products.price.PriceResponse;
import com.appdirect.connector.autodesk.rest.model.products.remove.RemoveProductsRequest;
import com.appdirect.connector.autodesk.rest.model.seats.add.AddSeatsRequest;
import com.appdirect.connector.autodesk.rest.model.seats.add.AddSeatsResponse;
import com.appdirect.connector.autodesk.rest.model.seats.remove.RemoveSeatsRequest;
import com.appdirect.connector.autodesk.type.OperationType;
import com.appdirect.connector.autodesk.type.StatusType;
import com.appdirect.connector.autodesk.util.RequestBuilderHelper;

import retrofit2.Call;
import retrofit2.Response;

@Slf4j
@Service
public class AutodeskServiceImpl implements AutodeskService {

    private static final String SUBS_ID_NOT_FOUND_MESSAGE = "Failed to get subscription id for poNumber %s and product %s";
    private static final String SKU_NOT_FOUND_ERROR_MESSAGE = "Failed to get sku for product %s";
    private static final String NEW = "New";

    @Value("${autodesk.csn.renewable}")
    private String autodeskRenewable;

    @Value("${autodesk.csn.recurring}")
    private String autodeskRecurring;

    @Autowired
    private AutodeskRestService restService;

    @Autowired
    private AutodeskProductService productService;

    @Autowired
    private DefaultConverter defaultConverter;

    @Autowired
    private OrderDetailsConverter orderDetailsConverter;

    @Autowired
    private RequestBuilderHelper requestBuilder;

    @Autowired
    private AutodeskOrderRepository orderRepository;

    @Autowired
    private AutodeskRetryService retryService;

    @Override
    public CompletableFuture<AutodeskResponse> placeOrder(String poNumber, String productName, Integer quantity)
            throws AutodeskServiceException, AutodeskAPIException {
        String sku = getSku(productName, OperationType.INITIAL_ORDER);
        Double price = getPrice(sku);

        try {
            PlaceOrderRequest request = requestBuilder.buildPlaceOrderRequest(poNumber, sku, quantity, price);

            Call<PlaceOrderResponse> placeOrderCall = restService.placeOrder(autodeskRecurring, request);
            Response<PlaceOrderResponse> placeOrderResponse = placeOrderCall.execute();

            PlaceOrderResponse apiResponse = defaultConverter.process(placeOrderResponse);

            return asyncFutureWithCallback(apiResponse.getReferenceNumber(), response -> saveOrder(poNumber));
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    /**
     * Retrieves contract number for a given poNumber and stores the created order
     *
     * @param poNumber
     */
    protected void saveOrder(String poNumber) {
        try {
            String contract = retryService
                    .getWithRetryCondition(() -> getOrderDetails(poNumber).getContractNumber(), failure -> true);
            AutodeskOrder order = new AutodeskOrder(poNumber, contract);
            orderRepository.save(order);
        } catch (AutodeskRetryServiceException e) {
            log.error("Couldn't save order for poNumber = {} ", poNumber, e);
        }
    }

    @Override
    public OrderStatusResponse getOrderStatus(String referenceNumber)
            throws AutodeskServiceException, AutodeskAPIException {
        try {
            Call<OrderStatusResponse> getOrderStatusCall = restService.getOrderStatus(autodeskRecurring,
                    referenceNumber);
            Response<OrderStatusResponse> getOrderStatusResponse = getOrderStatusCall.execute();

            return defaultConverter.process(getOrderStatusResponse);
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public CompletableFuture<AutodeskResponse> addSeats(String poNumber, String productName, Integer quantity)
            throws AutodeskServiceException, AutodeskAPIException {
        String sku = getSku(productName, OperationType.ADD_SEAT);
        Double price = getPrice(sku);

        String contractNumber = getContractNumber(poNumber);
        String subscriptionId = getSubscriptionId(poNumber, contractNumber, productName);

        try {
            AddSeatsRequest request = requestBuilder.buildAddSeatsRequest(poNumber, contractNumber, subscriptionId,
                    sku, quantity, price);
            Call<AddSeatsResponse> addSeatsCall = restService.addSeats(autodeskRecurring, request);
            Response<AddSeatsResponse> addSeatsResponse = addSeatsCall.execute();

            AddSeatsResponse apiResponse = defaultConverter.process(addSeatsResponse);

            return asyncFuture(apiResponse.getReferenceNumber());
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public CompletableFuture<AutodeskResponse> cancelOrder(String poNumber)
            throws AutodeskServiceException, AutodeskAPIException {
        String contractNumber = getContractNumber(poNumber);

        try {
            CancelOrderRequest request = requestBuilder.buildCancelOrderRequest(contractNumber);

            Call<RevokeResponse> cancelOrderCall = restService.cancelOrder(autodeskRecurring, request);
            Response<RevokeResponse> cancelOrderResponse = cancelOrderCall.execute();

            RevokeResponse apiResponse = defaultConverter.process(cancelOrderResponse);

            return asyncFuture(apiResponse.getReferenceNumber());
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public CompletableFuture<AutodeskResponse> removeProducts(String poNumber, String productName)
            throws AutodeskServiceException, AutodeskAPIException {
        String contractNumber = getContractNumber(poNumber);
        String subscriptionId = getSubscriptionId(poNumber, contractNumber, productName);

        try {
            RemoveProductsRequest request = requestBuilder.buildRemoveProductsRequest(contractNumber,
                    subscriptionId);

            Call<RevokeResponse> removeProductsCall = restService.removeProducts(autodeskRecurring, request);
            Response<RevokeResponse> removeProductsResponse = removeProductsCall.execute();

            RevokeResponse apiResponse = defaultConverter.process(removeProductsResponse);

            return asyncFuture(apiResponse.getReferenceNumber());
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public OrderDetailsResponse getOrderDetails(String poNumber)
            throws AutodeskServiceException, AutodeskAPIException {
        try {
            Call<OrderDetailsResponse> getOrderDetailsCall = restService.getOrderDetails(autodeskRecurring,
                    autodeskRecurring, poNumber);
            Response<OrderDetailsResponse> getOrderDetailsResponse = getOrderDetailsCall.execute();

            return orderDetailsConverter.process(getOrderDetailsResponse);
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public CompletableFuture<AutodeskResponse> removeSeats(String poNumber, String productName, Integer quantity)
            throws AutodeskServiceException, AutodeskAPIException {
        String contractNumber = getContractNumber(poNumber);
        String subscriptionId = getSubscriptionId(poNumber, contractNumber, productName);

        try {
            RemoveSeatsRequest request = requestBuilder.buildRemoveSeatsRequest(contractNumber, subscriptionId,
                    quantity);

            Call<RevokeResponse> removeSeatsCall = restService.removeSeats(autodeskRecurring, request);
            Response<RevokeResponse> removeSeatsResponse = removeSeatsCall.execute();

            RevokeResponse apiResponse = defaultConverter.process(removeSeatsResponse);

            return asyncFuture(apiResponse.getReferenceNumber());
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    @Override
    public CompletableFuture<AutodeskResponse> addProducts(String poNumber, String productName, Integer quantity)
            throws AutodeskServiceException, AutodeskAPIException {
        String sku = getSku(productName, OperationType.ADD_PRODUCT);
        String contractNumber = getContractNumber(poNumber);
        Double price = getPrice(sku);

        try {
            AddProductsRequest request = requestBuilder.buildAddProductsRequest(poNumber, contractNumber, sku,
                    quantity, price);
            Call<AddProductsResponse> addProductsCall = restService.addProducts(autodeskRecurring, request);
            Response<AddProductsResponse> addProductsResponse = addProductsCall.execute();

            AddProductsResponse apiResponse = defaultConverter.process(addProductsResponse);

            return asyncFuture(apiResponse.getReferenceNumber());
        } catch (AutodeskAPIException e) {
            throw e;
        } catch (Throwable t) {
            throw new AutodeskServiceException(t);
        }
    }

    protected String getContractNumber(String poNumber) throws AutodeskServiceException, AutodeskAPIException {

        Optional<String> contractNumber = Optional.ofNullable(orderRepository.findOne(poNumber))
                .map(o -> o.getContractNumber());
        if (contractNumber.isPresent()) {
            return contractNumber.get();
        } else {
            return getOrderDetails(poNumber).getContractNumber();
        }
    }

    protected String getSku(String productName, OperationType operation) throws AutodeskServiceException {
        return productService.getProductByNameAndOperation(productName, operation)
                .orElseThrow(
                        () -> new AutodeskServiceException(String.format(SKU_NOT_FOUND_ERROR_MESSAGE, productName)))
                .getSku();
    }

    protected Double getPrice(String sku) throws AutodeskServiceException, AutodeskAPIException {
        PriceResponse priceResponse = productService.getPrice(sku);
        Price price = priceResponse.getResponse();
        return price.getNetPrice();
    }

    protected String getSubscriptionId(String poNumber, String contractNumber, String productName)
            throws AutodeskServiceException, AutodeskAPIException {
        String initialSku = getSku(productName, OperationType.INITIAL_ORDER);
        OrderDetailsResponse orderDetails = getOrderDetails(poNumber);

        Optional<OrderItemsArray> itemOptional = orderDetails.getMessage().getElements().stream()
                .filter(element -> element.getOrderHeaderArray().stream()
                        .filter(h -> h.getContractNumber().equals(contractNumber)).findFirst().isPresent())
                .findFirst().map(element -> element.getOrderItemsArray()).orElse(Collections.emptyList()).stream()
                .filter(item -> item.getSku().equals(initialSku) && item.getSalesLicenseType().equals(NEW))
                .findFirst();

        return itemOptional.orElseThrow(
                () -> new AutodeskServiceException(String.format(SUBS_ID_NOT_FOUND_MESSAGE, poNumber, productName)))
                .getSubsId();
    }

    protected CompletableFuture<AutodeskResponse> asyncFuture(String referenceNumber) {
        return asyncFutureWithCallback(referenceNumber, response -> {
        });
    }

    protected CompletableFuture<AutodeskResponse> asyncFutureWithCallback(String referenceNumber,
            Consumer<AutodeskResponse> onSuccess) {
        return retryService.getAsyncResponse(() -> getOrderStatus(referenceNumber), onSuccess,
                response -> StatusType.ACCEPTED.equals(response.getStatus()),
                response -> StatusType.FAILED.equals(response.getStatus()));
    }
}