Java tutorial
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())); } }