/*
* Copyright 2015 MV Informática.
*
* 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 br.com.mv.modulo.web;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import br.com.mv.modulo.business.GenericCrudBusiness;
import br.com.mv.modulo.exception.GenericMessages;
import br.com.mv.modulo.model.type.EnumTipoMensagem;
import br.com.mv.modulo.repository.GenericCrudRepository;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public abstract class GenericCrudController<T> {
protected Page<T> page;
protected final GenericMessages genericMessages;
protected final GenericCrudBusiness<T, GenericCrudRepository<T>> genericCrudBusiness;
private static final int DEFAULT_INITIAL_PAGINATION_PAGE = 0;
private static final int DEFAULT_PAGINATION_SIZE = 7;
private Type type = Arrays.stream(((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()).findFirst().get();
private Class<?> clazz = (Class<?>) type;
@Autowired
@SuppressWarnings({ "rawtypes", "unchecked" })
public GenericCrudController(GenericMessages genericMessages, GenericCrudBusiness genericCrudBusiness) {
this.genericMessages = genericMessages;
this.genericCrudBusiness = genericCrudBusiness;
}
@RequestMapping(value={"/", "/list"}, method = RequestMethod.GET)
public String tolist(Model model) {
instantiateModel(model);
page = null;
model.addAttribute("page", page);
return getListPageName();
}
@RequestMapping(value="/list", method = RequestMethod.POST)
public String findModel(@ModelAttribute T t, Model model) {
listModel(t, DEFAULT_INITIAL_PAGINATION_PAGE, DEFAULT_PAGINATION_SIZE, model);
return getListPageName();
}
@RequestMapping(value="/listPaginated", method = RequestMethod.GET)
public String findModelPaginated(@ModelAttribute T t,
@RequestParam(value = "page", defaultValue = "") Integer page,
@RequestParam(value = "size", defaultValue = "") Integer size,
@RequestParam(value = "idToRender", defaultValue = "") String idToRender,
Model model,
HttpServletRequest request) {
listModel(t, page, size, model);
if(isAjax(request)) {
return getListPageName() + " :: #" + idToRender;
} else {
return getListPageName();
}
}
protected boolean isAjax(HttpServletRequest request) {
String header = request.getHeader("x-requested-with");
return header != null && "XMLHttpRequest".equals(header);
}
private void listModel(T t, Integer page, Integer size, Model model) {
this.page = genericCrudBusiness.listModel(t, getPageable(page, size));
model.addAttribute("page", this.page);
model.addAttribute(getModelName(), t);
}
@RequestMapping(value="/new", method = RequestMethod.GET)
public String toNewForm(Model model) {
instantiateModel(model);
return getFormPageName();
}
@RequestMapping(value="/delete", method = RequestMethod.GET)
public String remove(@RequestParam(value = "id", required = true) Long id, RedirectAttributes redirectAttrs) {
try {
genericCrudBusiness.delete(id);
redirectAttrs.addFlashAttribute(EnumTipoMensagem.SUCESSO.getDescricao(), genericMessages.getDeleteSuccess());
} catch (IllegalArgumentException e) {
redirectAttrs.addFlashAttribute(EnumTipoMensagem.ERRO.getDescricao(), genericMessages.getNotFound());
log.trace("Não foi encontrado:", e);
} catch (Exception e) {
redirectAttrs.addFlashAttribute(EnumTipoMensagem.ERRO.getDescricao(), e.getMessage());
log.error("Erro ao salvar:", e);
}
return getReturnToListURL();
}
@RequestMapping(value="/edit", method = RequestMethod.GET)
public String toEditForm(@RequestParam(value = "id", required = true) T t, Model model) {
model.addAttribute(getModelName(), t);
return getFormPageName();
}
@RequestMapping(value="/save", method = RequestMethod.POST)
public String save(@ModelAttribute @Valid T t, final BindingResult bindingResult,
RedirectAttributes redirectAttrs, Model model, SessionStatus status) {
if (bindingResult.hasErrors()) {
model.addAttribute("org.springframework.validation.BindingResult.strategy", bindingResult);
model.addAttribute(getModelName(), t);
return getFormPageName();
} else {
try {
genericCrudBusiness.save(t);
status.setComplete();
redirectAttrs.addFlashAttribute(EnumTipoMensagem.SUCESSO.getDescricao(), genericMessages.getSaveSuccess());
} catch (DataIntegrityViolationException e) {
redirectAttrs.addFlashAttribute(EnumTipoMensagem.ERRO.getDescricao(), e.getMessage());
log.trace("Erro de integridade:", e);
} catch (Exception e) {
redirectAttrs.addFlashAttribute(EnumTipoMensagem.ERRO.getDescricao(), e.getMessage());
log.error("Erro ao salvar:", e);
}
}
return getReturnToListURL();
}
protected String getReturnToListURL() {
return "redirect:/" + getModelName() + "/returnToList";
}
private String getModelName() {
return StringUtils.uncapitalize(clazz.getSimpleName());
}
@RequestMapping(value={"/returnToList"}, method = RequestMethod.GET)
public String returnToListAndFindAll(Model model) {
this.page = genericCrudBusiness.listModel(createNewObject(), getPageable(DEFAULT_INITIAL_PAGINATION_PAGE, DEFAULT_PAGINATION_SIZE));
instantiateModel(model);
model.addAttribute("page", this.page);
return getListPageName();
}
protected void instantiateModel(Model model) {
model.addAttribute(getModelName(), createNewObject());
}
@SuppressWarnings("unchecked")
private T createNewObject() {
T t = null;
try {
t = (T) clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
log.error("Erro ao instanciar um objeto:", e);
}
return t;
}
protected Pageable getPageable(Integer page, Integer size) {
Pageable pageable;
if (StringUtils.isNotEmpty(getFieldToSortList())) {
pageable = new PageRequest(page, size, Sort.DEFAULT_DIRECTION, getFieldToSortList());
} else {
pageable = new PageRequest(page, size);
}
return pageable;
}
protected String getFieldToSortList() {
return null;
}
protected int getDefaultPaginationSize() {
return DEFAULT_PAGINATION_SIZE;
}
protected String getListPageName() {
return getModelUrlMapping() + "List";
}
protected String getFormPageName() {
return getModelUrlMapping() + "Form";
}
private String getModelUrlMapping() {
return getModelName() + "/" + getModelName();
}
}