diff --git a/.gitignore b/.gitignore index 8499fc5..16baa22 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ gradle.properties *.iws .classpath .settings -.project \ No newline at end of file +.project +/bin/ diff --git a/build.gradle b/build.gradle index 8c44ba0..98ec8b2 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ apply plugin: 'signing' group = 'io.sprucehill' archivesBaseName = 'zalando-java-api-wrapper' -version = '0.5.0' +version = '0.6.0-SNAPSHOT' description = 'A Java API client for the Zalando REST API' processResources { @@ -76,7 +76,7 @@ uploadArchives { } snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: hasProperty('ossrhUsername')?ossrhUsername:'', password: hasProperty('ossrhPassword')?ossrhPassword:'') + authentication(userName: this.hasProperty('ossrhUsername')?ossrhUsername:'', password: this.hasProperty('ossrhPassword')?ossrhPassword:'') } pom.project { diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Address.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Address.java new file mode 100644 index 0000000..7793fde --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Address.java @@ -0,0 +1,121 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Address extends Base { + + @JsonProperty + private String id; + + @JsonProperty(value="customer_number") + private String customerNumber; + + @JsonProperty + private String gender; + + @JsonProperty(value="first_name") + private String firstName; + + @JsonProperty(value="last_name") + private String lastName; + + @JsonProperty + private String street; + + @JsonProperty + private String additional; + + @JsonProperty + private String zip; + + @JsonProperty + private String city; + + @JsonProperty(value="country_code") + private String countryCode; + + @JsonProperty(value="pack_station") + private Boolean packStation; + + @JsonProperty(value="default_billing") + private Boolean defaultBilling; + + @JsonProperty(value="default_shipping") + private Boolean defaultShipping; + + public Address(){} + + public Address(String id, String customerNumber, String gender, String firstName, String lastName, String street,String additional, String zip, String city, String countryCode, Boolean packStation,Boolean defaultBilling, Boolean defaultShipping) { + this.id=id; + this.customerNumber=customerNumber; + this.gender=gender; + this.firstName=firstName; + this.lastName=lastName; + this.street=street; + this.additional=additional; + this.city=city; + this.countryCode=countryCode; + this.packStation=packStation; + this.defaultBilling=defaultBilling; + this.defaultShipping=defaultShipping; + this.zip = zip; + } + + public String getId() { + return id; + } + + public String getCustomerNumber() { + return customerNumber; + } + + public String getGender() { + return gender; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getStreet() { + return street; + } + + public String getAdditional() { + return additional; + } + + public String getZip() { + return zip; + } + + public String getCity() { + return city; + } + + public String getCountryCode() { + return countryCode; + } + + public Boolean getPackStation() { + return packStation; + } + + public Boolean getDefaultBilling() { + return defaultBilling; + } + + public Boolean getDefaultShipping() { + return defaultShipping; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckRequest.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckRequest.java new file mode 100644 index 0000000..ae03497 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckRequest.java @@ -0,0 +1,24 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class AddressCheckRequest extends Base { + + @JsonProperty + private Address address; + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckResponse.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckResponse.java new file mode 100644 index 0000000..64499ee --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/AddressCheckResponse.java @@ -0,0 +1,56 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class AddressCheckResponse extends Base { + + @JsonProperty + private String status; + + @JsonProperty + private Boolean blacklisted; + + @JsonProperty + private Address address; + + @JsonProperty(value="normalized_address") + private Address normalizedAddress; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Boolean getBlacklisted() { + return blacklisted; + } + + public void setBlacklisted(Boolean blacklisted) { + this.blacklisted = blacklisted; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public Address getNormalizedAddress() { + return normalizedAddress; + } + + public void setNormalizedAddress(Address normalizedAddress) { + this.normalizedAddress = normalizedAddress; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Cart.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Cart.java new file mode 100644 index 0000000..ce84a64 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Cart.java @@ -0,0 +1,84 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import java.util.ArrayList; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Cart extends Base { + + @JsonProperty + private String id; + + @JsonProperty(value="sales_channel") + private String appDomainId; + + @JsonProperty + private List items = new ArrayList(); + + @JsonProperty(value="items_out_of_stock") + private List itemsOutOfStock = new ArrayList(); + + @JsonProperty + private Delivery delivery; + + @JsonProperty + private Money grossTotal; + + @JsonProperty + private Money taxTotal; + + @JsonProperty(value="cart_url") + private String cartUrl; + + public Cart() {} + + public Cart(String id,String appDomainId ,List items,List itemsOutOfStock,Delivery delivery, + Money grossTotal,Money taxTotal,String cartUrl){ + this.id =id; + this.appDomainId=appDomainId; + this.items =items; + this.itemsOutOfStock =itemsOutOfStock; + this.delivery =delivery; + this.grossTotal =grossTotal; + this.taxTotal= taxTotal; + this.cartUrl=cartUrl; + } + + public String getId() { + return id; + } + + public String getAppDomainId() { + return appDomainId; + } + + public List getItems() { + return items; + } + + public List getItemsOutOfStock() { + return itemsOutOfStock; + } + + public Delivery getDelivery() { + return delivery; + } + + public Money getGrossTotal() { + return grossTotal; + } + + public Money getTaxTotal() { + return taxTotal; + } + + public String getCartUrl() { + return cartUrl; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Checkout.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Checkout.java new file mode 100644 index 0000000..40cfabf --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Checkout.java @@ -0,0 +1,81 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Checkout extends Base { + + @JsonProperty + private String id; + + @JsonProperty(value="customer_number") + private String customerNumber; + + @JsonProperty(value="cart_id") + private String cartId; + + @JsonProperty(value="billing_address_id") + private String billingAddressId; + + @JsonProperty(value="shipping_address_id") + private String shippingAddressId; + + @JsonProperty + private Delivery delivery; + + @JsonProperty + private Payment payment; + + public Checkout() {} + + public Checkout(String id,String customerNumber,String cartId, String billingAddressId,String shippingAddressId,Delivery delivery,Payment payment){ + this.id=id; + this.customerNumber=customerNumber; + this.cartId=cartId; + this.billingAddressId=billingAddressId; + this.shippingAddressId=shippingAddressId; + this.delivery=delivery; + this.payment=payment; + } + + public String getId() { + return id; + } + + public String getCustomerNumber() { + return customerNumber; + } + + public String getCartId() { + return cartId; + } + + public String getBillingAddressId() { + return billingAddressId; + } + + public String getShippingAddressId() { + return shippingAddressId; + } + + public void setBillingAddressId(String billingAddressId) { + this.billingAddressId = billingAddressId; + } + + public void setShippingAddressId(String shippingAddressId) { + this.shippingAddressId = shippingAddressId; + } + + public Delivery getDelivery() { + return delivery; + } + + public Payment getPayment() { + return payment; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Customer.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Customer.java new file mode 100644 index 0000000..8d35770 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Customer.java @@ -0,0 +1,47 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Customer extends Base { + + @JsonProperty(value="customer_number") + private String customerNumber; + + @JsonProperty + private String gender; + + @JsonProperty(value="first_name") + private String firstName; + + @JsonProperty(value="last_name") + private String lastName; + + @JsonProperty + private String email; + + public String getCustomerNumber() { + return customerNumber; + } + + public String getGender() { + return gender; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Delivery.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Delivery.java new file mode 100644 index 0000000..b0727e5 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Delivery.java @@ -0,0 +1,39 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Delivery extends Base { + + @JsonProperty + @JsonFormat(pattern="yyyy-MM-dd") + private Date earliest; + + @JsonProperty + @JsonFormat(pattern="yyyy-MM-dd") + private Date latest; + + public Date getEarliest() { + return earliest; + } + + public void setEarliest(Date earliest) { + this.earliest = earliest; + } + + public Date getLatest() { + return latest; + } + + public void setLatest(Date latest) { + this.latest = latest; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Items.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Items.java new file mode 100644 index 0000000..8f9f4c7 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Items.java @@ -0,0 +1,41 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Items extends Base { + + @JsonProperty + private String sku; + + @JsonProperty + private Integer quantity; + + public Items(){} + + public Items(String sku,Integer quantity){ + this.sku = sku; + this.quantity = quantity; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public String getSku() { + return sku; + } + + public void setSku(String sku) { + this.sku = sku; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Money.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Money.java new file mode 100644 index 0000000..77ac03a --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Money.java @@ -0,0 +1,39 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import java.math.BigInteger; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Money extends Base{ + + public enum Currency { + EUR,DKK,GBP,CHF,NOK,SEK,PLN + } + + @JsonProperty + private BigInteger amount; + + @JsonProperty + private Currency currency; + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public BigInteger getAmount() { + return amount; + } + + public void setAmount(BigInteger amount) { + this.amount = amount; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Order.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Order.java new file mode 100644 index 0000000..e090a6f --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Order.java @@ -0,0 +1,107 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Order extends Base { + + @JsonProperty(value="checkout_id") + private String checkoutId; + + @JsonProperty(value="order_number") + private String orderNumber; + + @JsonProperty(value="customer_number") + private String customerNumber; + + @JsonProperty(value="billing_address") + private Address billingAddress ; + + @JsonProperty(value="shipping_address") + private Address shippingAddress; + + @JsonProperty + private Delivery delivery; + + @JsonProperty(value="gross_total") + private Money grossTotal; + + @JsonProperty(value="tax_total") + private Money taxTotal; + + @JsonProperty + @JsonFormat(pattern = "yyyy-MM-dd") + private String created; + + @JsonProperty(value="detail_url") + private String detailUrl; + + @JsonProperty(value="external_payment_url") + private String externalPaymentUrl; + + public Order(){} + + public Order(String orderNumber,String customerNumber,Address billingAddress,Address shippingAddress,Delivery delivery, + Money grossTotal,Money taxTotal,String created,String detailUrl,String externalPaymentUrl){ + this.orderNumber=orderNumber; + this.customerNumber=customerNumber; + this.billingAddress=billingAddress; + this.shippingAddress=shippingAddress; + this.delivery=delivery; + this.grossTotal=grossTotal; + this.taxTotal=taxTotal; + this.created=created; + this.detailUrl=detailUrl; + this.externalPaymentUrl=externalPaymentUrl; + } + + public String getOrderNumber() { + return orderNumber; + } + + public String getCustomerNumber() { + return customerNumber; + } + + public Address getBillingAddress() { + return billingAddress; + } + + public Address getShippingAddress() { + return shippingAddress; + } + + public Delivery getDelivery() { + return delivery; + } + + public Money getGrossTotal() { + return grossTotal; + } + + public Money getTaxTotal() { + return taxTotal; + } + + public String getCreated() { + return created; + } + + public String getDetailUrl() { + return detailUrl; + } + + public String getExternalPaymentUrl() { + return externalPaymentUrl; + } + + public void setCheckoutId(String checkoutId) { + this.checkoutId = checkoutId; + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Payment.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Payment.java new file mode 100644 index 0000000..0aa95ff --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Payment.java @@ -0,0 +1,75 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import java.util.HashMap; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Payment extends Base { + + @JsonProperty(value="callback_url") + private String callbackUrl; + + @JsonProperty + private Map templateParameters = new HashMap(); + + @JsonProperty(value="selection_page_url") + private String selectionPageUrl; + + @JsonProperty + private Selected selected; + + @JsonProperty + private String token; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public Map getTemplateParameters() { + return templateParameters; + } + + public String getSelectionPageUrl() { + return selectionPageUrl; + } + + public Selected getSelected() { + return selected; + } + + public static class Selected extends Base { + + @JsonProperty + private String method; + + @JsonProperty + private Map metadata = new HashMap(); + + public String getMethod() { + return method; + } + + public Map getMetadata() { + return metadata; + } + } +} + diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/Problem.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Problem.java new file mode 100644 index 0000000..8fd0caf --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/Problem.java @@ -0,0 +1,50 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class Problem extends Base{ + + private String type; + private String title; + private String status; + private String detail; + private String instance; + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } + public String getDetail() { + return detail; + } + public void setDetail(String detail) { + this.detail = detail; + } + public String getInstance() { + return instance; + } + public void setInstance(String instance) { + this.instance = instance; + } + + + +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/model/TokenInfo.java b/src/main/java/io/sprucehill/zalando/api/nativecart/model/TokenInfo.java new file mode 100644 index 0000000..ccd3cfb --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/model/TokenInfo.java @@ -0,0 +1,46 @@ +package io.sprucehill.zalando.api.nativecart.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.sprucehill.zalando.api.model.Base; + +/** + * + * @author dipteewarudkar + * + */ +public class TokenInfo extends Base{ + + @JsonProperty(value="token_type") + public String tokenType; + + @JsonProperty(value="access_token") + public String accessToken; + + @JsonProperty(value="uid") + public String customerNumber; + + public String getTokenType() { + return tokenType; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getCustomerNumber() { + return customerNumber; + } + + public void setCustomerNumber(String customerNumber) { + this.customerNumber = customerNumber; + } +} + diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/AccessTokenService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/AccessTokenService.java new file mode 100644 index 0000000..e841ce8 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/AccessTokenService.java @@ -0,0 +1,62 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.http.HttpHeaders; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicNameValuePair; + +import com.fasterxml.jackson.core.type.TypeReference; + +import io.sprucehill.zalando.api.nativecart.model.TokenInfo; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class AccessTokenService extends AbstractService implements IAccessTokenService { + + @Override + public TokenInfo read() throws Exception { + HttpPost request = postRequest("/access_token"); + + List params = new ArrayList(); + params.add(new BasicNameValuePair("realm","/customers")); + params.add(new BasicNameValuePair("grant_type","client_credentials")); + params.add(new BasicNameValuePair("client_id",clientId)); + params.add(new BasicNameValuePair("client_secret",clientCredential)); + + request.setEntity(new UrlEncodedFormEntity(params)); + + return execute(request, new TypeReference() {}); + } + + @Override + public TokenInfo readFromAuthorizationCode(String authCode,String redirectUrl) throws Exception { + HttpPost request = postRequest("/access_token"); + + List params = new ArrayList(); + params.add(new BasicNameValuePair("realm","/customers")); + params.add(new BasicNameValuePair("grant_type","authorization_code")); + params.add(new BasicNameValuePair("client_id",clientId)); + params.add(new BasicNameValuePair("client_secret",clientCredential)); + params.add(new BasicNameValuePair("code",authCode)); + params.add(new BasicNameValuePair("redirect_uri",redirectUrl)); + + request.setEntity(new UrlEncodedFormEntity(params)); + + return execute(request, new TypeReference() {}); + } + + @Override + public TokenInfo read(String accessToken) throws Exception { + HttpGet request = getRequest("/tokeninfo?access_token="+accessToken); + return execute(request, new TypeReference() {}); + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/AddressService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/AddressService.java new file mode 100644 index 0000000..b284d82 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/AddressService.java @@ -0,0 +1,74 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import java.util.List; + +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ByteArrayEntity; +import com.fasterxml.jackson.core.type.TypeReference; +import io.sprucehill.zalando.api.nativecart.model.Address; +import io.sprucehill.zalando.api.nativecart.model.AddressCheckRequest; +import io.sprucehill.zalando.api.nativecart.model.AddressCheckResponse; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class AddressService extends AbstractService implements IAddressService { + + @Override + public List
read(String accessToken,String customerNumber) throws Exception { + HttpGet request = getRequest("/addresses"); + request.setHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + return execute(request, new TypeReference>() {}); + } + + @Override + public Address read(String accessToken,String customerNumber, String addressId) throws Exception { + HttpGet request = getRequest("/addresses/"+addressId); + request.setHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + return execute(request, new TypeReference
() {}); + } + + @Override + public Address update(String accessToken,String customerNumber, String addressId, Address updateAddressRequest) throws Exception { + HttpPut request = putRequest("/addresses/"+addressId); + + try { + request.setHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.address.update+json"); + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(updateAddressRequest))); + }catch(Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + return execute(request, new TypeReference
() {}); + } + + @Override + public Address create(String accessToken,String customerNumber, Address createAddressRequest) throws Exception { + HttpPost request = postRequest("/addresses"); + request.setHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.address.create+json"); + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(createAddressRequest))); + return execute(request, new TypeReference
() {}); + } + + @Override + public AddressCheckResponse checkAddress(String accessToken,AddressCheckRequest checkAddressRequest) throws Exception { + HttpPost request = postRequest("/address-checks"); + try { + request.setHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.address-check.create+json"); + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(checkAddressRequest))); + }catch(Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + return execute(request, new TypeReference() {}); + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/CartService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CartService.java new file mode 100644 index 0000000..601698a --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CartService.java @@ -0,0 +1,56 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ByteArrayEntity; +import com.fasterxml.jackson.core.type.TypeReference; +import io.sprucehill.zalando.api.nativecart.model.Cart; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class CartService extends AbstractService implements ICartService { + + @Override + public Cart create(String accessToken, Cart createCartRequest) throws Exception { + HttpPost request = postRequest("/carts"); + + try { + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.cart.create+json"); + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(createCartRequest))); + return execute(request, new TypeReference() {}); + }catch(Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + } + + @Override + public Cart read(String access_token, String cart_id) throws Exception { + HttpGet request = getRequest("/carts/" + cart_id); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.cart+json"); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+access_token); + return execute(request, new TypeReference() {}); + } + + @Override + public Cart update(String access_token, String cart_id,Cart updateCartRequest) throws Exception { + HttpPut request = putRequest("/carts/"+cart_id+"/items"); + + try { + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+access_token); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.cart.items.update+json"); + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(updateCartRequest.getItems()))); + return execute(request, new TypeReference() {}); + }catch(Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/CheckoutService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CheckoutService.java new file mode 100644 index 0000000..acbbdae --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CheckoutService.java @@ -0,0 +1,56 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ByteArrayEntity; +import com.fasterxml.jackson.core.type.TypeReference; +import io.sprucehill.zalando.api.nativecart.model.Checkout; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class CheckoutService extends AbstractService implements ICheckoutService { + + @Override + public Checkout read(String accessToken,String customerNumber, String checkout_id) throws Exception { + HttpGet request = getRequest("/checkouts/"+checkout_id); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.checkout.create+json"); + return execute(request, new TypeReference() {}); + } + + @Override + public Checkout create(String accessToken,String customerNumber, Checkout createcheckoutRequest) throws Exception { + HttpPost request = postRequest("/checkouts"); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.checkout.create+json"); + + try { + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(createcheckoutRequest))); + return execute(request, new TypeReference() {}); + }catch (Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + } + + @Override + public Checkout update(String accessToken,String customerNumber, String checkoutId,Checkout updateCheckoutRequest) throws Exception { + HttpPut request = putRequest("/checkouts/"+checkoutId); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.checkout.update+json"); + + try { + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(updateCheckoutRequest))); + return execute(request, new TypeReference() {}); + }catch (Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/CustomerService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CustomerService.java new file mode 100644 index 0000000..0235207 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/CustomerService.java @@ -0,0 +1,22 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.HttpGet; +import com.fasterxml.jackson.core.type.TypeReference; +import io.sprucehill.zalando.api.nativecart.model.Customer; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class CustomerService extends AbstractService implements ICustomerService { + + @Override + public Customer read(String accessToken ,String customerNumber) throws Exception { + HttpGet request = getRequest("/customer"); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + return execute(request, new TypeReference() {}); + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAccessTokenService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAccessTokenService.java new file mode 100644 index 0000000..2c29820 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAccessTokenService.java @@ -0,0 +1,36 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import io.sprucehill.zalando.api.exception.NotFoundException; +import io.sprucehill.zalando.api.nativecart.model.TokenInfo; + +/** + * + * @author dipteewarudkar + * + */ +public interface IAccessTokenService { + + /** + * + * @return Access token + * @throws Exception Any Exception that is thrown while doing the operation + */ + TokenInfo read() throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @return Token details for the given accessToken + * @throws Exception Any Exception that is thrown while doing the operation + */ + TokenInfo read(String accessToken) throws Exception; + + /** + * + * @param authCode authorization code + * @param redirectUrl The redirect url to receive callnack + * @return Token details for the given authorization code + * @throws Exception Any Exception that is thrown while doing the operation + */ + TokenInfo readFromAuthorizationCode(String authCode, String redirectUrl) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAddressService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAddressService.java new file mode 100644 index 0000000..53765b4 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IAddressService.java @@ -0,0 +1,62 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import java.util.List; +import io.sprucehill.zalando.api.nativecart.model.Address; +import io.sprucehill.zalando.api.nativecart.model.AddressCheckRequest; +import io.sprucehill.zalando.api.nativecart.model.AddressCheckResponse; + +/** + * + * @author dipteewarudkar + * + */ +public interface IAddressService { + /** + * + * @param accessToken The access token for authorization + * @param checkAddressRequest The address object to be checked + * @return The address object with normalized address + * @throws Exception Any Exception that is thrown while doing the operation + */ + AddressCheckResponse checkAddress(String accessToken,AddressCheckRequest checkAddressRequest) throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @return The list of user addresses + * @throws Exception Any Exception that is thrown while doing the operation + */ + List
read(String accessToken,String customerNumber) throws Exception ; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param addressId The ID of the address to read + * @return The address with the requested ID for the specified customer + * @throws Exception Any Exception that is thrown while doing the operation + */ + Address read(String accessToken,String customerNumber,String addressId) throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param addressId The ID of the address to update + * @param request The address object to update + * @return The updated address object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Address update(String accessToken,String customerNumber,String addressId,Address request) throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param createAddressRequest The address object to create + * @return Newly created address object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Address create(String accessToken,String customerNumber,Address createAddressRequest) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICartService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICartService.java new file mode 100644 index 0000000..02e83c7 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICartService.java @@ -0,0 +1,39 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import io.sprucehill.zalando.api.nativecart.model.Cart; + +/** + * + * @author dipteewarudkar + * + */ +public interface ICartService { + + /** + * + * @param accessToken access token for performing create cart operation + * @param createCartRequest The Cart object to be created + * @return Newly created cart object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Cart create(String accessToken,Cart createCartRequest) throws Exception; + + /** + * + * @param accessToken access token for performing create cart operation + * @param cartId The ID of the cart to read + * @return The cart with the requested ID for the specified accessToken + * @throws Exception Any Exception that is thrown while doing the operation + */ + Cart read(String accessToken,String cartId) throws Exception; + + /** + * + * @param accessToken access token for performing update cart operation + * @param cartId The ID of the cart to update + * @param updateCartRequest Cart object to be updated + * @return The updated Cart object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Cart update(String accessToken,String cartId,Cart updateCartRequest) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICheckoutService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICheckoutService.java new file mode 100644 index 0000000..c724f5b --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICheckoutService.java @@ -0,0 +1,42 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import io.sprucehill.zalando.api.nativecart.model.Checkout; + +/** + * + * @author dipteewarudkar + * + */ +public interface ICheckoutService { + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param checkoutId The ID of the checkout to read + * @return The checkout object with the requested ID for the specified customer + * @throws Exception Any Exception that is thrown while doing the operation + */ + Checkout read(String accessToken,String customerNumber,String checkoutId) throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param CreatecheckoutRequest The checkout object to be created + * @return The newly created checkout object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Checkout create(String accessToken,String customerNumber,Checkout CreatecheckoutRequest) throws Exception; + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @param checkoutId The ID of the address to update + * @param updateCheckoutRequest The checkout object to be updated + * @return The updated checkout object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Checkout update(String accessToken,String customerNumber,String checkoutId,Checkout updateCheckoutRequest) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICustomerService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICustomerService.java new file mode 100644 index 0000000..4d2d596 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/ICustomerService.java @@ -0,0 +1,20 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import io.sprucehill.zalando.api.nativecart.model.Customer; + +/** + * + * @author dipteewarudkar + * + */ +public interface ICustomerService { + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The customer unique id + * @return Details of the customer with specified customer_number + * @throws Exception Any Exception that is thrown while doing the operation + */ + Customer read(String accessToken,String customerNumber) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/IOrderService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IOrderService.java new file mode 100644 index 0000000..e9e240a --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/IOrderService.java @@ -0,0 +1,21 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import io.sprucehill.zalando.api.nativecart.model.Order; + +/** + * + * @author dipteewarudkar + * + */ +public interface IOrderService { + + /** + * + * @param accessToken The access token for authorization + * @param customerNumber The unique id of the customer + * @param createOrderRequest The order object to be created + * @return The newly create order object + * @throws Exception Any Exception that is thrown while doing the operation + */ + Order create(String accessToken,String customerNumber,Order createOrderRequest) throws Exception; +} diff --git a/src/main/java/io/sprucehill/zalando/api/nativecart/service/OrderService.java b/src/main/java/io/sprucehill/zalando/api/nativecart/service/OrderService.java new file mode 100644 index 0000000..9df61a2 --- /dev/null +++ b/src/main/java/io/sprucehill/zalando/api/nativecart/service/OrderService.java @@ -0,0 +1,30 @@ +package io.sprucehill.zalando.api.nativecart.service; + +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import com.fasterxml.jackson.core.type.TypeReference; +import io.sprucehill.zalando.api.nativecart.model.Order; +import io.sprucehill.zalando.api.service.AbstractService; + +/** + * + * @author dipteewarudkar + * + */ +public class OrderService extends AbstractService implements IOrderService { + + @Override + public Order create(String accessToken,String customerNumber, Order createOrderRequest) throws Exception { + HttpPost request = postRequest("/orders"); + request.addHeader(HttpHeaders.AUTHORIZATION,"Bearer "+accessToken); + request.addHeader(HttpHeaders.CONTENT_TYPE,"application/x.zalando.customer.order.create+json"); + try { + request.setEntity(new ByteArrayEntity(objectMapper.writeValueAsBytes(createOrderRequest))); + }catch(Throwable t) { + logger.warn(t.getMessage()); + throw new RuntimeException(t); + } + return execute(request, new TypeReference() {}); + } +} diff --git a/src/main/java/io/sprucehill/zalando/api/service/AbstractService.java b/src/main/java/io/sprucehill/zalando/api/service/AbstractService.java index 9f33cbd..3b6c608 100644 --- a/src/main/java/io/sprucehill/zalando/api/service/AbstractService.java +++ b/src/main/java/io/sprucehill/zalando/api/service/AbstractService.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.sprucehill.zalando.api.exception.NotFoundException; import io.sprucehill.zalando.api.model.Domain; +import io.sprucehill.zalando.api.nativecart.model.Problem; + import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -23,268 +25,307 @@ */ public abstract class AbstractService { - String apiBase = "https://api.zalando.com"; - - String scheme; - - String host; - - Integer port; - - String pathPrefix; - - protected Domain defaultDomain; - - protected Logger logger = LoggerFactory.getLogger(getClass()); - - protected HttpClient httpClient; - - protected ObjectMapper objectMapper; - - /** - * Set a different API base - * - * @param apiBase The API base to use; defaults to 'https://api.zalando.com' - */ - public void setApiBase(String apiBase) { - this.apiBase = apiBase; - } - - /** - * Set the default domain to use; this is a mandatory setter to be called - * - * @param defaultDomain The default shop domain to use - */ - public void setDefaultDomain(Domain defaultDomain) { - this.defaultDomain = defaultDomain; - } - - /** - * Set a custom HttpClient to use; the bean will create a default HttpClient on its postConstruct method if no HttpClient has been set previously. - * You might want to set your custom HttpClient as the default implementation does not use any pooling or threading implementation. - * - * @param httpClient The HttpClient to use. - */ - public void setHttpClient(HttpClient httpClient) { - this.httpClient = httpClient; - } - - /** - * Set a custom ObjectMapper to use; the bean will create a default ObjectMapper on its postConstruct method if no ObjectMapper has been set previously. - * - * @param objectMapper The ObjectMapper to use. - */ - public void setObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - /** - * Call this method on postConstruct for any subclasses as it takes care to initialize the bean - */ - @PostConstruct - public void postConstruct() { - if (null == httpClient) { - httpClient = HttpClientBuilder.create().build(); - } - if (null == objectMapper) { - objectMapper = new ObjectMapper(); - } - if (null == defaultDomain) { - throw new RuntimeException("'defaultDomain' must be set!"); - } - if (null == apiBase) { - throw new RuntimeException("'apiBase' must be set!"); - } - try { - URI uri = new URI(apiBase); - scheme = uri.getScheme(); - host = uri.getHost(); - port = uri.getPort(); - pathPrefix = uri.getPath(); - if (("https".equalsIgnoreCase(scheme) && 443 == port) || ("http".equalsIgnoreCase(scheme) && 80 == port)) { - port = null; - } - if ("/".equalsIgnoreCase(pathPrefix)) { - pathPrefix = null; - } - else if (pathPrefix.endsWith("/")) { - pathPrefix = pathPrefix.substring(0,pathPrefix.length()-1); - } - } - catch (URISyntaxException e) { - throw new RuntimeException("'apiBase' is invalid"); - } - } - - /** - * Create and initialize a GET request for the specified path - * - * @param path The path of the GET request - * @return A HttpGet object for the specified path - */ - HttpGet getRequest(String path) { - return enrich(new HttpGet(normalizePath(path))); - } - - /** - * Create an initialize a GET request for the specified URIBuilder - * - * @param uriBuilder The URIBuilder to work upon - * @return A HttGet object for the specified URIBuilder's URI - * @throws URISyntaxException Throw if URI cannot be built from the supplied URIBuilder - */ - HttpGet getRequest(URIBuilder uriBuilder) throws URISyntaxException { - return enrich(new HttpGet(normalize(uriBuilder))); - } - - /** - * Create and initialize a POST request for the specified path - * - * @param path The path of the POST request - * @return A HttpGet object for the specified path - */ - HttpPost postRequest(String path) { - return enrich(new HttpPost(normalizePath(path))); - } - - /** - * Create and initialize a PUT request for the specified path - * - * @param path The path of the PUT request - * @return A HttpGet object for the specified path - */ - HttpPut putRequest(String path) { - return enrich(new HttpPut(normalizePath(path))); - } - - /** - * Create and initialize a DELETE request for the specified path - * - * @param path The path of the DELETE request - * @return A HttpGet object for the specified path - */ - HttpDelete deleteRequest(String path) { - return enrich(new HttpDelete(normalizePath(path))); - } - - /** - * Helper method to normalize a supplied path; - * the current implementation only append a '/' if none is present and prefix with API Base - * - * @param path The path to normalize - * @return The normalized path - */ - protected String normalizePath(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } - return apiBase + path; - } - - /** - * Helper method to normalize a supplied path; - * the current implementation will set scheme, host, port and prefix with pathPrefix if present - * - * @param uriBuilder The URIBuilder to work upon - * @return A normalized path with defaults set if necessary - * @throws URISyntaxException Throw if the URL cannot be built - */ - protected String normalize(URIBuilder uriBuilder) throws URISyntaxException { - if (null == uriBuilder.getHost() || null == uriBuilder.getScheme()) { - uriBuilder.setHost(host); - uriBuilder.setScheme(scheme); - if (null != port) { - uriBuilder.setPort(port); - } - if (null != pathPrefix) { - uriBuilder.setPath(pathPrefix + uriBuilder.getPath()); - } - } - return uriBuilder.build().toString(); - } - - /** - * Enrich a HttpRequest with some default stuff; - * the current implementation does nothing here - * - * @param request The request to enrich - * @param Generic method to handle different types of HttpRequests - * @return The supplied HttpRequest object - */ - protected T enrich(T request) { - return request; - } - - /** - * Execute a HttpRequest and handle common response states. - * - * @param request The HttpRequest to execute - * @param typeReference The type of the expected response - * @param Generic method to request different response data - * @return The response data for the request - * @throws NotFoundException This exception is thrown when a 404 status code is encountered on the response - */ - protected T execute(HttpRequestBase request, TypeReference typeReference) throws NotFoundException { - try { - if (null == request.getHeaders(HttpHeaders.ACCEPT_LANGUAGE)) { - request.addHeader(HttpHeaders.ACCEPT_LANGUAGE,defaultDomain.getLocale()); - } - HttpResponse httpResponse = httpClient.execute(request); - if (200 == httpResponse.getStatusLine().getStatusCode()) { - return objectMapper.readValue(httpResponse.getEntity().getContent(),typeReference); - } - if (404 == httpResponse.getStatusLine().getStatusCode()) { - throw new NotFoundException(httpResponse.getStatusLine().getReasonPhrase()); - } - else { - throw new RuntimeException("StatusCode: "+httpResponse.getStatusLine().getStatusCode() + ", Reason: " + httpResponse.getStatusLine().getReasonPhrase()); - } - } - catch (IOException e) { - logger.error(e.getMessage(), e); - throw new RuntimeException(e); - } - finally { - if (null != request && !request.isAborted()) { - request.abort(); - } - } - } - - protected static abstract class Init> { - - protected S service; - - protected Init(S service) { - this.service = service; - } - - public B withHttpClient(HttpClient httpClient) { - service.setHttpClient(httpClient); - return self(); - } - - public B withObjectMapper(ObjectMapper objectMapper) { - service.setObjectMapper(objectMapper); - return self(); - } - - public B withApiBase(String apiBase) { - service.setApiBase(apiBase); - return self(); - } - - public B withDefaultDomain(Domain defaultDomain) { - service.setDefaultDomain(defaultDomain); - return self(); - } - - protected void onBuild() { - service.postConstruct(); - } - - protected abstract B self(); - - public abstract I build(); - } + String apiBase = "https://api.zalando.com"; + + String scheme; + + String host; + + Integer port; + + String pathPrefix; + + protected Domain defaultDomain; + + protected Logger logger = LoggerFactory.getLogger(getClass()); + + protected HttpClient httpClient; + + protected ObjectMapper objectMapper; + + protected String clientId; + + protected String clientCredential; + + /** + * Set a client Id + * + * @param clientId The clientId of the app + */ + public void setClientId(String clientId) { + this.clientId = clientId; + } + + /** + * Set a client clientCredential + * + * @param clientCredential The client secret of the app + */ + public void setClientCredential(String clientCredential) { + this.clientCredential = clientCredential; + } + + /** + * Set a different API base + * + * @param apiBase The API base to use; defaults to 'https://api.zalando.com' + */ + public void setApiBase(String apiBase) { + this.apiBase = apiBase; + } + + /** + * Set the default domain to use; this is a mandatory setter to be called + * + * @param defaultDomain The default shop domain to use + */ + public void setDefaultDomain(Domain defaultDomain) { + this.defaultDomain = defaultDomain; + } + + /** + * Set a custom HttpClient to use; the bean will create a default HttpClient on its postConstruct method if no HttpClient has been set previously. + * You might want to set your custom HttpClient as the default implementation does not use any pooling or threading implementation. + * + * @param httpClient The HttpClient to use. + */ + public void setHttpClient(HttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Set a custom ObjectMapper to use; the bean will create a default ObjectMapper on its postConstruct method if no ObjectMapper has been set previously. + * + * @param objectMapper The ObjectMapper to use. + */ + public void setObjectMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Call this method on postConstruct for any subclasses as it takes care to initialize the bean + */ + @PostConstruct + public void postConstruct() { + if (null == httpClient) { + httpClient = HttpClientBuilder.create().build(); + } + if (null == objectMapper) { + objectMapper = new ObjectMapper(); + } + if (null == defaultDomain) { + throw new RuntimeException("'defaultDomain' must be set!"); + } + if (null == apiBase) { + throw new RuntimeException("'apiBase' must be set!"); + } + try { + URI uri = new URI(apiBase); + scheme = uri.getScheme(); + host = uri.getHost(); + port = uri.getPort(); + pathPrefix = uri.getPath(); + if (("https".equalsIgnoreCase(scheme) && 443 == port) || ("http".equalsIgnoreCase(scheme) && 80 == port)) { + port = null; + } + if ("/".equalsIgnoreCase(pathPrefix)) { + pathPrefix = null; + } + else if (pathPrefix.endsWith("/")) { + pathPrefix = pathPrefix.substring(0,pathPrefix.length()-1); + } + } + catch (URISyntaxException e) { + throw new RuntimeException("'apiBase' is invalid"); + } + } + + /** + * Create and initialize a GET request for the specified path + * + * @param path The path of the GET request + * @return A HttpGet object for the specified path + */ + protected HttpGet getRequest(String path) { + return enrich(new HttpGet(normalizePath(path))); + } + + /** + * Create an initialize a GET request for the specified URIBuilder + * + * @param uriBuilder The URIBuilder to work upon + * @return A HttGet object for the specified URIBuilder's URI + * @throws URISyntaxException Throw if URI cannot be built from the supplied URIBuilder + */ + HttpGet getRequest(URIBuilder uriBuilder) throws URISyntaxException { + return enrich(new HttpGet(normalize(uriBuilder))); + } + + /** + * Create and initialize a POST request for the specified path + * + * @param path The path of the POST request + * @return A HttpGet object for the specified path + */ + protected HttpPost postRequest(String path) { + return enrich(new HttpPost(normalizePath(path))); + } + + /** + * Create and initialize a PUT request for the specified path + * + * @param path The path of the PUT request + * @return A HttpGet object for the specified path + */ + protected HttpPut putRequest(String path) { + return enrich(new HttpPut(normalizePath(path))); + } + + /** + * Create and initialize a DELETE request for the specified path + * + * @param path The path of the DELETE request + * @return A HttpGet object for the specified path + */ + HttpDelete deleteRequest(String path) { + return enrich(new HttpDelete(normalizePath(path))); + } + + /** + * Helper method to normalize a supplied path; + * the current implementation only append a '/' if none is present and prefix with API Base + * + * @param path The path to normalize + * @return The normalized path + */ + protected String normalizePath(String path) { + if (!path.startsWith("/")) { + path = "/" + path; + } + return apiBase + path; + } + + /** + * Helper method to normalize a supplied path; + * the current implementation will set scheme, host, port and prefix with pathPrefix if present + * + * @param uriBuilder The URIBuilder to work upon + * @return A normalized path with defaults set if necessary + * @throws URISyntaxException Throw if the URL cannot be built + */ + protected String normalize(URIBuilder uriBuilder) throws URISyntaxException { + if (null == uriBuilder.getHost() || null == uriBuilder.getScheme()) { + uriBuilder.setHost(host); + uriBuilder.setScheme(scheme); + if (null != port) { + uriBuilder.setPort(port); + } + if (null != pathPrefix) { + uriBuilder.setPath(pathPrefix + uriBuilder.getPath()); + } + } + return uriBuilder.build().toString(); + } + + /** + * Enrich a HttpRequest with some default stuff; + * the current implementation does nothing here + * + * @param request The request to enrich + * @param Generic method to handle different types of HttpRequests + * @return The supplied HttpRequest object + */ + protected T enrich(T request) { + return request; + } + + /** + * Execute a HttpRequest and handle common response states. + * + * @param request The HttpRequest to execute + * @param typeReference The type of the expected response + * @param Generic method to request different response data + * @return The response data for the request + * @throws NotFoundException This exception is thrown when a resource is not found + */ + protected T execute(HttpRequestBase request, TypeReference typeReference) throws NotFoundException { + try { + if (null == request.getHeaders(HttpHeaders.ACCEPT_LANGUAGE)) { + request.addHeader(HttpHeaders.ACCEPT_LANGUAGE,defaultDomain.getLocale()); + } + HttpResponse httpResponse = httpClient.execute(request); + if (200 == httpResponse.getStatusLine().getStatusCode()) { + return objectMapper.readValue(httpResponse.getEntity().getContent(),typeReference); + } + + if (404 == httpResponse.getStatusLine().getStatusCode()) { + throw new NotFoundException(httpResponse.getStatusLine().getReasonPhrase()); + } + else { + try{ + Problem problem = objectMapper.readValue(httpResponse.getEntity().getContent(),Problem.class); + throw new RuntimeException("StatusCode: "+problem.getStatus() + ", Reason: " + problem.getDetail()); + }catch(Exception e){ + throw new RuntimeException("StatusCode: "+httpResponse.getStatusLine().getStatusCode() + ", Reason: " + httpResponse.getStatusLine().getReasonPhrase()); + } + + } + } + catch (IOException e) { + logger.error(e.getMessage(), e); + throw new RuntimeException(e); + } + finally { + if (null != request && !request.isAborted()) { + request.abort(); + } + } + } + + protected static abstract class Init> { + + protected S service; + + protected Init(S service) { + this.service = service; + } + + public B withHttpClient(HttpClient httpClient) { + service.setHttpClient(httpClient); + return self(); + } + + public B withObjectMapper(ObjectMapper objectMapper) { + service.setObjectMapper(objectMapper); + return self(); + } + + public B withApiBase(String apiBase) { + service.setApiBase(apiBase); + return self(); + } + + public B withDefaultDomain(Domain defaultDomain) { + service.setDefaultDomain(defaultDomain); + return self(); + } + + public B withClientId(String clientId) { + service.setClientId(clientId);; + return self(); + } + + public B withClientCredential(String clientCredential) { + service.setClientCredential(clientCredential);; + return self(); + } + + protected void onBuild() { + service.postConstruct(); + } + + protected abstract B self(); + + public abstract I build(); + } }