Skip to content
Closed
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
13 changes: 10 additions & 3 deletions src/main/java/com/sendgrid/SendGrid.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.sendgrid;

import com.sendgrid.typechecker.TypeCheckException;
import com.sendgrid.typechecker.TypeChecker;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Class SendGrid allows for quick and easy access to the SendGrid API.
Expand Down Expand Up @@ -41,6 +44,8 @@ public class SendGrid implements SendGridAPI {
/** The number of milliseconds to sleep between retries. */
private int rateLimitSleep;

private TypeChecker typeChecker = new TypeChecker();

/**
* Construct a new SendGrid API wrapper.
* @param apiKey is your SendGrid API Key: https://app.sendgrid.com/settings/api_keys
Expand Down Expand Up @@ -209,7 +214,9 @@ public Response makeCall(Request request) throws IOException {
* @return the response object.
* @throws IOException in case of a network error.
*/
public Response api(Request request) throws IOException {
public Response api(Request request) throws IOException, TypeCheckException {
typeChecker.checkRequest(request);

Request req = new Request();
req.setMethod(request.getMethod());
req.setBaseUri(this.host);
Expand Down Expand Up @@ -260,7 +267,7 @@ public void run() {
for (int i = 0; i < rateLimitRetry; ++i) {
try {
response = api(request);
} catch (IOException ex) {
} catch (IOException | TypeCheckException ex) {
// Stop retrying if there is a network error.
callback.error(ex);
return;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/sendgrid/SendGridAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,5 @@ public interface SendGridAPI {
* @return returns a response.
* @throws IOException in case of network or marshal error.
*/
public Response api(Request request) throws IOException;
public Response api(Request request) throws Exception;
}
81 changes: 81 additions & 0 deletions src/main/java/com/sendgrid/typechecker/MailFieldIds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.sendgrid.typechecker;

public class MailFieldIds {

public static final String PERSONALIZATIONS = "personalizations";

public static final String TO = "to";
public static final String CC = "cc";
public static final String BCC = "bcc";

public static final String FROM = "from";
public static final String REPLY_TO = "reply_to";
public static final String EMAIL = "email";
public static final String NAME = "name";

public static final String SUBJECT = "subject";
public static final String HEADERS = "headers";
public static final String SUBSTITUTIONS = "substitutions";

public static final String CUSTOM_ARGS = "custom_args";
public static final String SEND_AT = "send_at";


public static final String CONTENT = "content";
public static final String TYPE = "type";
public static final String VALUE = "value";

public static final String ATTACHMENTS = "attachments";

public static final String FILENAME = "filename";
public static final String DISPOSITION = "disposition";
public static final String CONTENT_ID = "content_id";

public static final String TEMPLATE_ID = "template_id";

public static final String SECTIONS = "sections";

public static final String CATEGORIES = "categories";

public static final String BATCH_ID = "batch_id";
public static final String ASM = "asm";

public static final String GROUP_ID = "group_id";
public static final String GROUPS_TO_DISPLAY = "groups_to_display";

public static final String IP_POOL_NAME = "ip_pool_name";


public static final String MAIL_SETTINGS = "mail_settings";
public static final String ENABLE = "enable";

public static final String BYPASS_LIST_MANAGEMENT = "bypass_list_management";
public static final String FOOTER = "footer";
public static final String TEXT = "text";
public static final String HTML = "html";

public static final String SANDBOX_MODE = "sandbox_mode";
public static final String SPAM_CHECK = "spam_check";
public static final String THRESHOLD = "threshold";
public static final String POST_TO_URL = "post_to_url";

public static final String TRACKING_SETTINGS = "tracking_settings";
public static final String CLICK_TRACKING = "click_tracking";

public static final String ENABLE_TEXT = "enable_text";
public static final String OPEN_TRACKING = "open_tracking";
public static final String SUBSTITUTION_TAG = "substitution_tag";

public static final String SUBSCRIPTION_TRACKING = "subscription_tracking";
public static final String GANALYTICS = "ganalytics";
public static final String UTM_SOURCE = "utm_source";
public static final String UTM_MEDIUM = "utm_medium";

public static final String UTM_TERM = "utm_term";
public static final String UTM_CONTENT = "utm_content";
public static final String UTM_CAMPAIGN = "utm_campaign";


private MailFieldIds() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sendgrid.typechecker;

class RequiredFieldMissingException extends TypeCheckException {
RequiredFieldMissingException(String msg) {
super(msg);
}
}
216 changes: 216 additions & 0 deletions src/main/java/com/sendgrid/typechecker/TypeAsserts.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package com.sendgrid.typechecker;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class TypeAsserts {

/**
* Call this method to check object not null.
* @param fieldId id to be shown in exception log
* @param value object to be checked
* @throws RequiredFieldMissingException thrown if object is null
*/
public static void assertNotNull(String fieldId, Object value)
throws RequiredFieldMissingException {
if (value == null) {
throw new RequiredFieldMissingException("Field: " + fieldId + " must not be null");
}
}

/**
* Call this method to check JsonNode is of type JsonNode.STRING.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if JsonNode is not of type JsonNode.STRING
*/
public static void assertString(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
if (isRequired) {
assertNotNull(fieldId, value);
}
if (value != null && value.getNodeType() != JsonNodeType.STRING) {
throw new TypeCheckException("Field: " + fieldId + " must be of type String");
}
}

/**
* Call this method to check JsonNode is of type JsonNode.NUMBER.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if JsonNode is not of type JsonNode.NUMBER
*/
public static void assertInteger(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
if (isRequired) {
assertNotNull(fieldId, value);
}

if (value != null && value.getNodeType() != JsonNodeType.NUMBER) {
throw new TypeCheckException("Field: " + fieldId + " must be of type Integer");
}
}

/**
* Call this method to check JsonNode is of type JsonNode.BOOLEAN.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if JsonNode is not of type JsonNode.BOOLEAN
*/
public static void assertBoolean(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
if (isRequired) {
assertNotNull(fieldId, value);
}
if (value != null && value.getNodeType() != JsonNodeType.BOOLEAN) {
throw new TypeCheckException("Field: " + fieldId + " must be of type Boolean");
}
}

/**
* Call this method to check JsonNode is of type JsonNode.OBJECT.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if JsonNode is not of type JsonNode.OBJECT
*/
public static void assertObject(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
if (isRequired) {
assertNotNull(fieldId, value);
}
if (value != null && value.getNodeType() != JsonNodeType.OBJECT) {
throw new TypeCheckException("Field: " + fieldId + " must be Object");
}
}

/**
* Call this method to check JsonNode is of type JsonNode.ARRAY.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if JsonNode is not of type JsonNode.ARRAY
*/
public static void assertObjectArray(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
if (isRequired) {
assertNotNull(fieldId, value);
}
if (value != null && value.getNodeType() != JsonNodeType.ARRAY) {
throw new TypeCheckException("Field: " + fieldId + " must be of type Array");
}
}

/**
* Call this method to check json array items are of type JsonNode.NUMBER.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if json array items are not of type JsonNode.NUMBER
*/
public static void assertIntArray(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
assertObjectArray(fieldId, isRequired, value);

List<JsonNode> notIntNodes = StreamSupport.stream(value.spliterator(), false)
.filter(new Predicate<JsonNode>() {
@Override
public boolean test(JsonNode el) {
return el.getNodeType() != JsonNodeType.NUMBER;
}
})
.collect(Collectors.<JsonNode>toList());

if (!notIntNodes.isEmpty()) {
throw new TypeCheckException("Field: " + fieldId + " contents must be of type Integer");
}
}

/**
* Call this method to check json array items are of type JsonNode.STRING.
* @param fieldId id to be shown in exception log
* @param isRequired if true object is checked for null
* @param value node to be checked
* @throws TypeCheckException thrown if json array items are not of type JsonNode.STRING
*/
public static void assertStringArray(String fieldId,
boolean isRequired,
JsonNode value) throws TypeCheckException {
assertObjectArray(fieldId, isRequired, value);

if (value != null) {
List<JsonNode> notIntNodes = StreamSupport.stream(value.spliterator(), false)
.filter(new Predicate<JsonNode>() {
@Override
public boolean test(JsonNode el) {
return el.getNodeType() != JsonNodeType.STRING;
}
})
.collect(Collectors.<JsonNode>toList());

if (!notIntNodes.isEmpty()) {
throw new TypeCheckException("Field: " + fieldId + " contents must be of type String");
}
}
}

/**
* Call this method to apply assertions on all json array items.
* @param assertions assertions to be applied on node children
* @param value node array container
* @throws TypeCheckException thrown if any of json array items are not satisfying assertions
*/
public static void applyAssertions(
ThrowingConsumer<JsonNode, TypeCheckException> assertions,
JsonNode value) throws TypeCheckException {
final ThrowingConsumer<JsonNode, TypeCheckException> asserts = assertions;
List<TypeCheckException> nodesCheckResult =
StreamSupport.stream(value.spliterator(), true)
.map(new Function<JsonNode, TypeCheckException>() {
@Override
public TypeCheckException apply(JsonNode el) {
try {
asserts.accept(el);
return null;
} catch (TypeCheckException ex) {
return ex;
}
}
})
.filter(new Predicate<TypeCheckException>() {
@Override
public boolean test(TypeCheckException obj) {
return Objects.nonNull(obj);
}
})
.collect(Collectors.<TypeCheckException>toList());

if (nodesCheckResult != null && !nodesCheckResult.isEmpty()) {
throw nodesCheckResult.get(0);
}
}

@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}

private TypeAsserts() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sendgrid.typechecker;

public class TypeCheckException extends Exception {
public TypeCheckException(String message) {
super(message);
}
}
Loading