4848import com .shopify .model .ShopifyCustomerRoot ;
4949import com .shopify .model .ShopifyCustomerUpdateRequest ;
5050import com .shopify .model .ShopifyCustomerUpdateRoot ;
51+ import com .shopify .model .ShopifyCustomersRoot ;
5152import com .shopify .model .ShopifyFulfillment ;
5253import com .shopify .model .ShopifyFulfillmentCreationRequest ;
5354import com .shopify .model .ShopifyFulfillmentRoot ;
5455import com .shopify .model .ShopifyFulfillmentUpdateRequest ;
56+ import com .shopify .model .ShopifyGetCustomersRequest ;
5557import com .shopify .model .ShopifyGiftCard ;
5658import com .shopify .model .ShopifyGiftCardCreationRequest ;
5759import com .shopify .model .ShopifyGiftCardRoot ;
9294
9395public class ShopifySdk {
9496
97+ private static final String EMPTY_STRING = "" ;
98+
99+ static final String RETRY_AFTER_HEADER = "Retry-After" ;
100+
95101 private static final String MINIMUM_REQUEST_RETRY_DELAY_CANNOT_BE_LARGER_THAN_MAXIMUM_REQUEST_RETRY_DELAY_MESSAGE = "Maximum request retry delay must be larger than minimum request retry delay." ;
96102
97103 private static final String INVALID_MAXIMUM_REQUEST_RETRY_TIMEOUT_MESSAGE = "Maximum request retry timeout cannot be set lower than 2 seconds." ;
@@ -131,7 +137,12 @@ public class ShopifySdk {
131137 static final String ANY_STATUSES = "any" ;
132138 static final String CREATED_AT_MIN_QUERY_PARAMETER = "created_at_min" ;
133139 static final String CREATED_AT_MAX_QUERY_PARAMETER = "created_at_max" ;
140+ static final String UPDATED_AT_MIN_QUERY_PARAMETER = "updated_at_min" ;
141+ static final String UPDATED_AT_MAX_QUERY_PARAMETER = "updated_at_max" ;
134142 static final String ATTRIBUTION_APP_ID_QUERY_PARAMETER = "attribution_app_id" ;
143+ static final String IDS_QUERY_PARAMETER = "ids" ;
144+ static final String SINCE_ID_QUERY_PARAMETER = "since_id" ;
145+ static final String QUERY_QUERY_PARAMETER = "query" ;
135146 static final String CALCULATE = "calculate" ;
136147 static final String REFUNDS = "refunds" ;
137148 static final String TRANSACTIONS = "transactions" ;
@@ -171,19 +182,20 @@ public class ShopifySdk {
171182 private long minimumRequestRetryRandomDelayMilliseconds ;
172183 private long maximumRequestRetryRandomDelayMilliseconds ;
173184 private long maximumRequestRetryTimeoutMilliseconds ;
174- private final ShopifySdkRetryListener shopifySdkRetryListener = new ShopifySdkRetryListener ();
175185
176186 private static final Client CLIENT = buildClient ();
177187
178188 private static final String CUSTOMERS = "customers" ;
189+ private static final String SEARCH = "search" ;
179190
180191 public static interface OptionalsStep {
181192
182193 /**
183- * The Shopify SDK uses random waits in between retry attempts. Minimum duration
184- * time to wait before retrying a failed request. Value must also be less than
185- * {@link #withMaximumRequestRetryRandomDelay(int, TimeUnit) Maximum Request
186- * Retry Random Delay}.<br>
194+ * The Shopify SDK uses random waits in between retry attempts. Minimum
195+ * duration time to wait before retrying a failed request. Value must
196+ * also be less than
197+ * {@link #withMaximumRequestRetryRandomDelay(int, TimeUnit) Maximum
198+ * Request Retry Random Delay}.<br>
187199 * Default value is: 1 second.
188200 *
189201 * @param duration
@@ -193,10 +205,11 @@ public static interface OptionalsStep {
193205 OptionalsStep withMinimumRequestRetryRandomDelay (int duration , TimeUnit timeUnit );
194206
195207 /**
196- * The Shopify SDK uses random waits in between retry attempts. Maximum duration
197- * time to wait before retrying a failed request. Value must also be more than
198- * {@link #withMinimumRequestRetryRandomDelay(int, TimeUnit) Minimum Request
199- * Retry Random Delay}.<br>
208+ * The Shopify SDK uses random waits in between retry attempts. Maximum
209+ * duration time to wait before retrying a failed request. Value must
210+ * also be more than
211+ * {@link #withMinimumRequestRetryRandomDelay(int, TimeUnit) Minimum
212+ * Request Retry Random Delay}.<br>
200213 * Default value is: 5 seconds.
201214 *
202215 * @param duration
@@ -569,6 +582,18 @@ public List<ShopifyOrder> getOrders(final DateTime mininumCreationDate, final Da
569582 return getOrders (mininumCreationDate , maximumCreationDate , page , DEFAULT_REQUEST_LIMIT );
570583 }
571584
585+ public List <ShopifyOrder > getUpdatedOrdersCreatedBefore (final DateTime minimumUpdatedAtDate ,
586+ final DateTime maximumUpdatedAtDate , final DateTime maximumCreatedAtDate , final int page ,
587+ final int pageSize ) {
588+ final Response response = get (getWebTarget ().path (ORDERS ).queryParam (STATUS_QUERY_PARAMETER , ANY_STATUSES )
589+ .queryParam (LIMIT_QUERY_PARAMETER , pageSize )
590+ .queryParam (UPDATED_AT_MIN_QUERY_PARAMETER , minimumUpdatedAtDate .toString ())
591+ .queryParam (UPDATED_AT_MAX_QUERY_PARAMETER , maximumUpdatedAtDate .toString ())
592+ .queryParam (CREATED_AT_MAX_QUERY_PARAMETER , maximumCreatedAtDate .toString ())
593+ .queryParam (PAGE_QUERY_PARAMETER , page ));
594+ return getOrders (response );
595+ }
596+
572597 public List <ShopifyOrder > getOrders (final DateTime mininumCreationDate , final DateTime maximumCreationDate ,
573598 final int page , final int pageSize ) {
574599 final Response response = get (getWebTarget ().path (ORDERS ).queryParam (STATUS_QUERY_PARAMETER , ANY_STATUSES )
@@ -645,6 +670,44 @@ public ShopifyCustomer updateCustomer(final ShopifyCustomerUpdateRequest shopify
645670 return shopifyCustomerRootResponse .getCustomer ();
646671 }
647672
673+ public ShopifyCustomer getCustomer (final String customerId ) {
674+ final Response response = get (getWebTarget ().path (CUSTOMERS ).path (customerId ));
675+ final ShopifyCustomerRoot shopifyCustomerRootResponse = response .readEntity (ShopifyCustomerRoot .class );
676+ return shopifyCustomerRootResponse .getCustomer ();
677+ }
678+
679+ public List <ShopifyCustomer > getCustomers (final ShopifyGetCustomersRequest shopifyGetCustomersRequest ) {
680+ WebTarget target = getWebTarget ().path (CUSTOMERS );
681+ if (shopifyGetCustomersRequest .getPage () != 0 ) {
682+ target = target .queryParam (PAGE_QUERY_PARAMETER , shopifyGetCustomersRequest .getPage ());
683+ }
684+ if (shopifyGetCustomersRequest .getLimit () != 0 ) {
685+ target = target .queryParam (LIMIT_QUERY_PARAMETER , shopifyGetCustomersRequest .getLimit ());
686+ } else {
687+ target = target .queryParam (LIMIT_QUERY_PARAMETER , DEFAULT_REQUEST_LIMIT );
688+ }
689+ if (shopifyGetCustomersRequest .getIds () != null ) {
690+ target = target .queryParam (IDS_QUERY_PARAMETER , String .join ("," , shopifyGetCustomersRequest .getIds ()));
691+ }
692+ if (shopifyGetCustomersRequest .getSinceId () != null ) {
693+ target = target .queryParam (SINCE_ID_QUERY_PARAMETER , shopifyGetCustomersRequest .getSinceId ());
694+ }
695+ if (shopifyGetCustomersRequest .getCreatedAtMin () != null ) {
696+ target = target .queryParam (CREATED_AT_MIN_QUERY_PARAMETER , shopifyGetCustomersRequest .getCreatedAtMin ());
697+ }
698+ if (shopifyGetCustomersRequest .getCreatedAtMax () != null ) {
699+ target = target .queryParam (CREATED_AT_MAX_QUERY_PARAMETER , shopifyGetCustomersRequest .getCreatedAtMax ());
700+ }
701+ final Response response = get (target );
702+ return getCustomers (response );
703+ }
704+
705+ public List <ShopifyCustomer > searchCustomers (final String query ) {
706+ final Response response = get (getWebTarget ().path (CUSTOMERS ).path (SEARCH )
707+ .queryParam (QUERY_QUERY_PARAMETER , query ).queryParam (LIMIT_QUERY_PARAMETER , DEFAULT_REQUEST_LIMIT ));
708+ return getCustomers (response );
709+ }
710+
648711 public ShopifyFulfillment cancelFulfillment (final String orderId , final String fulfillmentId ) {
649712 final Response response = post (
650713 getWebTarget ().path (ORDERS ).path (orderId ).path (FULFILLMENTS ).path (fulfillmentId ).path (CANCEL ),
@@ -759,6 +822,11 @@ public String getAccessToken() {
759822 return accessToken ;
760823 }
761824
825+ private List <ShopifyCustomer > getCustomers (final Response response ) {
826+ final ShopifyCustomersRoot shopifyCustomersRootResponse = response .readEntity (ShopifyCustomersRoot .class );
827+ return shopifyCustomersRootResponse .getCustomers ();
828+ }
829+
762830 private ShopifyRefund calculateRefund (final ShopifyRefundCreationRequest shopifyRefundCreationRequest ) {
763831 final ShopifyRefundRoot shopifyRefundRoot = new ShopifyRefundRoot ();
764832
@@ -844,7 +912,7 @@ private Response handleResponse(final Response response, final Status... expecte
844912 return response ;
845913 }
846914
847- throw new ShopifyErrorResponseException (response , shopifySdkRetryListener . getResponseBody () );
915+ throw new ShopifyErrorResponseException (response );
848916 }
849917
850918 private List <Integer > getExpectedStatusCodes (final Status ... expectedStatus ) {
@@ -861,20 +929,21 @@ private Response invokeResponseCallable(final Callable<Response> responseCallabl
861929 }
862930
863931 private Retryer <Response > buildResponseRetyer () {
864- return RetryerBuilder .<Response >newBuilder ().retryIfResult (ShopifySdk ::shouldRetryResponse ).retryIfException ()
932+ return RetryerBuilder .<Response > newBuilder ().retryIfResult (ShopifySdk ::shouldRetryResponse ).retryIfException ()
865933 .withWaitStrategy (WaitStrategies .randomWait (minimumRequestRetryRandomDelayMilliseconds ,
866934 TimeUnit .MILLISECONDS , maximumRequestRetryRandomDelayMilliseconds , TimeUnit .MILLISECONDS ))
867935 .withStopStrategy (
868936 StopStrategies .stopAfterDelay (maximumRequestRetryTimeoutMilliseconds , TimeUnit .MILLISECONDS ))
869- .withRetryListener (shopifySdkRetryListener ).build ();
937+ .withRetryListener (new ShopifySdkRetryListener () ).build ();
870938 }
871939
872940 private static boolean shouldRetryResponse (final Response response ) {
873941 return isServerError (response ) || hasExceededRateLimit (response ) || hasNotBeenSaved (response );
874942 }
875943
876944 private static boolean hasExceededRateLimit (final Response response ) {
877- return TOO_MANY_REQUESTS_STATUS_CODE == response .getStatus ();
945+ return TOO_MANY_REQUESTS_STATUS_CODE == response .getStatus ()
946+ && response .getHeaders ().containsKey (RETRY_AFTER_HEADER );
878947 }
879948
880949 private static boolean isServerError (final Response response ) {
@@ -895,7 +964,7 @@ private static boolean hasNotBeenSaved(final Response response) {
895964 private String generateToken () {
896965 try {
897966
898- final Entity <String > entity = Entity .entity ("" , MediaType .APPLICATION_JSON );
967+ final Entity <String > entity = Entity .entity (EMPTY_STRING , MediaType .APPLICATION_JSON );
899968 final Response response = this .webTarget .path (OAUTH ).path (ACCESS_TOKEN ).queryParam (CLIENT_ID , this .clientId )
900969 .queryParam (CLIENT_SECRET , this .clientSecret )
901970 .queryParam (AUTHORIZATION_CODE , this .authorizationToken ).request (MediaType .APPLICATION_JSON )
@@ -946,23 +1015,21 @@ public class ShopifySdkRetryListener implements RetryListener {
9461015 private static final String RETRY_EXCEPTION_ATTEMPT_MESSAGE = "An exception occurred while making an API call to shopify: {} on attempt number {} and {} seconds since first attempt" ;
9471016 private static final String RETRY_INVALID_RESPONSE_ATTEMPT_MESSAGE = "Waited {} seconds since first retry attempt. This is attempt {}. Please review the following failed request information.\n Request Location of {}\n Response Status Code of {}\n Response Headers of:\n {}\n Response Body of:\n {}" ;
9481017
949- private String responseBody ;
950-
9511018 @ Override
9521019 public <V > void onRetry (final Attempt <V > attempt ) {
9531020 if (attempt .hasResult ()) {
9541021 final Response response = (Response ) attempt .getResult ();
9551022
9561023 response .bufferEntity ();
957- this . responseBody = response .readEntity (String .class );
1024+ final String responseBody = response .readEntity (String .class );
9581025
9591026 if (LOGGER .isWarnEnabled () && !hasExceededRateLimit (response ) && shouldRetryResponse (response )) {
9601027
9611028 final long delaySinceFirstAttemptInSeconds = convertMillisecondsToSeconds (
9621029 attempt .getDelaySinceFirstAttempt ());
9631030 LOGGER .warn (RETRY_INVALID_RESPONSE_ATTEMPT_MESSAGE , delaySinceFirstAttemptInSeconds ,
9641031 attempt .getAttemptNumber (), response .getLocation (), response .getStatus (),
965- response .getStringHeaders (), this . responseBody );
1032+ response .getStringHeaders (), responseBody );
9661033
9671034 }
9681035
@@ -975,10 +1042,6 @@ public <V> void onRetry(final Attempt<V> attempt) {
9751042 }
9761043 }
9771044
978- public String getResponseBody () {
979- return responseBody ;
980- }
981-
9821045 private long convertMillisecondsToSeconds (final long milliiseconds ) {
9831046 return TimeUnit .SECONDS .convert (milliiseconds , TimeUnit .MILLISECONDS );
9841047 }
0 commit comments