diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java index b30a252..d442d01 100644 --- a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java @@ -29,7 +29,7 @@ public class AccountsIntegrationTest { assertEquals("Test username", savedAccount.getUsername()); assertEquals("test password", savedAccount.getPassword()); - assertTrue(savedAccount.isAdministratorStatus()); + assertTrue(savedAccount.getAdministratorStatus()); savedAccount.setPassword("Test Update"); @@ -37,7 +37,7 @@ public class AccountsIntegrationTest { assertEquals("Test username", savedAccount.getUsername()); assertEquals("Test Update", savedAccount.getPassword()); - assertTrue(savedAccount.isAdministratorStatus()); + assertTrue(savedAccount.getAdministratorStatus()); assertEquals(updatedAccount.getId(), id); accountsRepository.delete(accountDto); diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java index 35b8a86..b68bad1 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java @@ -7,5 +7,5 @@ import org.springframework.stereotype.Component; @Component @AllArgsConstructor public class NotationController { - final private NotationRepository notationRepository; + private final NotationRepository notationRepository; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java index 51e5d25..e52b209 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java @@ -7,5 +7,5 @@ import org.springframework.stereotype.Component; @Component @AllArgsConstructor public class ProofController { - final private ProofRepository proofRepository; + private final ProofRepository proofRepository; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java index 080ed54..9c26063 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java @@ -7,5 +7,5 @@ import org.springframework.stereotype.Component; @Component @AllArgsConstructor public class TheoremController { - final private TheoremRepository theoremRepository; + private final TheoremRepository theoremRepository; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java index 717bc64..882826c 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java @@ -22,10 +22,30 @@ import java.util.Date; public class AccountDto extends BaseDto implements Serializable { @NotBlank(groups = Insert.class, message = "A username must be specified") @Size(max = 50) private String username; @NotBlank(groups = Insert.class, message = "A password must be specified") @Size(max = 256) private String password; - @NotNull @JsonProperty("administrator_status") private boolean administratorStatus; - @Temporal(TemporalType.DATE) @JsonProperty("last_login") private Date lastLogin; + @NotNull private boolean administratorStatus; + @Temporal(TemporalType.DATE) private Date lastLogin; - public static final long serialVersionUID = 7095627971593953734L; + private static final long serialVersionUID = 7095627971593953734L; + + @JsonProperty("administrator_status") + public boolean getAdministratorStatus() { + return administratorStatus; + } + + @JsonProperty("administrator_status") + public void setAdministratorStatus(final boolean administratorStatus) { + this.administratorStatus = administratorStatus; + } + + @JsonProperty("last_login") + public Date getLastLogin() { + return lastLogin; + } + + @JsonProperty("last_login") + public void setLastLogin(final Date lastLogin) { + this.lastLogin = lastLogin; + } public interface Insert {} } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java index b718619..b6eb9ce 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java @@ -36,5 +36,5 @@ public class BaseDto implements Serializable { @Version private Integer version; - public static final long serialVersionUID = -1686252381978213945L; + private static final long serialVersionUID = -1686252381978213945L; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java index e346772..b2a26cb 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java @@ -13,5 +13,5 @@ import java.util.List; public class Definition implements Serializable { private List definitions; - public static final long serialVersionUID = -2208496232532214840L; + private static final long serialVersionUID = -2208496232532214840L; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java index 806e84c..89583ad 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java @@ -28,7 +28,7 @@ public class DefinitionDto extends BaseDto implements Serializable { @Type(type = "json") @Column(columnDefinition = "jsonb") private Notation notation; - public static final long serialVersionUID = -5314619286352932857L; + private static final long serialVersionUID = -5314619286352932857L; public interface Insert {} } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java index 0545f3c..3936174 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java @@ -12,5 +12,5 @@ import java.util.List; @ToString public class Notation implements Serializable { private List notations; - public static final long serialVersionUID = 2301438318932336121L; + private static final long serialVersionUID = 2301438318932336121L; } diff --git a/persistence/src/main/resources/application.properties b/persistence/src/main/resources/application.properties index 0068dff..c7ecc80 100644 --- a/persistence/src/main/resources/application.properties +++ b/persistence/src/main/resources/application.properties @@ -1,6 +1,6 @@ spring.jpa.hibernate.ddl-auto = none spring.jpa.database=mysql -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false&serverTimezone=UTC spring.datasource.username=panda spring.datasource.password=secret spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver diff --git a/services/build.gradle b/services/build.gradle index a53319f..05efbeb 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -19,6 +19,10 @@ repositories { dependencies { compile project(':persistence') - testCompile group: 'junit', name: 'junit', version: '4.12' + compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4.11' + compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.7' + compile group: 'com.google.code.gson', name: 'gson', version: '2.7' compile fileTree(dir: 'lib', include: '**/*.jar') + + testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/services/src/main/java/edu/msudenver/tsp/services/RestService.java b/services/src/main/java/edu/msudenver/tsp/services/RestService.java new file mode 100644 index 0000000..78f0cb9 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/RestService.java @@ -0,0 +1,100 @@ +package edu.msudenver.tsp.services; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import edu.msudenver.tsp.services.factory.RequestFactory; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.fluent.Request; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Slf4j +@Service +public class RestService { + private static final Gson GSON = new Gson(); + private final RequestFactory requestFactory; + + @Autowired + public RestService(final RequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + public boolean delete(final String uri, final Integer connectionTimeout, final Integer socketTimeout, final HttpStatus httpStatus) { + LOG.info("Sending DELETE {}", uri); + final Optional response = send(requestFactory.delete(uri), null, connectionTimeout, socketTimeout); + + return response.isPresent() && response.get().getStatusLine().getStatusCode() == httpStatus.value(); + } + + Optional get(final String uri, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout, final String auth) { + LOG.info("Sending GET {}", uri); + return send(requestFactory.get(uri), auth, connectionTimeout, socketTimeout, type); + } + + Optional post(final String uri, final String requestJson, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout) { + LOG.info("Sending POST {} with body: {}", uri, requestJson); + return send(requestFactory.post(uri, requestJson), null, connectionTimeout, socketTimeout, type); + } + + Optional post(final String uri, final String requestJson, final Integer connectionTimeout, final Integer socketTimeout) { + LOG.info("Sending POST {} with body: {}", uri, requestJson); + return send(requestFactory.post(uri, requestJson), null, connectionTimeout, socketTimeout); + } + + Optional put(final String uri, final String requestJson, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout, final String auth) { + LOG.info("Sending PUT {} with body: {}", uri, requestJson); + return send(requestFactory.put(uri, requestJson), auth, connectionTimeout, socketTimeout, type); + } + + private Optional send(final Request request, final String auth, final Integer connectionTimeout, final Integer socketTimeout, final TypeToken type) { + try { + final Optional optionalHttpResponse = send(request, auth, connectionTimeout, socketTimeout); + if (optionalHttpResponse.isPresent()) { + final HttpResponse httpResponse = optionalHttpResponse.get(); + LOG.info("Received {} response", httpResponse.getStatusLine().getStatusCode()); + + final String jsonResponse = httpResponse.getEntity() == null ? null : EntityUtils.toString(httpResponse.getEntity()); + if (StringUtils.isNotBlank(jsonResponse)) { + final T responses = GSON.fromJson(jsonResponse, type.getType()); + if (responses instanceof List) { + LOG.info("Found {} responses.", ((List) responses).size()); + if (((List) responses).isEmpty()) { + return Optional.empty(); + } + } + + return Optional.ofNullable(responses); + } + } + } catch (final Exception e) { + LOG.error("Could not send request", e); + } + + return Optional.empty(); + } + + private Optional send(final Request request, final String auth, final Integer connectionTimeout, final Integer socketTimeout) { + if (StringUtils.isNotBlank(auth)) { + request.addHeader("Authorization", "Basic " + auth); + } + + try { + return Optional.ofNullable(request.connectTimeout(connectionTimeout) + .socketTimeout(socketTimeout) + .execute() + .returnResponse()); + } catch (final Exception e) { + LOG.error("Could not send request", e); + return Optional.empty(); + } + } +} + + diff --git a/services/src/main/java/edu/msudenver/tsp/services/UserService.java b/services/src/main/java/edu/msudenver/tsp/services/UserService.java new file mode 100644 index 0000000..f119441 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/UserService.java @@ -0,0 +1,57 @@ +package edu.msudenver.tsp.services; + +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import edu.msudenver.tsp.services.dto.Account; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; + +@Slf4j +@Service +public class UserService { + private final RestService restService; + @Value("${persistence.api.connection.timeout.milliseconds}") private int connectionTimeoutMilliseconds; + @Value("${persistence.api.socket.timeout.milliseconds}") private int socketTimeoutMilliseconds; + @Value("${persistence.api.base.url}") private String persistenceApiBaseUrl; + + @Autowired + public UserService(final RestService restService) { + this.restService = restService; + } + + public Optional createNewAccount(final Account account) { + if (account == null) { + LOG.error("Given null account, returning {}"); + return Optional.empty(); + } + final Instant start = Instant.now(); + + try { + final TypeToken typeToken = new TypeToken() {}; + final Optional persistenceApiResponse = restService.post(persistenceApiBaseUrl + "/accounts/", + new GsonBuilder().create().toJson(account), + typeToken, + connectionTimeoutMilliseconds, + socketTimeoutMilliseconds); + + if (persistenceApiResponse.isPresent()) { + LOG.info("Returning {}", persistenceApiResponse.get()); + } else { + LOG.info("Unable to create new account {}", account.toString()); + } + + return persistenceApiResponse; + } catch (final Exception e) { + LOG.error("Error creating new account {}", e); + return Optional.empty(); + } finally { + LOG.info("Create new account request took {} ms", Duration.between(start, Instant.now()).toMillis()); + } + } +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java b/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java new file mode 100644 index 0000000..c82731a --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java @@ -0,0 +1,22 @@ +package edu.msudenver.tsp.services.dto; + +import com.google.gson.annotations.SerializedName; +import edu.msudenver.tsp.persistence.dto.AccountDto; + +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; + +public class Account extends BaseDto implements Serializable { + @NotBlank(groups = AccountDto.Insert.class, message = "A username must be specified") @Size(max = 50) private String username; + @NotBlank(groups = AccountDto.Insert.class, message = "A password must be specified") @Size(max = 256) private String password; + @NotNull @SerializedName("administrator_status") private boolean administratorStatus; + @Temporal(TemporalType.DATE) @SerializedName("last_login") private Date lastLogin; + + private static final long serialVersionUID = 7095627971593953734L; + +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java b/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java new file mode 100644 index 0000000..4dc5dfd --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java @@ -0,0 +1,13 @@ +package edu.msudenver.tsp.services.dto; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BaseDto implements Serializable { + private int id; + private Integer version; + + private static final long serialVersionUID = 5343705942114910963L; +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java b/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java new file mode 100644 index 0000000..726b9a8 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java @@ -0,0 +1,25 @@ +package edu.msudenver.tsp.services.factory; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; +import org.springframework.stereotype.Service; + +@Service +public class RequestFactory { + public Request delete(final String uri) { + return Request.Delete(uri); + } + + public Request get(final String uri) { + return Request.Get(uri); + } + + public Request post(final String uri, final String requestJson) { + return StringUtils.isNotBlank(requestJson) ? Request.Post(uri).bodyString(requestJson, ContentType.APPLICATION_JSON) : Request.Post(uri); + } + + public Request put(final String uri, final String requestJson) { + return StringUtils.isNotBlank(requestJson) ? Request.Put(uri).bodyString(requestJson, ContentType.APPLICATION_JSON) : Request.Put(uri); + } +} \ No newline at end of file diff --git a/services/src/main/resources/application.properties b/services/src/main/resources/application.properties new file mode 100644 index 0000000..ff86c7e --- /dev/null +++ b/services/src/main/resources/application.properties @@ -0,0 +1,3 @@ +persistence.api.connection.timeout.milliseconds = 5000 +persistence.api.socket.timeout.milliseconds = 10000 +persistence.api.base.url = http://localhost:8090/ \ No newline at end of file