diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..946164b
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,38 @@
+version: 2
+jobs:
+ build:
+ docker:
+ - image: circleci/openjdk:8-jdk
+ working_directory: ~/moip-sdk-java
+
+ environment:
+ JVM_OPTS: -Xmx3200m
+ TERM: dumb
+
+ steps:
+ - checkout
+
+ - restore_cache:
+ keys:
+ - v1-dependencies-{{ checksum "build.gradle" }}
+ - v1-dependencies-
+
+ - run:
+ name: Dependencies
+ command: ./gradlew clean dependencies -PossrhUsername=username -PossrhPassword=password
+
+ - save_cache:
+ paths:
+ - ~/.gradle
+ key: v1-dependencies-{{ checksum "build.gradle" }}
+
+ - run:
+ name: Build and test
+ command: ./gradlew clean test -PossrhUsername=username -PossrhPassword=password -i
+
+workflows:
+ version: 2
+ moip_devx_tools:
+ jobs:
+ - build
+
diff --git a/.circleci/secring.gpg.enc b/.circleci/secring.gpg.enc
new file mode 100644
index 0000000..5f7b2b9
--- /dev/null
+++ b/.circleci/secring.gpg.enc
@@ -0,0 +1,204 @@
+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
diff --git a/.gitignore b/.gitignore
index 62c8935..ea90fe0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
-.idea/
\ No newline at end of file
+.idea/
+.gradle
+out/
+*.iml
+build/
\ No newline at end of file
diff --git a/.gradle/4.0/fileChanges/last-build.bin b/.gradle/4.0/fileChanges/last-build.bin
deleted file mode 100644
index f76dd23..0000000
Binary files a/.gradle/4.0/fileChanges/last-build.bin and /dev/null differ
diff --git a/.gradle/4.0/fileHashes/fileHashes.bin b/.gradle/4.0/fileHashes/fileHashes.bin
deleted file mode 100644
index 6972080..0000000
Binary files a/.gradle/4.0/fileHashes/fileHashes.bin and /dev/null differ
diff --git a/.gradle/4.0/fileHashes/fileHashes.lock b/.gradle/4.0/fileHashes/fileHashes.lock
deleted file mode 100644
index a395599..0000000
Binary files a/.gradle/4.0/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/.gradle/4.0/taskHistory/fileSnapshots.bin b/.gradle/4.0/taskHistory/fileSnapshots.bin
deleted file mode 100644
index 4353815..0000000
Binary files a/.gradle/4.0/taskHistory/fileSnapshots.bin and /dev/null differ
diff --git a/.gradle/4.0/taskHistory/taskHistory.bin b/.gradle/4.0/taskHistory/taskHistory.bin
deleted file mode 100644
index 7d4f5d6..0000000
Binary files a/.gradle/4.0/taskHistory/taskHistory.bin and /dev/null differ
diff --git a/.gradle/4.0/taskHistory/taskHistory.lock b/.gradle/4.0/taskHistory/taskHistory.lock
deleted file mode 100644
index 6378d29..0000000
Binary files a/.gradle/4.0/taskHistory/taskHistory.lock and /dev/null differ
diff --git a/.gradle/buildOutputCleanup/built.bin b/.gradle/buildOutputCleanup/built.bin
deleted file mode 100644
index e69de29..0000000
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
deleted file mode 100644
index 585f421..0000000
--- a/.gradle/buildOutputCleanup/cache.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-#Wed May 30 16:56:05 BRT 2018
-gradle.version=4.0
diff --git a/.gradle/buildOutputCleanup/cache.properties.lock b/.gradle/buildOutputCleanup/cache.properties.lock
deleted file mode 100644
index 40fdece..0000000
--- a/.gradle/buildOutputCleanup/cache.properties.lock
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 80ba0b9..444b8c9 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
-# moip-sdk-java-2
\ No newline at end of file
+# moip-sdk-java-2
+
+
diff --git a/build.gradle b/build.gradle
index bf2758b..58c4aa1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,99 @@
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'signing'
+
group 'br.com.moip'
+archivesBaseName = "sdk-java"
version '0.1.0'
-apply plugin: 'java'
+description = "Java SDK for Moip APIs integration"
sourceCompatibility = 1.8
+targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
+ compile group: "org.apache.httpcomponents", name: "httpclient", version: "4.5.3"
+ compile group: "org.apache.commons", name: "commons-lang3", version: "3.6"
+ compile group: "org.slf4j", name: "slf4j-api", version: "1.7.12"
+ compile group: "com.google.code.gson", name: "gson", version: "2.4"
+ compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5'
+
testCompile group: 'junit', name: 'junit', version: '4.12'
+ testCompile group: "org.slf4j", name: "slf4j-simple", version: "1.7.12"
+ testCompile group: "com.github.rodrigosaito", name: "mockwebserver-player", version: "1.1.0"
+}
+
+task javadocJar(type: Jar) {
+ classifier = 'javadoc'
+ from javadoc
+}
+
+task sourcesJar(type: Jar) {
+ classifier = 'sources'
+ from sourceSets.main.allSource
+}
+
+artifacts {
+ archives javadocJar, sourcesJar
+}
+
+signing {
+ sign configurations.archives
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+
+ repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
+ authentication(userName: System.getenv('MVN_USERNAME'), password: System.getenv('MVN_PASSWORD'))
+ }
+
+ snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
+ authentication(userName: System.getenv('MVN_USERNAME'), password: System.getenv('MVN_PASSWORD'))
+ }
+
+ pom.project {
+ name 'Moip Java SDK'
+ packaging 'jar'
+ // the artifactId can be defined here (it's optional)
+ description 'Java SDK for Moip APIs integration'
+ url 'https://github.com/moip/moip-sdk-java'
+
+ scm {
+ connection 'scm:git:ssh://git@github.com:moip/moip-sdk-java.git'
+ developerConnection 'scm:git:ssh://git@github.com:moip/moip-sdk-java.git'
+ url 'https://github.com/moip/moip-sdk-java'
+ }
+
+ licenses {
+ license {
+ name 'The MIT License (MIT)'
+ url 'http://opensource.org/licenses/MIT'
+ }
+ }
+
+ developers {
+ developer {
+ id 'matheus.nakaya'
+ name 'Matheus B. Nakaya'
+ email 'matheus.nakaya@moip.com.br'
+ }
+ }
+ }
+ }
+ }
+}
+
+processResources {
+ filesMatching("**/moipJavaSDK.properties") {
+ expand([
+ version: version
+ ])
+ }
}
diff --git a/src/main/java/br/com/moip/Moip.java b/src/main/java/br/com/moip/Moip.java
new file mode 100644
index 0000000..6f5c942
--- /dev/null
+++ b/src/main/java/br/com/moip/Moip.java
@@ -0,0 +1,44 @@
+package br.com.moip;
+
+import br.com.moip.api.APIResources;
+import br.com.moip.api.request.RequestMaker;
+
+import java.io.InputStream;
+import java.util.Properties;
+
+public class Moip {
+
+ public static final String SANDBOX_URL = "https://sandbox.moip.com.br";
+
+ public static final String PRODUCTION_URL = "https://api.moip.com.br";
+
+ public static final String CONNECT_SANDBOX_URL = "https://connect-sandbox.moip.com.br";
+
+ public static final String CONNECT_PRODUCTION_URL = "https://connect.moip.com.br";
+
+ /**
+ *
+ */
+ private static String USER_AGENT;
+
+ static {
+ try {
+ InputStream inputStream = RequestMaker.class.getResourceAsStream("/moipJavaSDK.properties");
+ Properties properties = new Properties();
+ properties.load(inputStream);
+
+ USER_AGENT = properties.getProperty("userAgent");
+ } catch (Exception e) { // verificar tipo de exception
+ USER_AGENT = "MoipJavaSDK/UnknownVersion (+https://github.com/moip/moip-sdk-java/)";
+ }
+ }
+
+ /**
+ * This method returns the {@code USER_AGENT} value.
+ *
+ * @return {@code String}
+ */
+ protected String getUserAgent() { return USER_AGENT; }
+
+ public static class API extends APIResources {}
+}
diff --git a/src/main/java/br/com/moip/api/APIResources.java b/src/main/java/br/com/moip/api/APIResources.java
new file mode 100644
index 0000000..2db03a1
--- /dev/null
+++ b/src/main/java/br/com/moip/api/APIResources.java
@@ -0,0 +1,35 @@
+package br.com.moip.api;
+
+import br.com.moip.models.Customer;
+import br.com.moip.models.Order;
+import br.com.moip.models.Payment;
+import br.com.moip.models.Refund;
+import br.com.moip.models.NotificationPreference;
+import br.com.moip.models.Webhook;
+
+public class APIResources {
+
+ private static Customer customerInstance = new Customer();
+ private static Order orderInstance = new Order();
+ private static Payment paymentInstance = new Payment();
+ private static Refund refundInstance = new Refund();
+ private static NotificationPreference notificationPreferenceInstance = new NotificationPreference();
+ private static Webhook webhookInstance = new Webhook();
+
+ /**
+ * This method is used to get a instance of customer object.
+ *
+ * @return {@code Customer}
+ */
+ public static Customer customers() { return customerInstance; }
+
+ public static Order orders() { return orderInstance; }
+
+ public static Payment payments() { return paymentInstance; }
+
+ public static Refund refunds() { return refundInstance; }
+
+ public static NotificationPreference notificationPreferences() { return notificationPreferenceInstance; }
+
+ public static Webhook webhooks() { return webhookInstance; }
+}
diff --git a/src/main/java/br/com/moip/api/request/APIDateRequest.java b/src/main/java/br/com/moip/api/request/APIDateRequest.java
new file mode 100644
index 0000000..45ea720
--- /dev/null
+++ b/src/main/java/br/com/moip/api/request/APIDateRequest.java
@@ -0,0 +1,20 @@
+package br.com.moip.api.request;
+
+import java.util.Date;
+
+public class APIDateRequest {
+
+ private Date date;
+
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * This constructor receive a APIDate object to fill the attribute date.
+ *
+ * @param date
+ * {@code APIDate} a numerical date.
+ */
+ public void date(Date date) { this.date = date; }
+}
diff --git a/src/main/java/br/com/moip/api/request/RequestMaker.java b/src/main/java/br/com/moip/api/request/RequestMaker.java
new file mode 100644
index 0000000..fe2ef8b
--- /dev/null
+++ b/src/main/java/br/com/moip/api/request/RequestMaker.java
@@ -0,0 +1,276 @@
+package br.com.moip.api.request;
+
+import br.com.moip.Moip;
+import br.com.moip.api.response.Response;
+import br.com.moip.auth.Authentication;
+import br.com.moip.exception.MoipAPIException;
+import br.com.moip.exception.UnauthorizedException;
+import br.com.moip.exception.UnexpectedException;
+import br.com.moip.exception.ValidationException;
+import br.com.moip.models.Setup;
+import br.com.moip.models.error.Errors;
+import br.com.moip.utilities.ssl.SSLSupport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.io.BufferedWriter;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RequestMaker extends Moip {
+
+ private final String moipEnvironment;
+ private final Authentication authentication;
+ private static final Logger LOGGER = LoggerFactory.getLogger(RequestMaker.class);
+ private RequestTools tools;
+ private Response response;
+
+
+ /**
+ * This constructor sets the Moip environment and the authentication received from parameter.
+ *
+ * @param setup
+ * {@code Setup} the setup object.
+ *
+ * @see br.com.moip.auth.Authentication
+ */
+ public RequestMaker(Setup setup) {
+
+ this.moipEnvironment = setup.getEnvironment();
+ this.authentication = setup.getAuthentication();
+ this.tools = new RequestTools();
+ this.response = new Response();
+ }
+
+ /**
+ * This method is used to build the request, it set the environment (Sandbox or Production)
+ * and the headers, create the {@code connection} object to establish connection with Moip
+ * APIResources, authenticate the connection, load the request properties received from parameter,
+ * serialize the request object and send it to the API. Finally, this method receive the
+ * response JSON and deserialize it into the respective model object, sending the response
+ * code and response body to {@code responseBodyTreatment} method to treat the response.
+ *
+ * @param requestProps
+ * {@code RequestProperties} the object containing the properties of
+ * request, its like request method, endpoint, object, type, content type
+ * and if it accepts another JSON version.
+ *
+ *
+ * @return {@code Map}
+ */
+ public Map doRequest(final RequestProperties requestProps) {
+
+ try {
+
+ URL url = new URL(moipEnvironment + requestProps.endpoint);
+
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestProperty("User-Agent", getUserAgent());
+ connection.setRequestProperty("Content-type", requestProps.getContentType().getMimeType());
+
+ if (requestProps.hasAccept()) connection.setRequestProperty("Accept", requestProps.accept);
+
+ connection.setRequestMethod(requestProps.method);
+
+ // This validation disable the TLS 1.0
+ if (connection instanceof HttpsURLConnection) {
+ ((HttpsURLConnection) connection).setSSLSocketFactory(new SSLSupport());
+ }
+
+ if (this.authentication != null) authentication.authenticate(connection);
+
+ LOGGER.debug("---> {} {}", requestProps.method, connection.getURL().toString());
+ logHeaders(connection.getRequestProperties().entrySet());
+
+ // Verificar essa parte do código, pois o objeto serializado deve ser um Map, não mais um String
+
+ if (requestProps.body != null) {
+ connection.setDoOutput(true);
+ String body = tools.getBody(requestProps.body, requestProps.contentType);
+
+ LOGGER.debug("{}", body);
+
+ DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(wr, "UTF-8"));
+ writer.write(body);
+ writer.close();
+ wr.flush();
+ wr.close();
+ }
+
+ // ----------------------------------------------------------------------------------------------
+
+ LOGGER.debug("---> END HTTP");
+
+ int responseCode = connection.getResponseCode();
+
+ LOGGER.debug("<--- {} {}", responseCode, connection.getResponseMessage());
+ logHeaders(connection.getHeaderFields().entrySet());
+
+ StringBuilder responseBody = new StringBuilder();
+
+ responseBody = responseBodyTreatment(responseBody, responseCode, connection);
+
+ LOGGER.debug("{}", responseBody.toString());
+ LOGGER.debug("<-- END HTTP ({}-byte body)", connection.getContentLength());
+
+ // Return the parsed response from JSON to Map.
+ return this.response.jsonToMap(responseBody.toString());
+
+ } catch(IOException | KeyManagementException | NoSuchAlgorithmException e){
+ throw new MoipAPIException("Error occurred connecting to Moip API: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ *
+ * @param requestProps
+ * @return
+ */
+ public List