Skip to content

Commit

Permalink
Updating exception handling, add new jobs and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
pranav-patil authored and Pranav Patil committed Dec 27, 2017
1 parent a952d63 commit 4272dce
Show file tree
Hide file tree
Showing 21 changed files with 373 additions and 76 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# Spring 5 MVC Showcase
Spring 5 MVC Application demonstrates the capabilities of the Spring 5 framework ranging from Spring MVC, Spring JPA, Spring Security.
[Spring 5](https://docs.spring.io/spring/docs/current/spring-framework-reference/index.html) MVC Application demonstrates the capabilities of the Spring 5 framework ranging from Spring MVC, Spring JPA, Spring Security.
Also helps in understanding of new techniques such as Thymeleaf templates for UI development, Selma for object mappings, Swagger/SpringFox for API documentation etc.

In this showcase you'll see the following in action:

* Rest Services using @Controller
* Mapping Objects using Selma
* Spring JPA using Hibernate for H2 SQL database
* Rest Services using @RestController
* Mapping Objects using [Selma](http://www.selma-java.org/)
* Spring JPA using [Hibernate](https://docs.jboss.org/hibernate/orm/5.0/manual/en-US/html/index.html) for H2 SQL database
* Validation
* Thymeleaf template using Spring expression language
* [Thymeleaf template](http://www.thymeleaf.org) using Spring expression language
* Exception Handling
* Swagger documentation using Spring Fox
* [Swagger](https://swagger.io/) documentation using [Spring Fox](http://springfox.github.io/springfox/docs/snapshot)
* [Quartz Job Scheduler](http://www.quartz-scheduler.org/) with database
* [Lombok](https://projectlombok.org/), log definitions with annotations

To run the application:
-------------------
Expand Down
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<jackson.version>2.9.2</jackson.version>
<logback.version>1.1.7</logback.version>
<jcl.slf4j.version>1.7.12</jcl.slf4j.version>
<dbh2.version>1.4.187</dbh2.version>
<dbh2.version>1.4.196</dbh2.version>
<hibernate.version>5.2.12.Final</hibernate.version>
</properties>

Expand Down Expand Up @@ -138,6 +138,12 @@
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>

<!-- Quartz Scheduler -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package com.library.spring.scheduler.job;

import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

@Slf4j
public class MongoSyncJob implements Job {

@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("MongoSyncJob is now running..");
JobDataMap jobMap = context.getMergedJobDataMap();
String collection = jobMap.getString("collection");
String service = jobMap.getString("service");

log.info(String.format("Syncing data from service url %s into mongodb collection name %s...", service, collection));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,17 @@ public static JobDescriptor buildDescriptor(JobDetail jobDetail, List<? extends

if(!jobDataMap.isEmpty() && jobDataMap.containsKey("jobDataClass")) {
ObjectMapper mapper = new ObjectMapper();
Class<? extends JobData> jobDataClass = (Class<? extends JobData>) jobDataMap.get("jobDataClass");
Object jobDataClassObject = jobDataMap.get("jobDataClass");

if(! (jobDataClassObject instanceof Class)) {
try {
jobDataClassObject = Class.forName(jobDataClassObject.toString());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}

Class<? extends JobData> jobDataClass = (Class<? extends JobData>) jobDataClassObject;
JobData jobData = mapper.convertValue(jobDataMap, jobDataClass);
jobDescriptor.setJobData(jobData);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.library.spring.scheduler.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class MongoSyncJobData implements JobData {

private String collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static Date getFutureExecutionDate(List<? extends Trigger> triggers) {
if(Objects.nonNull(triggers)) {
for (Trigger trigger : triggers) {
Date nextFireTime = trigger.getNextFireTime();
if (nextFireTime.compareTo(executionDate) < 0) {
if (nextFireTime != null && nextFireTime.compareTo(executionDate) < 0) {
executionDate = nextFireTime;
}
}
Expand All @@ -116,7 +116,7 @@ public static Date getLastExecutionDate(List<? extends Trigger> triggers) {
if(Objects.nonNull(triggers)) {
for (Trigger trigger : triggers) {
Date previousFireTime = trigger.getPreviousFireTime();
if (previousFireTime.compareTo(executionDate) > 0) {
if (previousFireTime != null && previousFireTime.compareTo(executionDate) > 0) {
executionDate = previousFireTime;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.library.spring.web.advice;

import com.library.spring.web.formatter.DateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;

import java.util.Date;

@ControllerAdvice
public class GlobalBindingInitializer {

/* Initialize a global InitBinder for dates instead of cloning its code in every Controller */

@InitBinder
public void binder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new DateEditor());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.library.spring.web.advice;

import com.library.spring.web.model.ResponseBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.nio.file.AccessDeniedException;
import java.util.UUID;

@Slf4j
@ControllerAdvice(basePackages = {"com.library.spring.web.controller"})
public class ServiceExceptionHandler {

@ExceptionHandler({Exception.class})
protected Object handleInvalidRequest(Exception exception) {

log.error("Service Failure", exception);
HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

if (exception instanceof AccessDeniedException) {
httpStatus = HttpStatus.FORBIDDEN;
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseBean responseBean = createResponseBean(exception);
return new ResponseEntity<>(responseBean, headers, httpStatus);
}

private ResponseBean createResponseBean(Exception exception) {
ResponseBean responseBean = new ResponseBean();
responseBean.setId(UUID.randomUUID().toString());
responseBean.setMessage(exception.getMessage());
responseBean.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
return responseBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.library.spring.web.advice;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Slf4j
@ControllerAdvice(basePackages = {"com.library.spring.web.view"})
public class ViewExceptionHandler {

@ExceptionHandler({Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String applicationError(HttpServletRequest req, Exception exception, final Model model) {
log.error("View Request Failed: " + req.getRequestURI(), exception);
model.addAttribute("exception", exception);
model.addAttribute("url", req.getRequestURL());
model.addAttribute("timestamp", new Date().toString());
return "error";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/batch")
Expand All @@ -34,7 +35,14 @@ public BatchTask jobOperation(@ApiParam(required = true, name = "BatchJobAction
mongoSyncBatchService.updateMongoSyncJob(batchTask);
} else if("delete".equals(batchTask.getAction())) {
mongoSyncBatchService.deleteMongoSyncJob(batchTask);
} else if("restore".equals(batchTask.getAction())) {
} else if("create".equals(batchTask.getAction())) {

if(batchTask.getId() == null) {
Random random = new Random();
int randomNumber = random.ints(0, Integer.MAX_VALUE - 1).findFirst().getAsInt();
batchTask.setId("job" + randomNumber);
}

mongoSyncBatchService.addMongoSyncJob(batchTask);
}

Expand Down
35 changes: 35 additions & 0 deletions src/main/java/com/library/spring/web/formatter/DateEditor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.library.spring.web.formatter;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @see <a href="https://dzone.com/articles/how-serialize-javautildate">How to Serialize Java.util.Date with Jackson JSON Processor</a>
* @see <a href="http://www.baeldung.com/jackson-serialize-dates">Jackson Date</a>
* @see <a href="http://magicmonster.com/kb/prg/java/spring/webmvc/jackson_custom.html">Customise the Jackson JSON mapper</a>
* @see <a href="https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers">Jackson How-To: Custom Serializers</a>
* @see <a href="https://www.concretepage.com/spring/spring-mvc/spring-mvc-validator-with-initbinder-webdatabinder-registercustomeditor-example">@InitBinder</a>
* @see <a href="How To create a global InitBinder in Spring with @ControllerAdvice">Create a global InitBinder in Spring with @ControllerAdvice</a>
*/
public class DateEditor extends PropertyEditorSupport {

public static final String DATE_FORMAT = "dd-MM-yyyy hh:mm:ss";

public void setAsText(String value) {
try {
setValue(new SimpleDateFormat(DATE_FORMAT).parse(value));
} catch (ParseException e) {
setValue(null);
}
}

public String getAsText() {
String s = "";
if (getValue() != null) {
s = new SimpleDateFormat(DATE_FORMAT).format((Date) getValue());
}
return s;
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/library/spring/web/model/BatchTask.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.library.spring.web.model;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class BatchTask {
Expand All @@ -8,6 +10,7 @@ public class BatchTask {
private String collection;
private String service;
private Integer refreshDuration;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private Date lastExecutionDate;
private String action;

Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/library/spring/web/model/ResponseBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.library.spring.web.model;

import java.io.Serializable;

public class ResponseBean implements Serializable {

private String id;
private String message;
private String responseCode;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getResponseCode() {
return responseCode;
}

public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ public List<BatchTask> getAllMongoSyncJobs() throws Exception {
batchTask.setService(jobData.getService());

List<? extends Trigger> triggers = jobService.getTriggers(MONGO_SYNC_JOB_GROUP, job.getName());
batchTask.setLastExecutionDate(TriggerDescriptor.getLastExecutionDate(triggers));
Date lastExecutionDate = TriggerDescriptor.getLastExecutionDate(triggers);
batchTask.setLastExecutionDate(lastExecutionDate);

Date futureExecutionDate = TriggerDescriptor.getFutureExecutionDate(triggers);
LocalDateTime lastExecutionDateTime = LocalDateTime.ofInstant(lastExecutionDate.toInstant(), ZoneId.systemDefault());
LocalDateTime futureExecutionDateTime = LocalDateTime.ofInstant(futureExecutionDate.toInstant(), ZoneId.systemDefault());
long minutes = Duration.between(futureExecutionDateTime, LocalDateTime.now()).toMinutes();
long minutes = Duration.between(futureExecutionDateTime, lastExecutionDateTime).toMinutes();
batchTask.setRefreshDuration((int) minutes);

batchTasks.add(batchTask);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.library.spring.web.controller;
package com.library.spring.web.view;

import com.library.spring.web.model.BatchTask;
import com.library.spring.web.service.MongoSyncBatchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/view")
public class ViewController {

@Autowired
Expand Down
5 changes: 2 additions & 3 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
title.application=Spring Thyme Seed-Starter Manager
title.list=Seed Starter List
title.new=Add new Seed Starter
title.application=Spring MVC Application
title.list=List of Batch Jobs

date.format=MM/dd/yyyy
bool.true=yes
Expand Down
Loading

0 comments on commit 4272dce

Please sign in to comment.