Skip to content

Commit

Permalink
Handle and output errors occurred when calling GreetMe server
Browse files Browse the repository at this point in the history
  • Loading branch information
bhelfert committed May 3, 2017
1 parent d7ead96 commit 30302a5
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 36 deletions.
29 changes: 29 additions & 0 deletions src/main/java/poc/openshift/greetme/web/client/ErrorObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package poc.openshift.greetme.web.client;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.web.client.RestClientException;

import java.util.UUID;

@NoArgsConstructor
@Getter
@Setter
@ToString
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ErrorObject<T> {

private String errorMessage;
private T errorDetails; // T is of type String or List<String>
private String errorId;

public ErrorObject(RestClientException e) {
errorMessage = "Could not communicate with GreetMe server";
errorDetails = (T) e.getMessage();
errorId = UUID.randomUUID().toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,77 @@
package poc.openshift.greetme.web.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import poc.openshift.greetme.web.controller.Greeting;
import poc.openshift.greetme.web.controller.Person;

import java.io.IOException;
import java.util.Collection;
import java.util.function.Supplier;

@Component
@Slf4j
public class GreetMeServerClient {

private RestTemplate serverTemplate;
private String greetingsResourceUrl;
private ObjectMapper objectMapper;

@Autowired
public GreetMeServerClient(@Value("${greetme.server.baseurl}") String greetMeServerBaseUrl,
@Value("${greetme.server.greetings.resource.url}") String greetingsResourceUrl) {
@Value("${greetme.server.greetings.resource.url}") String greetingsResourceUrl,
ObjectMapper objectMapper) {

this.serverTemplate = new RestTemplateBuilder().rootUri(greetMeServerBaseUrl).build();
this.greetingsResourceUrl = greetingsResourceUrl;
this.objectMapper = objectMapper;
}

public Object postPersonToGreet(Person person) {
Supplier<Object> postPersonToGreetCall = () -> serverTemplate.postForObject(greetingsResourceUrl, person, Greeting.class);
return callGreetMeServerWithExceptionHandling(postPersonToGreetCall, "greeting for person: " + person);
}

public Object getGreetings() {
Supplier<Object> getGreetingsCall = () -> serverTemplate.getForObject(greetingsResourceUrl, Collection.class);
return callGreetMeServerWithExceptionHandling(getGreetingsCall, "all greetings");
}

public Greeting postPersonToGreet(Person person) {
log.info("Requesting greeting for {}", person);
Greeting greeting = serverTemplate.postForObject(greetingsResourceUrl, person, Greeting.class);
log.info("Received {}", greeting);
return greeting;
private Object callGreetMeServerWithExceptionHandling(Supplier<?> greetMeServerCall, String callDescription) {
log.info("Requesting {}", callDescription);
Object result;
try {
result = greetMeServerCall.get();
log.info("Received {}: {}", callDescription, result);
}
catch (HttpStatusCodeException e) {
result = deserializeJsonErrorContent(e);
log.error("Received error for requesting {}: {}", callDescription, result);
}
catch (RestClientException e) {
result = new ErrorObject<String>(e);
log.error("Received error for requesting {}: {}", callDescription, result);
}
return result;
}

public Collection<Greeting> getGreetings() {
log.info("Requesting all greetings");
Collection<Greeting> greetings = serverTemplate.exchange(greetingsResourceUrl, HttpMethod.GET, null, new ParameterizedTypeReference<Collection<Greeting>>() {
}).getBody();
log.info("Received all greetings: {}", greetings);
return greetings;
private ErrorObject<?> deserializeJsonErrorContent(HttpStatusCodeException hsce) {
String jsonErrorContent = hsce.getResponseBodyAsString();
try {
return objectMapper.readValue(jsonErrorContent, ErrorObject.class);
}
catch (IOException ioe) {
String message = "Could not deserialize JSON error content to ErrorObject: " + jsonErrorContent;
RuntimeException re = new RuntimeException(message, ioe);
log.error(message, re);
throw re;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import poc.openshift.greetme.web.client.ErrorObject;
import poc.openshift.greetme.web.client.GreetMeServerClient;

import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Controller
@RequestMapping("/")
@SessionAttributes("greetings")
public class GreetingsController {

private static final List<Locale> ALL_LOCALES = Stream.of(Locale.getISOLanguages())
Expand All @@ -31,22 +29,53 @@ public GreetingsController(GreetMeServerClient greetMeServerClient) {
this.greetMeServerClient = greetMeServerClient;
}

@PostMapping
public String addGreeting(@ModelAttribute Person person, Model model) {
greetMeServerClient.postPersonToGreet(person);
addGreetingsAndLocalesToModel(model);
@GetMapping
public String getGreetings(Model model) {
model.addAttribute("allLocales", ALL_LOCALES);

Optional<List<Greeting>> greetings = requestGreetingsAndHandleErrors(model);
if (greetings.isPresent()) {
model.addAttribute("greetings", greetings.get());
}

if (!model.containsAttribute("person")) {
model.addAttribute(new Person("Bob", Locale.ENGLISH.getLanguage()));
}

return "greetings";
}

private void addGreetingsAndLocalesToModel(Model model) {
model.addAttribute("greetings", greetMeServerClient.getGreetings());
model.addAttribute("locales", ALL_LOCALES);
private Optional<List<Greeting>> requestGreetingsAndHandleErrors(Model model) {
Object response = greetMeServerClient.getGreetings();
if (isErrorObject(response)) {
ErrorObject<?> error = (ErrorObject<?>) response;
if (!model.containsAttribute("errors")) {
model.addAttribute("errors", Arrays.asList(error));
}
else {
List<ErrorObject<?>> errorsFromPostRequest = (List<ErrorObject<?>>) model.asMap().get("errors");
List<ErrorObject<?>> errors = new ArrayList<>(errorsFromPostRequest);
errors.add(error);
model.addAttribute("errors", errors);
}
return Optional.empty();
}
return Optional.of((List<Greeting>) response);
}

@GetMapping
public String getGreetings(Model model) {
addGreetingsAndLocalesToModel(model);
model.addAttribute("person", new Person("Bob", Locale.ENGLISH.getLanguage()));
return "greetings";
private boolean isErrorObject(Object response) {
return (response instanceof ErrorObject<?>);
}

@PostMapping
public String addGreeting(@ModelAttribute Person person, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute(person);

Object response = greetMeServerClient.postPersonToGreet(person);
if (isErrorObject(response)) {
redirectAttributes.addFlashAttribute("errors", Arrays.asList((ErrorObject<?>) response));
}

return "redirect:/";
}
}
5 changes: 4 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ greetme.server.baseurl=http://localhost:9090
greetme.server.greetings.resource.url=/greetings

# Allow unsecured access to all REST resources but Actuator endpoints
security.basic.path=
security.basic.path=

# Disable URL rewriting by allowing usage of cookies only
server.session.tracking-modes=cookie
7 changes: 5 additions & 2 deletions src/main/resources/templates/greetings.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
<form action="#" th:action="@{/}" th:object="${person}" method="post">
<p>My name is: <input type="text" th:field="*{name}" /></p>
<p>I am speaking: <select th:field="*{nativeLanguageCode}">
<option th:each="locale : ${locales}"
<option th:each="locale : ${allLocales}"
th:value="${locale.getLanguage()}"
th:text="${locale.getDisplayLanguage(T(java.util.Locale).ENGLISH)}">
</option>
</select>
</p>
<p><input type="submit" value="Greet Me!" /></p>
</form>
<ul>
<ul th:unless="${#lists.isEmpty(errors)}">
<li th:each="error : ${errors}" th:text="${error.toString()}"></li>
</ul>
<ul th:unless="${#lists.isEmpty(greetings)}">
<li th:each="greeting : ${greetings}" th:text="${greeting.message}"></li>
</ul>
</body>
Expand Down

0 comments on commit 30302a5

Please sign in to comment.