Skip to content

Commit

Permalink
Merge pull request #38 from skyflowapi/release/12.04.2022
Browse files Browse the repository at this point in the history
Release/12.04.2022
  • Loading branch information
prathyusha-skyflow authored Apr 12, 2022
2 parents 172f7c5 + c6b1b1f commit e517dcf
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

## [1.5.0] - 2022-04-12

### Added
- support for application/x-www-form-urlencoded and multipart/form-data content-type's in connections.

## [1.4.1] - 2022-03-29

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This Java SDK is designed to help developers easily implement Skyflow into their

Add this dependency to your project's build file:
```
implementation 'com.skyflow:skyflow-java:1.4.1'
implementation 'com.skyflow:skyflow-java:1.5.0'
```

#### Maven users
Expand All @@ -47,7 +47,7 @@ Add this dependency to your project's POM:
<dependency>
<groupId>com.skyflow</groupId>
<artifactId>skyflow-java</artifactId>
<version>1.4.1</version>
<version>1.5.0</version>
</dependency>
```
---
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.skyflow</groupId>
<artifactId>skyflow-java</artifactId>
<version>1.4.1</version>
<version>1.5.0</version>
<packaging>jar</packaging>

<name>${project.groupId}:${project.artifactId}</name>
Expand Down
60 changes: 56 additions & 4 deletions src/main/java/com/skyflow/common/utils/Helpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
import com.skyflow.entities.InsertRecordInput;
import com.skyflow.errors.ErrorCode;
import com.skyflow.errors.SkyflowException;
import com.skyflow.logs.DebugLogs;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;


public final class Helpers {

private static final String LINE_FEED = "\r\n";
public static JSONObject constructInsertRequest(InsertInput recordsInput, InsertOptions options) throws SkyflowException {
JSONObject finalRequest = new JSONObject();
List<JSONObject> requestBodyContent = new ArrayList<JSONObject>();
Expand Down Expand Up @@ -161,4 +161,56 @@ public static String appendRequestIdToErrorObj(int status, String error, String
return error;
}

public static String formatJsonToFormEncodedString(JSONObject requestBody){
LogUtil.printDebugLog(DebugLogs.FormatRequestBodyFormUrlFormEncoded.getLog());
StringBuilder formEncodeString = new StringBuilder();
HashMap<String,String> jsonMap = convertJsonToMap(requestBody,"");

for (Map.Entry<String,String> currentEntry : jsonMap.entrySet())
formEncodeString.append(makeFormEncodeKeyValuePair(currentEntry.getKey(),currentEntry.getValue()));

return formEncodeString.substring(0,formEncodeString.length()-1);
}

public static String formatJsonToMultiPartFormDataString(JSONObject requestBody,String boundary){
LogUtil.printDebugLog(DebugLogs.FormatRequestBodyFormData.getLog());
StringBuilder formEncodeString = new StringBuilder();
HashMap<String,String> jsonMap = convertJsonToMap(requestBody,"");

for (Map.Entry<String,String> currentEntry : jsonMap.entrySet())
formEncodeString.append(makeFormDataKeyValuePair(currentEntry.getKey(),currentEntry.getValue(),boundary));

formEncodeString.append(LINE_FEED);
formEncodeString.append("--").append(boundary).append("--").append(LINE_FEED);

return formEncodeString.toString();
}

private static HashMap<String,String> convertJsonToMap(JSONObject json,String rootKey){
HashMap<String,String> currentMap = new HashMap<>();
for (Object key : json.keySet()) {
Object currentValue = json.get(key);
String currentKey = rootKey.length() != 0 ? rootKey + '[' + key.toString() + ']' : rootKey + key.toString();
if(currentValue instanceof JSONObject){
currentMap.putAll(convertJsonToMap((JSONObject) currentValue, currentKey));
}else {
currentMap.put(currentKey,currentValue.toString());
}
}
return currentMap;
}

private static String makeFormEncodeKeyValuePair(String key, String value){
return key+"="+value+"&";
}

private static String makeFormDataKeyValuePair(String key,String value,String boundary){
StringBuilder formDataTextField = new StringBuilder();
formDataTextField.append("--").append(boundary).append(LINE_FEED);
formDataTextField.append("Content-Disposition: form-data; name=\"").append(key).append("\"").append(LINE_FEED);
formDataTextField.append(LINE_FEED);
formDataTextField.append(value).append(LINE_FEED);

return formDataTextField.toString();
}
}
26 changes: 23 additions & 3 deletions src/main/java/com/skyflow/common/utils/HttpUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,48 @@
import java.nio.charset.StandardCharsets;
import java.util.Map;

import static com.skyflow.common.utils.Helpers.formatJsonToFormEncodedString;
import static com.skyflow.common.utils.Helpers.formatJsonToMultiPartFormDataString;

public final class HttpUtility {

public static String sendRequest(String method, String requestUrl, JSONObject params, Map<String, String> headers) throws IOException, SkyflowException {
HttpURLConnection connection = null;
BufferedReader in = null;
StringBuffer response = null;
String boundary = String.valueOf(System.currentTimeMillis());
try {
URL url = new URL(requestUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(method);
connection.setRequestProperty("content-type", "application/json");
connection.setRequestProperty("Accept", "*/*");

if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
for (Map.Entry<String, String> entry : headers.entrySet())
connection.setRequestProperty(entry.getKey(), entry.getValue());

// append dynamic boundary if content-type is multipart/form-data
if (headers.containsKey("content-type")) {
if (headers.get("content-type") == "multipart/form-data") {
connection.setRequestProperty("content-type", "multipart/form-data; boundary=" + boundary);
}
}
}

if (params != null && params.size() > 0) {
connection.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
byte[] input = params.toString().getBytes(StandardCharsets.UTF_8);
byte[] input = null;
String requestContentType = connection.getRequestProperty("content-type");

if (requestContentType.contains("application/x-www-form-urlencoded")) {
input = formatJsonToFormEncodedString(params).getBytes(StandardCharsets.UTF_8);
} else if (requestContentType.contains("multipart/form-data")) {
input = formatJsonToMultiPartFormDataString(params, boundary).getBytes(StandardCharsets.UTF_8);
}else {
input = params.toString().getBytes(StandardCharsets.UTF_8);
}

wr.write(input, 0, input.length);
wr.flush();
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/skyflow/logs/DebugLogs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.skyflow.logs;

public enum DebugLogs {

FormatRequestBodyFormUrlFormEncoded("Formatting request body for form-urlencoded content-type"),
FormatRequestBodyFormData("Formatting request body for form-data content-type");
private final String log;

DebugLogs(String log) {
this.log = log;
}

public String getLog() {
return log;
}
}
38 changes: 38 additions & 0 deletions src/test/java/com/skyflow/common/utils/HelpersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.skyflow.common.utils;

import org.json.simple.JSONObject;
import org.junit.Test;

public class HelpersTest {

@Test
public void testFormatJsonToFormEncodedString(){
JSONObject testJson = new JSONObject();
testJson.put("key1","value1");
JSONObject nestedObj = new JSONObject();
nestedObj.put("key2","value2");
testJson.put("nest",nestedObj);

String testResponse = Helpers.formatJsonToFormEncodedString(testJson);
System.out.println(testResponse);
assert testResponse.contains("key1=value1");
assert testResponse.contains("nest[key2]=value2");
}

@Test
public void testFormatJsonToMultiPartFormDataString(){
JSONObject testJson = new JSONObject();
testJson.put("key1","value1");
JSONObject nestedObj = new JSONObject();
nestedObj.put("key2","value2");
testJson.put("nest",nestedObj);
String testBoundary = "123";
String testResponse = Helpers.formatJsonToMultiPartFormDataString(testJson,testBoundary);
assert testResponse.contains("--"+testBoundary);
assert testResponse.contains("--"+testBoundary+"--");
assert testResponse.contains("Content-Disposition: form-data; name=\"key1\"");
assert testResponse.contains("value1");
assert testResponse.contains("Content-Disposition: form-data; name=\"nest[key2]\"");
assert testResponse.contains("value2");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class TokenTest {
@Test
public void testInvalidFilePath() {
try {
Token.generateBearerToken("");
Token.GenerateToken("");
} catch (SkyflowException exception) {
assertEquals(exception.getMessage(), ErrorCode.EmptyFilePath.getDescription());
}
Expand Down
78 changes: 78 additions & 0 deletions src/test/java/com/skyflow/vault/InvokeConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.IOException;

import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;


Expand All @@ -34,6 +35,7 @@ public String getBearerToken() throws Exception {
@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "com.skyflow.common.utils.TokenUtils")
public class InvokeConnectionTest {
private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception";
private JSONObject testConfig;
private static Skyflow skyflowClient;

Expand Down Expand Up @@ -84,8 +86,10 @@ public void testInvokeConnectionValidInput() {
Assert.assertEquals(gatewayResponse.toJSONString(), mockResponse);
} catch (SkyflowException exception) {
Assert.assertNull(exception);
fail(INVALID_EXCEPTION_THROWN);
} catch (IOException exception) {
exception.printStackTrace();
fail(INVALID_EXCEPTION_THROWN);
}


Expand Down Expand Up @@ -158,4 +162,78 @@ public void testInvokeConnectionInvalidMethodName() {
}
}

@Test
@PrepareForTest(fullyQualifiedNames = {"com.skyflow.common.utils.HttpUtility", "com.skyflow.common.utils.TokenUtils"})
public void testInvokeConnectionWithFormEncoded() {
JSONObject testConfig = new JSONObject();
testConfig.put("connectionURL", "https://testgatewayurl.com/");
testConfig.put("methodName", RequestMethod.POST);

JSONObject requestHeadersJson = new JSONObject();
requestHeadersJson.put("content-type", "application/x-www-form-urlencoded");
testConfig.put("requestHeader", requestHeadersJson);

JSONObject testJson = new JSONObject();
testJson.put("key1","value1");
JSONObject nestedObj = new JSONObject();
nestedObj.put("key2","value2");
testJson.put("nest",nestedObj);

testConfig.put("requestBody", testJson);

try {
PowerMockito.mockStatic(HttpUtility.class);
String mockResponse = "{\"id\":\"12345\"}";
PowerMockito.when(HttpUtility.sendRequest(anyString(), anyString(), ArgumentMatchers.<JSONObject>any(), ArgumentMatchers.<String, String>anyMap())).thenReturn(mockResponse);
JSONObject gatewayResponse = skyflowClient.invokeConnection(testConfig);

Assert.assertNotNull(gatewayResponse);
Assert.assertEquals(gatewayResponse.toJSONString(), mockResponse);
} catch (SkyflowException exception) {
Assert.assertNull(exception);
fail(INVALID_EXCEPTION_THROWN);
} catch (IOException exception) {
exception.printStackTrace();
fail(INVALID_EXCEPTION_THROWN);
}

}

@Test
@PrepareForTest(fullyQualifiedNames = {"com.skyflow.common.utils.HttpUtility", "com.skyflow.common.utils.TokenUtils"})
public void testInvokeConnectionWithMultipartFormData() {
JSONObject testConfig = new JSONObject();
testConfig.put("connectionURL", "https://testgatewayurl.com/");
testConfig.put("methodName", RequestMethod.POST);

JSONObject requestHeadersJson = new JSONObject();
requestHeadersJson.put("content-type", "multipart/form-data");
testConfig.put("requestHeader", requestHeadersJson);

JSONObject testJson = new JSONObject();
testJson.put("key1","value1");
JSONObject nestedObj = new JSONObject();
nestedObj.put("key2","value2");
testJson.put("nest",nestedObj);

testConfig.put("requestBody", testJson);

try {
PowerMockito.mockStatic(HttpUtility.class);
String mockResponse = "{\"id\":\"12345\"}";
PowerMockito.when(HttpUtility.sendRequest(anyString(), anyString(), ArgumentMatchers.<JSONObject>any(), ArgumentMatchers.<String, String>anyMap())).thenReturn(mockResponse);
JSONObject gatewayResponse = skyflowClient.invokeConnection(testConfig);

Assert.assertNotNull(gatewayResponse);
Assert.assertEquals(gatewayResponse.toJSONString(), mockResponse);
} catch (SkyflowException exception) {
Assert.assertNull(exception);
fail(INVALID_EXCEPTION_THROWN);
} catch (IOException exception) {
exception.printStackTrace();
fail(INVALID_EXCEPTION_THROWN);
}

}

}

0 comments on commit e517dcf

Please sign in to comment.