Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
### v3.35.0 (2025-07-18)
* * *

### New Resources:
* BillingConfiguration has been added.
* Brand has been added.

### New Attributes:
* has_children has been added to Hierarchy
* coupon_applicability_mappings has been added to QuotedRamp.

### New Endpoint:
* listHierarchyDetail has been added to Customer.

### New Input parameters:
* change_reason children has been added to Entitlement#CreateRequest.
* entitlements[apply_grandfathering] has been added to Entitlement#CreateRequest.
* replace_primary_payment_source has been added to Purchase#CreateRequest.
* omnichannel_subscription has been added to RecordedPurchase#CreateRequest.
* contract_term has been added to Subscription#RemoveScheduledCancellationRequest.
* contract_term_billing_cycle_on_renewal has been added to Subscription#RemoveScheduledCancellationRequest.

### New Enums:
* payconiq_by_bancontact has been added to PaymentMethodType.
* solidgate has been added to Gateway.
* solidgate has been added to PaymentMethod.

### v3.34.0 (2025-06-23)
* * *

Expand Down
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,64 @@ public class Sample {
```
`isIdempotencyReplayed()` method can be accessed to differentiate between original and replayed requests.


### Retry HandlingAdd commentMore actions

Chargebee's SDK includes built-in retry logic to handle temporary network issues and server-side errors. This feature is **disabled by default** but can be **enabled when needed**.

#### Key features include:

- **Automatic retries for specific HTTP status codes**: Retries are automatically triggered for status codes `500`, `502`, `503`, and `504`.
- **Exponential backoff**: Retry delays increase exponentially to prevent overwhelming the server.
- **Rate limit management**: If a `429 Too Many Requests` response is received with a `Retry-After` header, the SDK waits for the specified duration before retrying.
> *Note: Exponential backoff and max retries do not apply in this case.*
- **Customizable retry behavior**: Retry logic can be configured using the `retryConfig` parameter in the environment configuration.

#### Example: Customizing Retry Logic

You can enable and configure the retry logic by passing a `retryConfig` object when initializing the Chargebee environment:

```java
import com.chargebee.Environment;
public class Sample {
public static void main(String[] args) throws Exception {
Environment.configure("{site}", "{site_api_key}");
Environment.defaultConfig().updateRetryConfig(
new com.chargebee.internal.RetryConfig(
true,
3,
500,
new java.util.HashSet<>(java.util.Arrays.asList(500))
)
);
// ... your Chargebee API operations ...
}
}

```

#### Example: Rate Limit retry logic

You can enable and configure the retry logic for rate-limit by passing a `retryConfig` object when initializing the Chargebee environment:

```java
import com.chargebee.Environment;
public class Sample {
public static void main(String[] args) throws Exception {
Environment.configure("{site}", "{site_api_key}");
Environment.defaultConfig().updateRetryConfig(
new com.chargebee.internal.RetryConfig(
true,
3,
500,
new java.util.HashSet<>(java.util.Arrays.asList(429))
)
);
// ... your Chargebee API operations ...
}
}
```

## Contribution
***
You may contribute patches to any of the **Active** versions of this library. To do so, raise a PR against the [respective branch](#library-versions).
Expand Down
26 changes: 19 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.chargebee</groupId>
<artifactId>chargebee-java</artifactId>
<version>3.34.1-SNAPSHOT</version>
<version>3.35.0</version>


<packaging>jar</packaging>
Expand All @@ -14,6 +14,14 @@

<url>https://github.com/chargebee/chargebee-java</url>

<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>

<organization>
<name>ChargeBee</name>
<url>http://www.chargebee.com</url>
Expand Down Expand Up @@ -80,12 +88,6 @@
</dependency>
</dependencies>

<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>9</version>
</parent>

<build>
<resources>
<resource>
Expand All @@ -96,6 +98,16 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.8.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>false</autoPublish>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/chargebee/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class Environment {

public static final String API_VERSION = "v2";

public static final String LIBRARY_VERSION = "3.34.0";
public static final String LIBRARY_VERSION = "3.35.0";

private final String apiBaseUrl;

Expand Down
28 changes: 20 additions & 8 deletions src/main/java/com/chargebee/internal/HttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static Result get(String url, Params params, Map<String,String> headers,
url = url + '?' + toQueryStr(params); // fixme: what about url size restrictions ??
}
HttpURLConnection conn = createConnection(url, Method.GET, headers, env);
Resp resp = sendRequestWithRetry(conn, env);
Resp resp = sendRequestWithRetry(conn, env, false);
return resp.toResult();
}

Expand All @@ -54,16 +54,22 @@ public static ListResult getList(String url, Params params, Map<String,String> h
url = url + '?' + toQueryStr(params, true); // fixme: what about url size restrictions ??
}
HttpURLConnection conn = createConnection(url, Method.GET, headers, env);
Resp resp = sendRequestWithRetry(conn, env);
Resp resp = sendRequestWithRetry(conn, env, false);
return resp.toListResult();
}
public static Result post(String url, Params params, Map<String,String> headers, Environment env, boolean isIdempotent) throws IOException {
return doFormSubmit(url, Method.POST, toQueryStr(params), headers, env, isIdempotent);
}

public static Result post(String url, Params params, Map<String,String> headers, Environment env) throws IOException {
return doFormSubmit(url, Method.POST, toQueryStr(params), headers, env);
return doFormSubmit(url, Method.POST, toQueryStr(params), headers, env, false);
}

public static Result post(String url, String content, Map<String,String> headers, Environment env) throws IOException {
return doFormSubmit(url, Method.POST, content, headers, env);
return doFormSubmit(url, Method.POST, content, headers, env, false);
}

public static Result post(String url, String content, Map<String,String> headers, Environment env, boolean isIdempotent) throws IOException {
return doFormSubmit(url, Method.POST, content, headers, env, isIdempotent);
}


Expand Down Expand Up @@ -100,10 +106,10 @@ private static String enc(String val) {
}
}

private static Result doFormSubmit(String url, Method m, String queryStr, Map<String,String> headers, Environment env) throws IOException {
private static Result doFormSubmit(String url, Method m, String queryStr, Map<String,String> headers, Environment env, boolean isIdempotent) throws IOException {
HttpURLConnection conn = createConnection(url, m, headers, env);
writeContent(conn, queryStr);
Resp resp = sendRequestWithRetry(conn, env);
Resp resp = sendRequestWithRetry(conn, env,isIdempotent);
return resp.toResult();
}

Expand All @@ -129,11 +135,17 @@ static HttpURLConnection createConnection(String url, Method m, Map<String, Stri
return conn;
}

private static Resp sendRequestWithRetry(HttpURLConnection conn, Environment env) throws IOException {
private static Resp sendRequestWithRetry(HttpURLConnection conn, Environment env, boolean isIdempotent) throws IOException {
int attempt = 0;
int lastRetryAfterDelay = 0;
while (true) {
try {
if (attempt > 0) {
conn.setRequestProperty("X-CB-Retry-Attempt", String.valueOf(attempt));
if (isIdempotent && conn.getRequestProperty("X-CB-Idempotency-Key") == null) {
conn.setRequestProperty("X-CB-Idempotency-Key", UUID.randomUUID().toString());
}
}
return sendRequest(conn);
} catch (Exception e) {
int statusCode = extractStatusCode(e);
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/com/chargebee/internal/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public Request(Method httpMethod, String uri, String pathParam, String subDomain
this.isJsonRequest = isContentTypeJson;
}

public U setIdempotency(boolean isIdempotent) {
this.isIdempotent = isIdempotent;
return (U) this;
}

public U param(String paramName, Object value){
params.add(paramName, value);
return (U)this;
Expand All @@ -43,6 +48,7 @@ public Result request() throws Exception {
return request(Environment.defaultConfig());
}


public Result request(Environment env) throws Exception {
RequestWrap c = new RequestWrap<Request>(env, this) {

Expand Down Expand Up @@ -70,12 +76,12 @@ private static Result _request(Environment env, Request<?> req) throws IOExcepti
return HttpUtil.get(url, req.params(), req.headers, env);
case POST:
if(req instanceof BatchRequest) {
return HttpUtil.post(url, ((BatchRequest<?>) req).buildRequest(), req.headers, env);
return HttpUtil.post(url, ((BatchRequest<?>) req).buildRequest(), req.headers, env, req.isIdempotent);
} else if(req.isJsonRequest){
req.headers.put(HttpUtil.CONTENT_TYPE_HEADER_NAME, "application/json;charset=" + Environment.CHARSET);
return HttpUtil.post(url, req.params.toString(), req.headers, env);
return HttpUtil.post(url, req.params.toString(), req.headers, env, req.isIdempotent);
}else {
return HttpUtil.post(url, req.params(), req.headers, env);
return HttpUtil.post(url, req.params(), req.headers, env, req.isIdempotent);
}
default:
throw new RuntimeException("Not handled type [" + req.httpMeth + "]");
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/chargebee/internal/RequestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class RequestBase<U extends RequestBase> {
protected Map<String,String> headers = new HashMap();
protected String subDomain;
protected boolean isJsonRequest;
protected boolean isIdempotent;

public U setIdempotencyKey(String idempotencyKey){
headers.put(IDEMPOTENCY_HEADER, idempotencyKey);
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/com/chargebee/internal/ResultBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public QuotedRamp quotedRamp() {
return (QuotedRamp)get("quoted_ramp");
}

public BillingConfiguration billingConfiguration() {
return (BillingConfiguration)get("billing_configuration");
}

public QuoteLineGroup quoteLineGroup() {
return (QuoteLineGroup)get("quote_line_group");
}
Expand Down Expand Up @@ -340,6 +344,10 @@ public UsageFile usageFile() {
return (UsageFile)get("usage_file");
}

public Brand brand() {
return (Brand)get("brand");
}

public List<AdvanceInvoiceSchedule> advanceInvoiceSchedules() {
return (List<AdvanceInvoiceSchedule>) getList("advance_invoice_schedules", "advance_invoice_schedule");
}
Expand Down Expand Up @@ -376,10 +384,6 @@ public List<InAppSubscription> inAppSubscriptions() {
return (List<InAppSubscription>) getList("in_app_subscriptions", "in_app_subscription");
}

public List<DifferentialPrice> differentialPrices() {
return (List<DifferentialPrice>) getList("differential_prices", "differential_price");
}


private List<? extends Resource> getList(String pluralName, String singularName) {
JSONArray listModels = jsonObj.optJSONArray(pluralName);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/chargebee/internal/RetryConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ public boolean shouldRetry(int statusCode, int retryCount) {
}

public static RetryConfig defaultConfig() {
return new RetryConfig(false, 3, 500, new HashSet<>(Arrays.asList(500)));
return new RetryConfig(false, 3, 500, new HashSet<>(Arrays.asList(500, 502, 503, 504)));
}
}
57 changes: 57 additions & 0 deletions src/main/java/com/chargebee/models/BillingConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.chargebee.models;

import com.chargebee.*;
import com.chargebee.internal.*;
import com.chargebee.filters.*;
import com.chargebee.filters.enums.SortOrder;
import com.chargebee.internal.HttpUtil.Method;
import com.chargebee.models.enums.*;
import org.json.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.*;

public class BillingConfiguration extends Resource<BillingConfiguration> {

public static class BillingDate extends Resource<BillingDate> {
public BillingDate(JSONObject jsonObj) {
super(jsonObj);
}

public Timestamp startDate() {
return optTimestamp("start_date");
}

public Timestamp endDate() {
return optTimestamp("end_date");
}

}

//Constructors
//============

public BillingConfiguration(String jsonStr) {
super(jsonStr);
}

public BillingConfiguration(JSONObject jsonObj) {
super(jsonObj);
}

// Fields
//=======

public Boolean isCalendarBillingEnabled() {
return reqBoolean("is_calendar_billing_enabled");
}

public List<BillingConfiguration.BillingDate> billingDates() {
return optList("billing_dates", BillingConfiguration.BillingDate.class);
}

// Operations
//===========


}
Loading
Loading