/**
* Copyright 2010-2016 Ralph Schaer <ralphschaer@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.ralscha.extdirectspring.bean;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.MessageSource;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.support.RequestContextUtils;
import ch.ralscha.extdirectspring.controller.Configuration;
import ch.ralscha.extdirectspring.controller.RouterController;
import ch.ralscha.extdirectspring.util.ExtDirectSpringUtil;
/**
* An utility class that helps building the response for a FORM_POST method. The response
* is written directly into the {@link HttpServletResponse#getOutputStream()} with
* {@link #buildAndWrite()}.
*/
public class ExtDirectResponseBuilder {
private final ExtDirectResponse extDirectResponse;
private final HttpServletRequest request;
private final HttpServletResponse response;
private final Map<String, Object> result;
private Class<?> jsonView;
/**
* Creates a builder that builds and writes the response of a FORM_POST method. Sets
* the successful flag to true, can be changed with the {@link #successful()} and
* {@link #unsuccessful()} methods.
*
* @param request the current http servlet request object
* @param response the current http servlet response object
*/
public ExtDirectResponseBuilder(HttpServletRequest request,
HttpServletResponse response) {
this.request = request;
this.response = response;
this.extDirectResponse = new ExtDirectResponse(request);
this.result = new HashMap<String, Object>();
successful();
this.extDirectResponse.setResult(this.result);
}
/**
* Creates a builder instance.
*
* @see #ExtDirectResponseBuilder(HttpServletRequest, HttpServletResponse)
*
* @param request the current http servlet request object
* @param response the current http servlet response object
*
* @return the created builder instance
*/
public static ExtDirectResponseBuilder create(HttpServletRequest request,
HttpServletResponse response) {
return new ExtDirectResponseBuilder(request, response);
}
/**
* Creates an "exception" response. Calls {@link ExtDirectResponse#setType(String)}
* with a value of "exception". Calls {@link ExtDirectResponse#setMessage(String)} and
* {@link ExtDirectResponse#setWhere(String)} according to the {@link Configuration}.
*
* This is a method primarily used for implementations of
* {@link HandlerExceptionResolver}.
*
* @param exception the exception that was thrown.
* @return this instance
*/
public ExtDirectResponseBuilder setException(Exception exception) {
unsuccessful();
WebApplicationContext ctx = RequestContextUtils
.findWebApplicationContext(this.request);
Configuration configuration;
try {
configuration = ctx.getBean(Configuration.class);
}
catch (NoSuchBeanDefinitionException e) {
configuration = new Configuration();
}
this.extDirectResponse.setType("exception");
this.extDirectResponse.setMessage(configuration.getMessage(exception));
if (configuration.isSendStacktrace()) {
this.extDirectResponse.setWhere(ExtDirectSpringUtil.getStackTrace(exception));
}
else {
this.extDirectResponse.setWhere(null);
}
return this;
}
/**
* Adds an "errors" property in the response if there are any errors in the
* bindingResult. Sets the success flag to false if there are errors.
*
* @param bindingResult
* @return this instance
*/
public ExtDirectResponseBuilder addErrors(BindingResult bindingResult) {
addErrors(null, null, bindingResult);
return this;
}
/**
* Adds an "errors" property in the response if there are any errors in the
* bindingResult. Sets the success flag to false if there are errors.
*
* @param locale
* @param messageSource
* @param bindingResult
* @return this instance
*/
public ExtDirectResponseBuilder addErrors(Locale locale, MessageSource messageSource,
final BindingResult bindingResult) {
if (bindingResult != null && bindingResult.hasFieldErrors()) {
Map<String, List<String>> errorMap = new HashMap<String, List<String>>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
String message = fieldError.getDefaultMessage();
if (messageSource != null) {
Locale loc = locale != null ? locale : Locale.getDefault();
message = messageSource.getMessage(fieldError.getCode(),
fieldError.getArguments(), loc);
}
List<String> fieldErrors = errorMap.get(fieldError.getField());
if (fieldErrors == null) {
fieldErrors = new ArrayList<String>();
errorMap.put(fieldError.getField(), fieldErrors);
}
fieldErrors.add(message);
}
if (errorMap.isEmpty()) {
addResultProperty("success", Boolean.TRUE);
}
else {
addResultProperty("errors", errorMap);
addResultProperty("success", Boolean.FALSE);
}
}
return this;
}
/**
* Add additional property to the response.
*
* @param key the key of the property
* @param value the value of this property
* @return this instance
*/
public ExtDirectResponseBuilder addResultProperty(String key, Object value) {
this.result.put(key, value);
return this;
}
/**
* Sets success flag to true.
*
* @return this instance
*/
public ExtDirectResponseBuilder successful() {
this.result.put("success", Boolean.TRUE);
return this;
}
/**
* Sets success flag to false.
*
* @return this instance
*/
public ExtDirectResponseBuilder unsuccessful() {
this.result.put("success", Boolean.FALSE);
return this;
}
/**
* Sets success flag to the provided parameter.
*
* @param flag the new success value
* @return this instance
*/
public ExtDirectResponseBuilder setSuccess(boolean flag) {
this.result.put("success", flag);
return this;
}
/**
* Sets a specific JSON View (filter) that Jackson uses to serialize the response.
*
* @param jsonView
*/
public void setJsonView(Class<?> jsonView) {
this.jsonView = jsonView;
}
/**
* Builds and writes the response into the OutputStream of {@link HttpServletResponse}
* . This methods has to be called at the end of a FORM_POST method.
*/
public void buildAndWrite() {
try {
RouterController routerController = RequestContextUtils
.findWebApplicationContext(this.request)
.getBean(RouterController.class);
routerController.writeJsonResponse(this.request, this.response,
this.extDirectResponse, this.jsonView);
}
catch (IOException e) {
LogFactory.getLog(getClass()).error("buildAndWrite", e);
throw new RuntimeException(e);
}
}
}