Skip to content

Commit

Permalink
Handling external event msg (#101)
Browse files Browse the repository at this point in the history
* preventing java null pointer exception upon receiving event triggered from outside Xendit

* fix json conversion

* handle unbundled case

* update readme
  • Loading branch information
stephenthajeb authored May 3, 2023
1 parent 8774406 commit b0967fe
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 47 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

## 3.8.2 (2023-05-03)
- Bug Fix: Handle External Event for 3DS

## 3.8.1 (2023-03-17)
- Chore: Upgrade sentry-android to 6.15.0
- Chore: Update sentry dsn
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,24 @@ Maven:
<dependency>
<groupId>com.xendit</groupId>
<artifactId>xendit-android</artifactId>
<version>3.8.1</version>
<version>3.8.2</version>
<type>pom</type>
</dependency>
```

Gradle:
```
compile 'com.xendit:xendit-android:3.8.1'
compile 'com.xendit:xendit-android:3.8.2'
```

Ivy:
```
<dependency org='com.xendit' name='xendit-android' rev='3.8.1'>
<dependency org='com.xendit' name='xendit-android' rev='3.8.2'>
<artifact name='xendit-android' ext='pom' ></artifact>
</dependency>
```

For more information, visit https://central.sonatype.dev/artifact/com.xendit/xendit-android/3.8.1/versions
For more information, visit https://central.sonatype.dev/artifact/com.xendit/xendit-android/3.8.2/versions

**Note**:

Expand Down
1 change: 0 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
implementation project(':xendit-android')
// implementation 'com.xendit:xendit-android:3.2.0'

// App's dependencies, including test
implementation 'androidx.annotation:annotation:1.0.0'
Expand Down
4 changes: 2 additions & 2 deletions xendit-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.bintray'

group 'com.xendit'
version '3.8.1'
version '3.8.2'

ext {
bintrayOrg = 'xendit'
Expand Down Expand Up @@ -36,7 +36,7 @@ android {
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName '3.8.1'
versionName '3.8.2'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.xendit.Models.Authentication;
import com.xendit.Models.Token;
import com.xendit.Models.XenditError;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;


/**
* Created by Javier on 26/10/20.
Expand All @@ -37,33 +41,56 @@ public void onReceive(Context context, Intent intent) {
String message = intent.getExtras().getString(XenditActivity.MESSAGE_KEY);
if (!message.isEmpty() && message.equals(context.getString(R.string.create_token_error_validation))) {
tokenCallback.onError(new XenditError(context.getString(R.string.create_token_error_validation)));
context.unregisterReceiver(this);

} else if (message.equals(context.getString(R.string.tokenization_error))) {
tokenCallback.onError(new XenditError("TOKENIZATION_ERROR", context.getString(R.string.tokenization_error)));
context.unregisterReceiver(this);

} else {
Gson gson = new Gson();
Authentication authentication = gson.fromJson(message, Authentication.class);
if (authentication.getStatus().equals("VERIFIED")) {
tokenCallback.onSuccess(new Token(authentication));
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
tokenCallback.onError(new XenditError(errorMessage));
} catch (JSONException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.tokenization_error)));
if (is3DSResultEventFromXendit(message)){
Gson gson = new Gson();
Authentication authentication = gson.fromJson(message, Authentication.class);
if (authentication.getStatus().equals("VERIFIED")) {
tokenCallback.onSuccess(new Token(authentication));
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
tokenCallback.onError(new XenditError(errorMessage));
} catch (JSONException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.tokenization_error)));
}
}
context.unregisterReceiver(this);

} else {
// NOTE: To handle case where event is triggered from external parties other than Xendit.
// Event payload here is not nullish but it is unknown format.
// Do not unregister broadcast receiver here.
}
}
} catch (NullPointerException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", e.getMessage()));
context.unregisterReceiver(this);

} catch (JsonSyntaxException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", "Error parsing response from 3DS. Please try again."));
context.unregisterReceiver(this);

}

context.unregisterReceiver(this);
}

private boolean is3DSResultEventFromXendit(String messageInString){
Map<String, Object> messageInJson = new Gson().fromJson(
messageInString, new TypeToken<HashMap<String, Object>>() {}.getType()
);

// A valid 3ds callback payload from Xendit, should contain required fields: id and status.
return messageInJson.get("id") != null && messageInJson.get("status") != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.xendit.Models.Authentication;
import com.xendit.Models.XenditError;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;


/**
* Created by gonzalez on 7/26/17.
Expand All @@ -32,34 +36,55 @@ public void onReceive(Context context, Intent intent) {
String message = intent.getExtras().getString(XenditActivity.MESSAGE_KEY);
if (!message.isEmpty() && message.equals(context.getString(R.string.create_token_error_validation))) {
authenticationCallback.onError(new XenditError(context.getString(R.string.create_token_error_validation)));
context.unregisterReceiver(this);

} else if (message.equals(context.getString(R.string.tokenization_error))) {
authenticationCallback.onError(new XenditError("AUTHENTICATION_ERROR", context.getString(R.string.tokenization_error)));
context.unregisterReceiver(this);

} else {
Gson gson = new Gson();
Authentication authentication = gson.fromJson(message, Authentication.class);
if (authentication.getStatus().equals("VERIFIED")) {
authenticationCallback.onSuccess(authentication);
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
authenticationCallback.onError(new XenditError(errorMessage, authentication));
} catch (JSONException e) {
e.printStackTrace();
authenticationCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.authentication_error)));
if (is3DSResultEventFromXendit(message)) {
Gson gson = new Gson();
Authentication authentication = gson.fromJson(message, Authentication.class);
if (authentication.getStatus().equals("VERIFIED")) {
authenticationCallback.onSuccess(authentication);
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
authenticationCallback.onError(new XenditError(errorMessage, authentication));
} catch (JSONException e) {
e.printStackTrace();
authenticationCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.authentication_error)));
}
}
context.unregisterReceiver(this);

} else {
// NOTE: To handle case where event is triggered from external parties other than Xendit.
// Event payload here is not nullish but it is unknown format.
// Do not unregister broadcast receiver here.
}
}
} catch (NullPointerException e) {
e.printStackTrace();
authenticationCallback.onError(new XenditError("SERVER_ERROR", e.getMessage()));
context.unregisterReceiver(this);

} catch (JsonSyntaxException e) {
e.printStackTrace();
authenticationCallback.onError(new XenditError("SERVER_ERROR", "Error parsing response from 3DS. Please try again."));
context.unregisterReceiver(this);

}
}

private boolean is3DSResultEventFromXendit(String messageInString){
Map<String, Object> messageInJson = new Gson().fromJson(
messageInString, new TypeToken<HashMap<String, Object>>() {}.getType()
);

context.unregisterReceiver(this);
// A valid 3ds callback payload from Xendit, should contain required fields: id and status.
return messageInJson.get("id") != null && messageInJson.get("status") != null;
}
}
54 changes: 40 additions & 14 deletions xendit-android/src/main/java/com/xendit/TokenBroadcastReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.xendit.Models.AuthenticatedToken;
import com.google.gson.reflect.TypeToken;
import com.xendit.Models.Authentication;
import com.xendit.Models.Token;
import com.xendit.Models.XenditError;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;


/**
* Created by Sergey on 3/30/17.
Expand All @@ -33,33 +37,55 @@ public void onReceive(Context context, Intent intent) {
String message = intent.getExtras().getString(XenditActivity.MESSAGE_KEY);
if (!message.isEmpty() && message.equals(context.getString(R.string.create_token_error_validation))) {
tokenCallback.onError(new XenditError(context.getString(R.string.create_token_error_validation)));
context.unregisterReceiver(this);

} else if (message.equals(context.getString(R.string.tokenization_error))) {
tokenCallback.onError(new XenditError("TOKENIZATION_ERROR", context.getString(R.string.tokenization_error)));
context.unregisterReceiver(this);

} else {
Gson gson = new Gson();
AuthenticatedToken authentication = gson.fromJson(message, AuthenticatedToken.class);
if (authentication.getStatus().equals("VERIFIED")) {
tokenCallback.onSuccess(new Token(authentication));
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
tokenCallback.onError(new XenditError(errorMessage));
} catch (JSONException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.tokenization_error)));
if (is3DSResultEventFromXendit(message)){
Gson gson = new Gson();
Authentication authentication = gson.fromJson(message, Authentication.class);
if (authentication.getStatus().equals("VERIFIED")) {
tokenCallback.onSuccess(new Token(authentication));
} else {
try {
JSONObject errorJson = new JSONObject(message);
String errorMessage = errorJson.getString("failure_reason");
tokenCallback.onError(new XenditError(errorMessage));
} catch (JSONException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", context.getString(R.string.tokenization_error)));
}
}
context.unregisterReceiver(this);

} else {
// NOTE: To handle case where event is triggered from external parties other than Xendit.
// Event payload here is not nullish but it is unknown format.
// Do not unregister broadcast receiver here.
}
}
} catch (NullPointerException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", e.getMessage()));
context.unregisterReceiver(this);

} catch (JsonSyntaxException e) {
e.printStackTrace();
tokenCallback.onError(new XenditError("SERVER_ERROR", "Error parsing response from 3DS. Please try again."));
context.unregisterReceiver(this);

}
}

private boolean is3DSResultEventFromXendit(String messageInString){
Map<String, Object> messageInJson = new Gson().fromJson(
messageInString, new TypeToken<HashMap<String, Object>>() {}.getType()
);

context.unregisterReceiver(this);
// A valid 3ds callback payload from Xendit, should contain required fields: id and status.
return messageInJson.get("id") != null && messageInJson.get("status") != null;
}
}

0 comments on commit b0967fe

Please sign in to comment.