From b77a750c3098793b9d4a4423c8837adcb5cab25c Mon Sep 17 00:00:00 2001 From: atusa17 Date: Sun, 24 Feb 2019 19:14:17 -0700 Subject: [PATCH] PAN-48 Created the AccountController and created the copyNonNullProperties method --- .../controller/AccountController.java | 163 +++++++++++++++++- .../tsp/persistence/dto/AccountsDto.java | 2 +- .../utilities/build.gradle | 3 +- .../tsp/utilities/PersistenceUtilities.java | 27 +++ 4 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 pandamonium-theorem-prover/utilities/src/main/java/edu/msudenver/tsp/utilities/PersistenceUtilities.java diff --git a/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java b/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java index 8404acb..25b1fe7 100644 --- a/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java +++ b/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java @@ -2,11 +2,22 @@ package edu.msudenver.tsp.persistence.controller; import edu.msudenver.tsp.persistence.dto.AccountsDto; import edu.msudenver.tsp.persistence.repository.AccountsRepository; +import edu.msudenver.tsp.utilities.PersistenceUtilities; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StopWatch; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; import java.util.Optional; +@Slf4j @RestController @AllArgsConstructor @RequestMapping("/accounts") @@ -14,13 +25,157 @@ public class AccountController { private final AccountsRepository accountsRepository; @GetMapping("/") - public @ResponseBody Iterable getListOfAccounts() { - return accountsRepository.findAll(); + public @ResponseBody + ResponseEntity> getListOfAccounts() { + LOG.info("Received request to list all accounts"); + + LOG.debug("Querying for list of accounts"); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfAccounts = (List) accountsRepository.findAll(); + + stopWatch.stop(); + + LOG.debug("Successfully completed query. Query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.info("Returning list of all accounts with size of " + listOfAccounts.size()); + + return new ResponseEntity<>(listOfAccounts, HttpStatus.OK); } @GetMapping("/{id}") public @ResponseBody - Optional getAccountById(@PathVariable("id") final Integer id) { - return accountsRepository.findById(id); + ResponseEntity getAccountById(@PathVariable("id") final Integer id) { + LOG.info("Received request to query for account with id " + id); + if (id == null) { + LOG.error("ERROR: ID was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Querying for account with id " + id); + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional account = accountsRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + return account.map(accountDto -> { + LOG.info("Returning account with id " + id); + return new ResponseEntity<>(accountDto, HttpStatus.OK); + }).orElseGet( + () -> { + LOG.warn("No account was found with id " + id); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + ); + } + + @PostMapping("/") + @Validated({AccountsDto.Insert.class, Default.class}) + public @ResponseBody ResponseEntity insertAccount( + @Valid @RequestBody final AccountsDto accountsDto, final BindingResult bindingResult) { + + LOG.info("Received request to insert a new account"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (accountsDto == null) { + LOG.error("Passed account is unprocessable"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Saving new account"); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final AccountsDto savedAccount = accountsRepository.save(accountsDto); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.info("Returning the newly created account"); + return new ResponseEntity<>(savedAccount, HttpStatus.CREATED); + } + + @PatchMapping("/{id}") + public @ResponseBody ResponseEntity updateAccount( + @PathVariable("id") final Integer id, + @RequestBody final AccountsDto accountsDto, final BindingResult bindingResult) { + + LOG.info("Received request to update an account"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (accountsDto == null) { + LOG.error("Passed entity is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (id == null) { + LOG.error("Account ID must be specified"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Checking for existence of account with id " + id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional existingAccount = accountsRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + + if (!existingAccount.isPresent()) { + LOG.error("No account associated with id " + id); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + PersistenceUtilities.copyNonNullProperties(accountsDto, existingAccount.get()); + existingAccount.get().setVersion(existingAccount.get().getVersion()+ 1); + + LOG.info("Updating account with id " + id); + LOG.debug("Querying for account with ID " + id); + + stopWatch.start(); + + final AccountsDto updatedAccount = accountsRepository.save(existingAccount.get()); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + + return new ResponseEntity<>(updatedAccount, HttpStatus.OK); + } + + @DeleteMapping("/{id}") + public @ResponseBody ResponseEntity deleteAccountById(@PathVariable("id") final Integer id) { + LOG.info("Received request to delete account with id " + id); + if (id == null) { + LOG.error("Specified Id is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Deleting account with id " + id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + accountsRepository.deleteById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); } } diff --git a/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountsDto.java b/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountsDto.java index ebc0a0a..cd71505 100644 --- a/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountsDto.java +++ b/pandamonium-theorem-prover/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountsDto.java @@ -27,5 +27,5 @@ public class AccountsDto extends BaseDto implements Serializable { public static final long serialVersionUID = 7095627971593953734L; - interface Insert {} + public interface Insert {} } diff --git a/pandamonium-theorem-prover/utilities/build.gradle b/pandamonium-theorem-prover/utilities/build.gradle index 007e3e1..b9e2ce9 100644 --- a/pandamonium-theorem-prover/utilities/build.gradle +++ b/pandamonium-theorem-prover/utilities/build.gradle @@ -18,6 +18,7 @@ repositories { } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.12' compile fileTree(dir: 'lib', include: '**/*.jar') + + testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/pandamonium-theorem-prover/utilities/src/main/java/edu/msudenver/tsp/utilities/PersistenceUtilities.java b/pandamonium-theorem-prover/utilities/src/main/java/edu/msudenver/tsp/utilities/PersistenceUtilities.java new file mode 100644 index 0000000..4b39e24 --- /dev/null +++ b/pandamonium-theorem-prover/utilities/src/main/java/edu/msudenver/tsp/utilities/PersistenceUtilities.java @@ -0,0 +1,27 @@ +package edu.msudenver.tsp.utilities; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; + +import java.beans.FeatureDescriptor; +import java.util.stream.Stream; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public abstract class PersistenceUtilities { + + private static String[] getNullPropertyNames(final Object source) { + final BeanWrapper wrappedSource = new BeanWrapperImpl(source); + return Stream.of(wrappedSource.getPropertyDescriptors()) + .map(FeatureDescriptor::getName) + .filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null + || propertyName.equals("id")) + .toArray(String[]::new); + } + + public static void copyNonNullProperties(final Object source, final Object target) { + BeanUtils.copyProperties(source, target, getNullPropertyNames(source)); + } +}