From 1e7be6462fd19d0b1d8540e08d910f6ac8a9784c Mon Sep 17 00:00:00 2001 From: oymakeg Date: Wed, 20 Sep 2017 11:32:37 -0400 Subject: [PATCH 1/2] This is a new version of SpringBootRestExample with Junit tests --- SpringRESTExample/pom.xml | 28 +++ .../com/springboot/restapi/Application.java | 92 +++------ .../com/springboot/restapi/CommonUtils.java | 108 ++++++++++ .../java/com/springboot/restapi/Email.java | 85 ++++++++ .../com/springboot/restapi/EmailSender.java | 125 ++++++++++++ .../springboot/restapi/FileController.java | 82 +++----- .../restapi/FileMetaDataSearchCriteria.java | 16 ++ .../springboot/restapi/FileUploadUtil.java | 12 +- .../com/springboot/restapi/RESTClient.java | 75 ++++--- .../springboot/restapi/RestClientTest.java | 189 +++++++++++++++++- .../restapi/ScheduledCronJobTests.java | 21 ++ .../springboot/restapi/ScheduledCronJobs.java | 44 +++- .../UploadFromRepository/TestExcel.xlsx | Bin 0 -> 7999 bytes .../UploadFromRepository/TestPDF.pdf | Bin 0 -> 8848 bytes .../UploadFromRepository/TestWord.docx | Bin 0 -> 11311 bytes .../src/main/resources/application.properties | 5 + .../src/main/resources/mail.properties | 8 + 17 files changed, 744 insertions(+), 146 deletions(-) create mode 100644 SpringRESTExample/src/main/java/com/springboot/restapi/CommonUtils.java create mode 100644 SpringRESTExample/src/main/java/com/springboot/restapi/Email.java create mode 100644 SpringRESTExample/src/main/java/com/springboot/restapi/EmailSender.java create mode 100644 SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobTests.java create mode 100644 SpringRESTExample/src/main/resources/UploadFromRepository/TestExcel.xlsx create mode 100644 SpringRESTExample/src/main/resources/UploadFromRepository/TestPDF.pdf create mode 100644 SpringRESTExample/src/main/resources/UploadFromRepository/TestWord.docx create mode 100644 SpringRESTExample/src/main/resources/mail.properties diff --git a/SpringRESTExample/pom.xml b/SpringRESTExample/pom.xml index dea964b..5c7d277 100644 --- a/SpringRESTExample/pom.xml +++ b/SpringRESTExample/pom.xml @@ -83,6 +83,34 @@ spring-boot-starter-cloud-connectors + + com.jayway.jsonpath + json-path-assert + + + org.skyscreamer + jsonassert + + + org.springframework.boot + + spring-boot-starter-data-elasticsearch + + + + org.springframework.boot + spring-boot-starter-artemis + + + org.springframework.boot + spring-boot-starter-freemarker + + + + javax.mail + mail + 1.4.7 + diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/Application.java b/SpringRESTExample/src/main/java/com/springboot/restapi/Application.java index 3497f0b..31880b6 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/Application.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/Application.java @@ -1,9 +1,12 @@ package com.springboot.restapi; +import java.util.Properties; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.web.client.RestTemplate; @SpringBootApplication @@ -14,72 +17,20 @@ public static void main(String[] args) { args); /** - * This method call will create a the folder "C://UploadRepo". This - * folder will be used to save the content of uploaded files. + * This method call will create the folder "C://UploadRepo". This folder + * will be used to save the content of the uploaded files. */ ((FileUploadUtil) context.getBean("fileUploadUtil")) .createUploadRepository(); - System.out.println(((RESTClient) context.getBean("restClient")) - .getAllFiles()); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile( - "src/main/resources/UploadFromRepository/TextFile.txt", - null, null)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .getAllFiles()); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile( - "src/main/resources/UploadFromRepository/TextFile.txt", - "TextFile_1.txt", null)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile( - "src/main/resources/UploadFromRepository/TextFile.txt", - "TextFile_2.txt", "Test")); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile("C://FileRepo/TextFileee.txt", "TextFile_3.txt", - "Test")); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile("C://FileRepo///", "TextFile_4.txt", "Test")); - - System.out.println(((RESTClient) context.getBean("restClient")) - .uploadFile("C://FileRepo/TextFile.txt", "Text//File_5.txt", - "Test")); - - System.out.println(((RESTClient) context.getBean("restClient")) - .getAllFiles()); - - System.out.println(((RESTClient) context.getBean("restClient")) - .getFileMetaDataById(1)); + System.out + .println("Important: For testing purposes, I assume that files in 'C://UploadRepo' and 'C://UploadRepo' folder itself will not be removed manually while the application is running."); - System.out.println(((RESTClient) context.getBean("restClient")) - .getFileMetaDataById(null)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .getFileMetaDataById(100)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .downloadFile(1)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .downloadFile(null)); - - System.out.println(((RESTClient) context.getBean("restClient")) - .downloadFile(100)); - - FileMetaDataSearchCriteria fileMetaDataSearchCriteria = new FileMetaDataSearchCriteria(); - - fileMetaDataSearchCriteria.setName("File_1"); - - System.out.println(((RESTClient) context.getBean("restClient")) - .searchFiles(fileMetaDataSearchCriteria)); + System.out + .println("Important: Please run RestClientTest.java to run the unit tests. The tests are connected to each other. Please make sure you run the whole class(not single methods) for the convenience of tests."); + System.out + .println("Important: Please run RestClientTest.java once for each run on Application.java. Otherwise, the test results will be unexpected due to uploading duplicate name files."); } @Bean @@ -87,4 +38,25 @@ public RestTemplate getRestTemplate() { return new RestTemplate(); } + /** + * This part may need update due to the network settings in the machine that + * code is executed. + * + * @return + */ + @Bean + public JavaMailSenderImpl createJavaMailSender() { + JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); + javaMailSender.setHost("smtp.gmail.com"); + javaMailSender.setPort(587); + Properties properties = new Properties(); + properties.put("spring.mail.username", "*****"); + properties.put("spring.mail.password", "*****"); + + properties.put("spring.mail.properties.mail.smtp.auth", true); + properties + .put("spring.mail.properties.mail.smtp.starttls.enable", true); + return javaMailSender; + } + } diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/CommonUtils.java b/SpringRESTExample/src/main/java/com/springboot/restapi/CommonUtils.java new file mode 100644 index 0000000..d7c0f87 --- /dev/null +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/CommonUtils.java @@ -0,0 +1,108 @@ +package com.springboot.restapi; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class CommonUtils { + + @Value("${run_scheduled_jobs}") + private String runScheduleJobs; + + @Value("${from_address}") + private String mailFromAddress; + + @Value("${to_address}") + private String mailToAddress; + + @Value("${reply_to_address}") + private String replyToAddress; + + /** + * This method is to convert a JSONArray to JSONObject list + * + * @param array + * @return + * @throws JSONException + */ + public List getJSONObjectListFromJSONArray(JSONArray array) + throws JSONException { + ArrayList jsonObjects = new ArrayList(); + for (int i = 0; i < (array != null ? array.length() : 0); jsonObjects + .add(array.getJSONObject(i++))) + ; + return jsonObjects; + } + + /** + * Returns whether or not a scheduled job is set to run based on the + * property value "run_scheduled_jobs" + * + * @return + */ + public boolean runScheduledJob() { + return Boolean.parseBoolean(runScheduleJobs); + } + + /** + * Returns the to_address entry in defined application.properties + * + * @return + */ + public String getMailToAddress() { + return mailToAddress; + } + + /** + * Returns the reply_to_address in defined application.properties + * + * @return + */ + public String getMailReplyToAddress() { + return replyToAddress; + } + + /** + * Returns the from_address in defined application.properties + * + * @return + */ + public String getMailFromAddress() { + return mailFromAddress; + } + + /** + * This method is to create an Email object from a list of FileMetaData . + * + * @param fileMetaDatas + * @return + */ + public Email generateEmailFrom(List fileMetaDatas) { + Email email = new Email(); + if (fileMetaDatas == null || fileMetaDatas.size() == 0) { + email.setSubject("No FileMetaData records added in last one hour"); + } else { + email.setSubject("New FileMetaData records added in last one hour: " + + fileMetaDatas.size()); + } + email.setFromAddress(getMailFromAddress()); + email.setToAddresses(getMailToAddress()); + email.setReplyTo(getMailReplyToAddress()); + + StringBuilder body = new StringBuilder(); + + for (FileMetaData fileMetaData : fileMetaDatas) { + body.append("

"); + body.append(fileMetaData.toString()); + body.append("

"); + } + email.setBody(body.toString()); + return email; + } +} diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/Email.java b/SpringRESTExample/src/main/java/com/springboot/restapi/Email.java new file mode 100644 index 0000000..5c52252 --- /dev/null +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/Email.java @@ -0,0 +1,85 @@ +package com.springboot.restapi; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * This class can be turned into an entity to store all email notifications in + * database. In that case, we will need to add more columns like sent_status, + * created_date, sent_date etc.Also we can write a separate scheduler to poll + * the emails that are waiting to be sent. + */ +public class Email { + private String fromAddress; + private String replyTo; + private String toAddresses; + private String ccAddresses; + private String bccAddresses; + private String subject; + private String body; + + public String getFromAddress() { + return fromAddress; + } + + public void setFromAddress(String fromAddress) { + this.fromAddress = fromAddress; + } + + public String getReplyTo() { + return replyTo; + } + + public void setReplyTo(String replyTo) { + this.replyTo = replyTo; + } + + public String getToAddresses() { + return toAddresses; + } + + public void setToAddresses(String toAddresses) { + this.toAddresses = toAddresses; + } + + public String getCcAddresses() { + return ccAddresses; + } + + public void setCcAddresses(String ccAddresses) { + this.ccAddresses = ccAddresses; + } + + public String getBccAddresses() { + return bccAddresses; + } + + public void setBccAddresses(String bccAddresses) { + this.bccAddresses = bccAddresses; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return new ToStringBuilder(this).appendSuper(super.toString()) + .append("fromAddress", fromAddress).append("replyTo", replyTo) + .append("toAddresses", toAddresses) + .append("ccAddresses", ccAddresses) + .append("bccAddresses", bccAddresses) + .append("subject", subject).append("body", body).toString(); + } +} \ No newline at end of file diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/EmailSender.java b/SpringRESTExample/src/main/java/com/springboot/restapi/EmailSender.java new file mode 100644 index 0000000..6b8b584 --- /dev/null +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/EmailSender.java @@ -0,0 +1,125 @@ +package com.springboot.restapi; + +import javax.inject.Inject; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +/** + * Utility to send email using JavaMailSender. + */ +@Component +public class EmailSender { + + private static final Logger logger = LoggerFactory + .getLogger(EmailSender.class); + + private static final char EMAIL_ADDR_SEPERATOR = ';'; + + @Inject + private JavaMailSender javaMailSender; + + /** + * Sends email using JavaMailSender. + * + * @param email + * the email + */ + public void sendEmail(Email email) { + if (logger.isTraceEnabled()) { + logger.trace("sendEmail(Email) - start"); + } + + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper; + + helper = new MimeMessageHelper(mimeMessage, true); + + prepareMimeMessageHelper(helper, email); + javaMailSender.send(mimeMessage); + logger.info("Email with subject: {} sent successfully", + email.getSubject()); + } catch (MessagingException e) { + logger.error("sendEmail(Email)", e); + } + + if (logger.isTraceEnabled()) { + logger.trace("sendEmail(Email) - end"); + } + } + + /** + * Prepare mime message. + * + * @param helper + * the MimeMessageHelper + * @param email + * the email + * @throws MessagingException + * the messaging exception + */ + private void prepareMimeMessageHelper(MimeMessageHelper helper, Email email) + throws MessagingException { + if (logger.isTraceEnabled()) { + logger.trace("prepareMimeMessageHelper(MimeMessageHelper, Email) - start"); + } + + String[] toAddresses = getEmailAddressesArray(email.getToAddresses()); + String[] ccAddresses = getEmailAddressesArray(email.getCcAddresses()); + String[] bccAddresses = getEmailAddressesArray(email.getBccAddresses()); + String subject = email.getSubject(); + String body = email.getBody(); + + helper.setFrom(email.getFromAddress()); + helper.setTo(toAddresses); + helper.setReplyTo(email.getReplyTo()); + + if (!ArrayUtils.isEmpty(ccAddresses)) { + helper.setCc(ccAddresses); + } + + if (!ArrayUtils.isEmpty(bccAddresses)) { + helper.setBcc(bccAddresses); + } + + helper.setSubject(subject); + /** + * Send as html + */ + helper.setText(body, true); + + if (logger.isTraceEnabled()) { + logger.trace("prepareMimeMessageHelper(MimeMessageHelper, Email) - end"); + } + } + + /** + * Gets the email addresses. + * + * @param toAddresses + * the to addresses + * @return the email addresses array + */ + private String[] getEmailAddressesArray(String toAddresses) { + if (logger.isTraceEnabled()) { + logger.trace("getEmailAddressesArray(String) - start"); + } + + String[] emailAddresses = StringUtils.split(toAddresses, + EMAIL_ADDR_SEPERATOR); + + if (logger.isTraceEnabled()) { + logger.trace("getEmailAddressesArray(String) - end"); + } + return emailAddresses; + } + +} diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/FileController.java b/SpringRESTExample/src/main/java/com/springboot/restapi/FileController.java index 692845d..5decb7f 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/FileController.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/FileController.java @@ -5,13 +5,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -39,17 +35,8 @@ public class FileController { * @return */ @RequestMapping(value = "/files", method = RequestMethod.GET) - public ResponseEntity getAllFiles() { - List resultList = null; - try { - resultList = repo.findAll(); - } catch (Exception e) { - return new ResponseEntity( - "Exception: getAllFiles has failed.", - HttpStatus.BAD_REQUEST); - } - return new ResponseEntity>(resultList, - HttpStatus.OK); + public List getAllFiles() { + return repo.findAll(); } /** @@ -73,10 +60,21 @@ public List searchFiles( * @return */ @RequestMapping(value = "/metadata/{id}", method = RequestMethod.GET) - public ResponseEntity getFileMetaData(@PathVariable Integer id) { + public FileMetaData getFileMetaData(@PathVariable Integer id) { FileMetaData fileMetaData = repo.findOne(id); if (fileMetaData != null) { + /** + * The reason I update some metadata fileds here is that since we + * are storing the file content in disk, I thought it might be + * helpful to update the last update and last access times and some + * other fields when we make a request to get a metadata by id. + * + * But honestly, I think we can do the same thing by a scheduled job + * which runs every 15 minutes to update some attributes of the + * related FileMetaData according to the metadata of the file on + * disk + */ try { Path path = Paths.get(fileMetaData.getPath()); BasicFileAttributes attr = Files.readAttributes(path, @@ -92,28 +90,19 @@ public ResponseEntity getFileMetaData(@PathVariable Integer id) { fileMetaData.setSymbolicLink(attr.isSymbolicLink()); fileMetaData.setSize(attr.size()); repo.saveAndFlush(fileMetaData); - - return new ResponseEntity(fileMetaData, - HttpStatus.OK); + return fileMetaData; } } catch (IOException e) { e.printStackTrace(); - return new ResponseEntity( - "IOException: Get file meta-data process has failed.", - HttpStatus.BAD_REQUEST); } catch (Exception e) { e.printStackTrace(); - return new ResponseEntity( - "Exception: Request has failed.", - HttpStatus.BAD_REQUEST); } } - return new ResponseEntity("No FileMetaData found with id: " - + id, HttpStatus.BAD_REQUEST); + return null; } /** @@ -126,27 +115,27 @@ public ResponseEntity getFileMetaData(@PathVariable Integer id) { * @return */ @RequestMapping(value = "/upload", method = RequestMethod.POST, consumes = "multipart/form-data") - public ResponseEntity uploadFile( - @RequestParam("file") MultipartFile file, + public String uploadFile(@RequestParam("file") MultipartFile file, @RequestParam(value = "name", required = false) String name, @RequestParam(value = "descr", required = false) String descr) { if (file.isEmpty()) { - return new ResponseEntity( - "Please select a file to upload.", HttpStatus.BAD_REQUEST); + return "Empty file: Please select a file to upload."; } String fileName = StringUtils.isEmpty(name) ? file .getOriginalFilename() : name; - try { + if (!fileUploadUtil.isFilenameValid(fileName)) { + return "Invalid file name : " + fileName; + } + try { if (!StringUtils.isEmpty(fileName)) { List metaDataList = repo.findByName(fileName); if (metaDataList != null && metaDataList.size() > 0) { - return new ResponseEntity( - "Duplicate file name - FileMetaData found for the given name: " - + fileName, HttpStatus.BAD_REQUEST); + return "Duplicate file name: An existing FileMetaData found for the given name " + + fileName; } } @@ -158,13 +147,11 @@ public ResponseEntity uploadFile( } catch (Exception e) { - return new ResponseEntity(e.getClass() - + ": File upload process has failed for the file " - + fileName, HttpStatus.BAD_REQUEST); + return "Failed to upload " + fileName + " -- Exception: " + + e.toString(); } - return new ResponseEntity(fileName + " successfully uploaded", - new HttpHeaders(), HttpStatus.OK); + return "You have successfully uploaded " + fileName; } /** @@ -175,7 +162,7 @@ public ResponseEntity uploadFile( * @return */ @RequestMapping(value = "/download/{id}", method = RequestMethod.GET) - public ResponseEntity downloadFile(@PathVariable("id") Integer id) { + public String downloadFile(@PathVariable("id") Integer id) { FileMetaData fileMetaData = repo.findOne(id); if (fileMetaData != null) { try { @@ -186,21 +173,18 @@ public ResponseEntity downloadFile(@PathVariable("id") Integer id) { Paths.get("src/main/resources/DownloadRepository/" + fileMetaData.getName()), data); - return new ResponseEntity( - "File successfully downloaded.", new HttpHeaders(), - HttpStatus.OK); + return "You have successfully downloaded the file ID: " + id + + ", Name: " + fileMetaData.getName(); } catch (Exception e) { e.printStackTrace(); - return new ResponseEntity(e.getClass() - + ": Download file process has failed", - HttpStatus.BAD_REQUEST); + return "Failed to download the file " + id + " --- Exception: " + + e.toString(); } } - return new ResponseEntity("File not found to download", - HttpStatus.BAD_REQUEST); + return "No FileMetaData found with ID: " + id; } } diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/FileMetaDataSearchCriteria.java b/SpringRESTExample/src/main/java/com/springboot/restapi/FileMetaDataSearchCriteria.java index d54da5e..f207eb4 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/FileMetaDataSearchCriteria.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/FileMetaDataSearchCriteria.java @@ -2,6 +2,8 @@ import java.time.LocalDateTime; +import org.apache.commons.lang3.builder.ToStringBuilder; + public class FileMetaDataSearchCriteria { private String name; @@ -124,4 +126,18 @@ public LocalDateTime getLastAccessDateTo() { public void setLastAccessDateTo(LocalDateTime lastAccessDateTo) { this.lastAccessDateTo = lastAccessDateTo; } + + @Override + public String toString() { + return new ToStringBuilder(this).appendSuper(super.toString()) + .append("name", name).append("descr", descr) + .append("path", path) + .append("createdDateFrom", createdDateFrom) + .append("createdDateTo", createdDateTo) + .append("lastUpdateDateFrom", lastUpdateDateFrom) + .append("lastUpdateDateTo", lastUpdateDateTo) + .append("contentType", contentType) + .append("lastAccessDateFrom", lastAccessDateFrom) + .append("lastAccessDateTo", lastAccessDateTo).toString(); + } } diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/FileUploadUtil.java b/SpringRESTExample/src/main/java/com/springboot/restapi/FileUploadUtil.java index 8cdb10e..5df794d 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/FileUploadUtil.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/FileUploadUtil.java @@ -36,7 +36,6 @@ public void createUploadRepository() { + DEFAULT_UPLOADED_FOLDER + "!"); } } - System.out .println("Please see the 'C:' directory for the new created UploadRepo folder that will be used as the default upload repository."); @@ -111,7 +110,7 @@ public FileMetaData createFileMetaDataFrom(String name, String descr, return fileMetaData; } - public static LocalDateTime createLocalDateTimeFrom(FileTime fileTime) { + public LocalDateTime createLocalDateTimeFrom(FileTime fileTime) { if (fileTime != null) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(fileTime.toMillis()); @@ -124,4 +123,13 @@ public static LocalDateTime createLocalDateTimeFrom(FileTime fileTime) { return null; } + /** + * This method is to check whether the given name is a valid file name + * + * @param file + * @return + */ + public boolean isFilenameValid(String file) { + return !file.matches("^.*[^a-zA-Z0-9._-].*$"); + } } diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/RESTClient.java b/SpringRESTExample/src/main/java/com/springboot/restapi/RESTClient.java index 2c8ae2d..a3c0dcf 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/RESTClient.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/RESTClient.java @@ -1,7 +1,5 @@ package com.springboot.restapi; -import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpEntity; @@ -24,11 +22,12 @@ public class RESTClient { * * @return */ - public String getAllFiles() { - String result = restTemplate.getForObject( + public ResponseEntity getAllFiles() { + ResponseEntity response = restTemplate.getForEntity( "http://localhost:8080/files", String.class); - - return result; + System.out.println("http://localhost:8080/files" + " ---> " + + response.toString()); + return response; } /** @@ -38,12 +37,16 @@ public String getAllFiles() { * @param fileMetaDataSearchCriteria * @return */ - public String searchFiles( + public ResponseEntity searchFiles( FileMetaDataSearchCriteria fileMetaDataSearchCriteria) { HttpEntity request = new HttpEntity<>( fileMetaDataSearchCriteria); - return restTemplate.postForObject("http://localhost:8080/searchFile", - request, List.class).toString(); + ResponseEntity response = restTemplate.postForEntity( + "http://localhost:8080/searchFile", request, String.class); + System.out.println("http://localhost:8080/searchFile" + + " Search Criteria: " + fileMetaDataSearchCriteria.toString() + + " ---> " + response.toString()); + return response; } /** @@ -55,7 +58,8 @@ public String searchFiles( * @param descr * @return */ - public String uploadFile(String filePath, String name, String descr) { + public ResponseEntity uploadFile(String filePath, String name, + String descr) { try { MultiValueMap parameters = new LinkedMultiValueMap(); parameters.add("file", new FileSystemResource(filePath)); @@ -66,16 +70,22 @@ public String uploadFile(String filePath, String name, String descr) { headers.set("Content-Type", "multipart/form-data"); headers.set("Accept", "text/plain"); - String result = restTemplate.postForObject( + ResponseEntity response = restTemplate.postForEntity( "http://localhost:8080/upload", new HttpEntity>(parameters, headers), String.class); - - return result; + System.out.println("http://localhost:8080/upload" + " file: " + + filePath + ", name: " + name + ", descr: " + descr + + " ---> " + response.toString()); + return response; } catch (Exception e) { - return new ResponseEntity("uploadFile('" + filePath - + "', '" + name + "', '" + descr + "') has failed.", - HttpStatus.BAD_REQUEST).toString(); + ResponseEntity excResponse = new ResponseEntity( + "uploadFile('" + filePath + "', '" + name + "', '" + descr + + "') has failed.", HttpStatus.BAD_REQUEST); + System.out.println("http://localhost:8080/upload" + " file: " + + filePath + ", name: " + name + ", descr: " + descr + + " ---> " + excResponse.toString()); + return excResponse; } } @@ -86,16 +96,21 @@ public String uploadFile(String filePath, String name, String descr) { * @param id * @return */ - public String getFileMetaDataById(Integer id) { + public ResponseEntity getFileMetaDataById(Integer id) { try { - String result = restTemplate.getForObject( + ResponseEntity response = restTemplate.getForEntity( "http://localhost:8080/metadata/" + id, String.class); + System.out.println("http://localhost:8080/metadata/" + id + + " ---> " + response.toString()); - return result; + return response; } catch (Exception e) { - return new ResponseEntity("getFileMetaDataById(" + id - + ") has failed.", HttpStatus.BAD_REQUEST).toString(); - + ResponseEntity excResponse = new ResponseEntity( + "getFileMetaDataById(" + id + ") has failed.", + HttpStatus.BAD_REQUEST); + System.out.println("http://localhost:8080/metadata/" + id + + " ---> " + excResponse.toString()); + return excResponse; } } @@ -106,18 +121,24 @@ public String getFileMetaDataById(Integer id) { * @param id * @return */ - public String downloadFile(Integer id) { + public ResponseEntity downloadFile(Integer id) { try { restTemplate.getMessageConverters().add( new ByteArrayHttpMessageConverter()); - return restTemplate.getForObject("http://localhost:8080/download/" - + id, String.class); + ResponseEntity response = restTemplate.getForEntity( + "http://localhost:8080/download/" + id, String.class); + System.out.println("http://localhost:8080/download/" + id + + " ---> " + response.toString()); + return response; } catch (Exception e) { - return new ResponseEntity("downloadFile(" + id - + ") has failed.", HttpStatus.BAD_REQUEST).toString(); + ResponseEntity excResponse = new ResponseEntity("downloadFile(" + id + + ") has failed.", HttpStatus.BAD_REQUEST); + System.out.println("http://localhost:8080/download/" + id + + " ---> " + excResponse.toString()); + return excResponse; } } } diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/RestClientTest.java b/SpringRESTExample/src/main/java/com/springboot/restapi/RestClientTest.java index 0194e5e..a89af7a 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/RestClientTest.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/RestClientTest.java @@ -1,23 +1,210 @@ package com.springboot.restapi; +import java.util.List; + +import org.hamcrest.CoreMatchers; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * RestTemplate tests in Application.java need to be implemented here. * + * The tests are connected to each other. Please make sure you run the whole + * class(not single methods) for the convenience of tests. + * + * Please run RestClientTest.java once for each run on Application.java. + * Otherwise, the test results will be unexpected due to uploading duplicate + * name files. + * */ @RunWith(value = SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RestClientTest { @Autowired private RESTClient restClient; + @Autowired + private CommonUtils commonUtils; + + @Test + public void createFileTests() { + Assert.assertEquals(restClient.getAllFiles().getBody(), "[]"); + ResponseEntity uploadResponse_1 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", null, + null); + ResponseEntity uploadResponse_2 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "TextFile_1.txt", null); + ResponseEntity uploadResponse_3 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "TextFile_2.txt", "Test"); + + ResponseEntity uploadResponse_4 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFileee.txt", + "TextFile_3.txt", "Test"); + + ResponseEntity uploadResponse_5 = restClient.uploadFile( + "src/main/resources//UploadFromRepository////", + "TextFile_4.txt", "Test"); + + // Invalid file name + ResponseEntity uploadResponse_6 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "Text//File_5.txt", "Test"); + + // Invalid file name + ResponseEntity uploadResponse_7 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "Text/File_5.txt", "Test"); + + // Invalid file name + ResponseEntity uploadResponse_8 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "Text\\File_5.txt", "Test"); + + // Duplicate file name + ResponseEntity uploadResponse_9 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TextFile.txt", + "TextFile_2.txt", "Test"); + + ResponseEntity uploadResponse_10 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TestPDF.pdf", + "FirstTestPDF.pdf", "Test"); + + ResponseEntity uploadResponse_11 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TestExcel.xlsx", + "FirstTestExcel.xlsx", "Test"); + + ResponseEntity uploadResponse_12 = restClient.uploadFile( + "src/main/resources/UploadFromRepository/TestWord.docx", + "FirstTestWord.docx", "Test"); + + Assert.assertThat(uploadResponse_1.getBody(), + CoreMatchers.containsString("successfully")); + Assert.assertThat(uploadResponse_2.getBody(), + CoreMatchers.containsString("successfully")); + Assert.assertThat(uploadResponse_3.getBody(), + CoreMatchers.containsString("successfully")); + + Assert.assertEquals(uploadResponse_4.getStatusCode(), + HttpStatus.BAD_REQUEST); + + Assert.assertEquals(uploadResponse_5.getStatusCode(), + HttpStatus.BAD_REQUEST); + + Assert.assertThat(uploadResponse_6.getBody(), + CoreMatchers.containsString("Invalid file name")); + + Assert.assertThat(uploadResponse_7.getBody(), + CoreMatchers.containsString("Invalid file name")); + + Assert.assertThat(uploadResponse_8.getBody(), + CoreMatchers.containsString("Invalid file name")); + + Assert.assertThat(uploadResponse_9.getBody(), + CoreMatchers.containsString("Duplicate")); + + Assert.assertThat(uploadResponse_10.getBody(), + CoreMatchers.containsString("successfully")); + + Assert.assertThat(uploadResponse_11.getBody(), + CoreMatchers.containsString("successfully")); + + Assert.assertThat(uploadResponse_12.getBody(), + CoreMatchers.containsString("successfully")); + } + @Test - public void testFindByName() { + public void downloadFileTests() { + Assert.assertEquals(restClient.downloadFile(null).getStatusCode(), + HttpStatus.BAD_REQUEST); + + ResponseEntity response = restClient.getAllFiles(); + + JSONArray jsonArray = new JSONArray(response.getBody()); + List jsonObjectList = commonUtils + .getJSONObjectListFromJSONArray(jsonArray); + for (JSONObject jsonObject : jsonObjectList) { + Assert.assertThat(restClient.downloadFile(jsonObject.getInt("id")) + .getBody(), CoreMatchers.containsString("successfully")); + + } + + Assert.assertThat(restClient.downloadFile(100).getBody(), + CoreMatchers.startsWith("No FileMetaData")); + } + + @Test + public void getFileMetaDataTests() { + Assert.assertEquals(restClient.getFileMetaDataById(null) + .getStatusCode(), HttpStatus.BAD_REQUEST); + Assert.assertEquals(restClient.getFileMetaDataById(1).getStatusCode(), + HttpStatus.OK); + Assert.assertEquals( + restClient.getFileMetaDataById(100).getStatusCode(), + HttpStatus.OK); + } + + @Test + public void getFilesTests() { + ResponseEntity response_1 = restClient.getAllFiles(); + Assert.assertEquals(response_1.getStatusCode(), HttpStatus.OK); + + JSONArray jsonArray = new JSONArray(response_1.getBody()); + List jsonObjectList = commonUtils + .getJSONObjectListFromJSONArray(jsonArray); + Assert.assertTrue(jsonObjectList.size() != 0); + } + + @Test + public void searchFileTests() { + FileMetaDataSearchCriteria searchCriteria_1 = new FileMetaDataSearchCriteria(); + searchCriteria_1.setName("XXXX"); + ResponseEntity response_1 = restClient + .searchFiles(searchCriteria_1); + + JSONArray jsonArray_1 = new JSONArray(response_1.getBody()); + List jsonObjectList_1 = commonUtils + .getJSONObjectListFromJSONArray(jsonArray_1); + + Assert.assertEquals(response_1.getStatusCode(), HttpStatus.OK); + Assert.assertTrue(jsonObjectList_1.size() == 0); + + FileMetaDataSearchCriteria searchCriteria_2 = new FileMetaDataSearchCriteria(); + searchCriteria_2.setName("TextFile"); + ResponseEntity response_2 = restClient + .searchFiles(searchCriteria_2); + + JSONArray jsonArray_2 = new JSONArray(response_2.getBody()); + List jsonObjectList_2 = commonUtils + .getJSONObjectListFromJSONArray(jsonArray_2); + + Assert.assertEquals(response_2.getStatusCode(), HttpStatus.OK); + Assert.assertTrue(jsonObjectList_2.size() > 1); + + FileMetaDataSearchCriteria searchCriteria_3 = new FileMetaDataSearchCriteria(); + searchCriteria_3.setContentType("WEIRD_CONTENT"); + ResponseEntity response_3 = restClient + .searchFiles(searchCriteria_3); + + JSONArray jsonArray_3 = new JSONArray(response_3.getBody()); + List jsonObjectList_3 = commonUtils + .getJSONObjectListFromJSONArray(jsonArray_3); + + Assert.assertEquals(response_3.getStatusCode(), HttpStatus.OK); + Assert.assertTrue(jsonObjectList_3.size() == 0); + } } \ No newline at end of file diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobTests.java b/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobTests.java new file mode 100644 index 0000000..982cf74 --- /dev/null +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobTests.java @@ -0,0 +1,21 @@ +package com.springboot.restapi; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(value = SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Application.class) +public class ScheduledCronJobTests { + + @Autowired + private ScheduledCronJobs scheduledCronJobs; + + + @Test + public void pollForNewItemsTest(){ + scheduledCronJobs.pollForNewItems(); + } +} diff --git a/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobs.java b/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobs.java index c64ddd3..41838fb 100644 --- a/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobs.java +++ b/SpringRESTExample/src/main/java/com/springboot/restapi/ScheduledCronJobs.java @@ -1,36 +1,66 @@ package com.springboot.restapi; +import java.time.LocalDateTime; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +@Service public class ScheduledCronJobs { private AtomicBoolean isRunning = new AtomicBoolean(false); + @Autowired + private FileMetaDataDao fileMetaDataDao; + + @Autowired + private CommonUtils commonUtils; + + @Autowired + private EmailSender emailSender; + /** * Scheduled job to poll for new items in the last hour and send an email + * + * Please remember that emailSender may give an error due to the SMTP + * configuration settings or any network restrictions in the machine that + * the code is executed. */ @Scheduled(cron = "0 0/60 * * *") public void pollForNewItems() { + if (!commonUtils.runScheduledJob()) { + System.out.println("Not running scheduled jobs on this container."); + return; + } if (isRunning.get()) { + System.out + .println("pollForNewItems cron job process is already running so exiting"); return; } + List fileMetaDataList = null; try { isRunning.set(true); - /** - * Add the business logic here to fetch the items in the last hour - */ + FileMetaDataSearchCriteria fileMetaDataSearchCriteria = new FileMetaDataSearchCriteria(); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime oneHourAgo = now.minusHours(1); + fileMetaDataSearchCriteria.setCreatedDateFrom(oneHourAgo); + fileMetaDataSearchCriteria.setCreatedDateTo(now); + + fileMetaDataList = fileMetaDataDao + .searchFileMetaData(fileMetaDataSearchCriteria); } catch (Exception e) { e.printStackTrace(); } finally { isRunning.set(false); - /** - * Send email if there are any new items added in the last hour - */ + if (fileMetaDataList != null) { + Email email = commonUtils.generateEmailFrom(fileMetaDataList); + emailSender.sendEmail(email); + } } } - } diff --git a/SpringRESTExample/src/main/resources/UploadFromRepository/TestExcel.xlsx b/SpringRESTExample/src/main/resources/UploadFromRepository/TestExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..099b21881eacc13000c05c0a36d00decc233ac48 GIT binary patch literal 7999 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 literal 0 HcmV?d00001 diff --git a/SpringRESTExample/src/main/resources/UploadFromRepository/TestPDF.pdf b/SpringRESTExample/src/main/resources/UploadFromRepository/TestPDF.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4c229a07a000c2a10f14c22b91f10819fbc3ae64 GIT binary patch literal 8848 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 literal 0 HcmV?d00001 diff --git a/SpringRESTExample/src/main/resources/UploadFromRepository/TestWord.docx b/SpringRESTExample/src/main/resources/UploadFromRepository/TestWord.docx new file mode 100644 index 0000000000000000000000000000000000000000..b09f25d211b6b18d8e770e2c6d6d05bc55a5b2e1 GIT binary patch literal 11311 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 literal 0 HcmV?d00001 diff --git a/SpringRESTExample/src/main/resources/application.properties b/SpringRESTExample/src/main/resources/application.properties index e69de29..037f8dd 100644 --- a/SpringRESTExample/src/main/resources/application.properties +++ b/SpringRESTExample/src/main/resources/application.properties @@ -0,0 +1,5 @@ +run_scheduled_jobs=true +send_emails=true +from_address=********* +to_address=********* +reply_to_address=********* diff --git a/SpringRESTExample/src/main/resources/mail.properties b/SpringRESTExample/src/main/resources/mail.properties new file mode 100644 index 0000000..a44ed7d --- /dev/null +++ b/SpringRESTExample/src/main/resources/mail.properties @@ -0,0 +1,8 @@ +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=***** +spring.mail.password=*** + +#mail properties +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true \ No newline at end of file From 2d5fc6b520980cb56fc9276c24be823b9fcbc53b Mon Sep 17 00:00:00 2001 From: codehunter34 <31874661+codehunter34@users.noreply.github.com> Date: Wed, 20 Sep 2017 11:52:45 -0400 Subject: [PATCH 2/2] Create README.md --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..5075c32 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# SpringBootApplications + +1) All the RestTemplate tests were implemented in RestClientTest.java using Junit. +After you start the application, you can run RestClientTest.java. + +Please remember that test methods have to be executed with the given order because results of one method is affecting the result of another one. +For example; we need to upload first to be able to make a download, get by id etc. + +2) CommonUtils class was added to define a few utility methods. + +3) Email, EmailSender, ScheduledCronJobTests classes were created to send emails + +4) Application.java, FileController.java, FileMetaDataSearchCriteria.java, FileUploadUtil.java, RESTClient.java, RestClientTest.java, +ScheduledCronJobs.java were updated. + + +Important notes: + +For testing purposes, I assume that files in 'C://UploadRepo' and 'C://UploadRepo' folder itself will not be removed manually while the application is running. + +Please run RestClientTest.java to run the unit tests. The tests are connected to each other. Please make sure you run the whole class(not single methods) for the convenience of tests. + +Please run RestClientTest.java once for each run on Application.java. Otherwise, the test results will be unexpected due to uploading duplicate name files. + +Please replace the email addresses in application.properties with your own email addresses to see whether the cron job is sending an email. It would be a better practice to keep these type of values in a SYSTEM_PARAMETERS table. +Application.createJavaMailSender needs update in terms of SMTP settings. + +Please check 'src/main/resourcec/DownloadRepository' and 'C://UploadRepo' for downloaded and uploaded files.