MessageSourceManagementController.java
/*
* Copyright 2000-2010 namics ag. All rights reserved.
*/
package com.namics.oss.spring.support.i18n.web;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
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.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.namics.oss.spring.support.i18n.exception.I18nException;
import com.namics.oss.spring.support.i18n.model.MessageResourceEntry;
import com.namics.oss.spring.support.i18n.service.MessageManagementService;
import com.namics.oss.spring.support.i18n.service.ReloadService;
/**
* MessageSourceManagementController handles management of labels for web purpose. Please be aware that all URLs used in this controller should be
* secured by a security framework like Spring Security to prevent misuse of the functionality.
*
* @author aschaefer, namics ag
* @since Namics commons i18n 1.0 - Oct 25, 2010
*/
@Controller("messageSourceManagementController")
@RequestMapping("/messages/admin")
public class MessageSourceManagementController
{
@Autowired(required = true)
@Qualifier("messageManagementService")
private MessageManagementService managementService;
@Autowired(required = false)
@Qualifier("messageSourceReloadService")
private ReloadService reloadService;
protected static final String CODE = "code";
protected static final String RESOURCE = "resource";
protected static final String LANGS = "langs";
protected static final String MESSAGES = "messages";
protected static final String SUCCESS = "success";
protected static final String ERROR = "error";
protected static final String REDIRECT_UPLOAD = "redirect:upload.html?";
protected static final String REDIRECT_EDIT = "redirect:edit.html?";
protected static final String REDIRECT_INDEX = "redirect:index.html?";
private String listView = "messages.admin.list";
private String uploadView = "messages.admin.upload";
private String editView = "messages.admin.edit";
private String putSuccessView = REDIRECT_INDEX + SUCCESS + "=success.admin.messages.put.success";
private String putFailView = REDIRECT_EDIT + ERROR + "=error.admin.messages.put.error";
private String confirmDelete = "messages.admin.delete.confirm";
private String uploadSuccessView = REDIRECT_UPLOAD + SUCCESS + "=success.admin.messages.upload.success";
private String uploadFailView = REDIRECT_UPLOAD + ERROR + "=error.admin.messages.upload.fail";
private String exportErrorView = REDIRECT_INDEX + ERROR + "=error.admin.messages.export.fail";
private String deleteFailView = REDIRECT_INDEX + ERROR + "=error.admin.messages.delete.fail";
private String deleteAbortView = "redirect:index.html";
private String deleteSuccessView = REDIRECT_INDEX + SUCCESS + "=success.admin.messages.delete.success";
private String reloadFailView = REDIRECT_INDEX + ERROR + "=error.admin.messages.reload.fail";
private String reloadSuccessView = REDIRECT_INDEX + SUCCESS + "=success.admin.messages.reload.success";
private static final Logger LOG = LoggerFactory.getLogger(MessageSourceManagementController.class);
private String imagesDir = "/src/main/resources/images/";
/**
* Triggers the reload method on the corresponding Service. Method Requires {@link ReloadService} to be configured. If it is not, nothing will
* happen.
*
* @return
*/
@RequestMapping("/reload.html")
public String reload()
{
if (this.reloadService != null)
{
try
{
this.reloadService.reload();
return this.reloadSuccessView;
}
catch (Exception e)
{
LOG.error("Exception during reloading of message sources" + e);
}
}
return this.reloadFailView;
}
/**
* Displays a list of all labels in system.
*
* @param success
* an additional success message to display
* @param error
* and additional error messare to display
* @return the model and view to be assembled by the framework
*/
@RequestMapping("/index.html")
public ModelAndView list( @RequestParam(value = SUCCESS, required = false) String success,
@RequestParam(value = ERROR, required = false) String error)
{
ModelAndView mav = new ModelAndView(this.listView);
Map<String, List<MessageResourceEntry>> messages = this.managementService.getAllMessagesGrouped();
List<Locale> langs = this.managementService.getAvailableLanguages();
mav.addObject(MESSAGES, messages);
mav.addObject(LANGS, langs);
if (StringUtils.hasText(error))
{
mav.addObject(ERROR, error);
}
if (StringUtils.hasText(success))
{
mav.addObject(SUCCESS, success);
}
return mav;
}
/**
* Displays a confirmation Dialog for delte of a message.
*
* @param code
* the message code to be deleted
* @return the model and view to be assembled by the framework
*/
@RequestMapping("/confirmDelete.html")
public ModelAndView confirmDelete(@RequestParam(CODE) String code)
{
MessageResourceEntry message = null;
try
{
message = this.managementService.getMessage(code);
}
catch (I18nException e)
{
return new ModelAndView(this.deleteFailView);
}
if (message != null)
{
ModelAndView mav = new ModelAndView(this.confirmDelete);
mav.addObject(RESOURCE, message);
return mav;
}
else
{
return new ModelAndView(this.deleteFailView);
}
}
/**
* Finally deletes a message in the system.
*
* @param code
* code of message to be deleted
* @param confirm
* the confirmation check made in confirmation dialog
* @return the success/fail view name to be used by framework.
*/
@RequestMapping("/delete.htm")
public String delete( @RequestParam(CODE) String code,
@RequestParam("confirm") boolean confirm)
{
if (!confirm)
{
return this.deleteAbortView;
}
try
{
this.managementService.deleteMessage(code);
}
catch (I18nException e)
{
return this.deleteFailView;
}
return this.deleteSuccessView;
}
/**
* Displays a file upload dialog for uploading an excel file.
*
* @param success
* an optional success message to be displayed
* @param error
* an optional error message to be displayed
* @param model
* the model were to put the messages
* @return the view name of the dialog
*/
@RequestMapping("/upload.html")
public String uploadView( @RequestParam(value = SUCCESS, required = false) String success,
@RequestParam(value = ERROR, required = false) String error,
Model model)
{
if (StringUtils.hasText(error))
{
model.addAttribute(ERROR, error);
}
if (StringUtils.hasText(success))
{
model.addAttribute(SUCCESS, success);
}
return this.uploadView;
}
/**
* File upload method processing a multipart file upload form and puts the excel file content in the system.
*
* @param file
* file upload form
* @return success/fail view to be shown by framework
*/
@RequestMapping(value = "/uploadFile.html", method = RequestMethod.POST)
public String uploadFile(@RequestParam("file") MultipartFile file)
{
try
{
InputStream input = file.getInputStream();
this.managementService.importFromExcel(input);
}
catch (Exception e)
{
LOG.error("faild to upload file", e);
return this.uploadFailView;
}
return this.uploadSuccessView;
}
/**
* Exports all messages in the system to an excel file.
*
* @param timestamp
* the timestamp, when the file link was generated (not a releavant parameter).
* @param type
* the requested file type, currently <code>xls</code> and <code>xlsx</code> are supported
* @param request
* the request obejct
* @param response
* the response object to write the data to
* @return the view name in case of an error, null when successful
*/
@RequestMapping("/messages-{time}.{type}")
public String export( @PathVariable("time") String timestamp,
@PathVariable("type") String type,
HttpServletRequest request,
HttpServletResponse response)
{
try
{
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "private");
if (type != null && "xls".equals(type))
{
response.setContentType("application/vnd.ms-excel");
this.managementService.exportToExcel97(response.getOutputStream());
}
else if (type != null && "xlsx".equals(type))
{
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
this.managementService.exportToExcel2007(response.getOutputStream());
}
else if (type != null && "sql".equals(type))
{
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
this.managementService.exportToText(response.getOutputStream());
}
else
{
return this.exportErrorView;
}
}
catch (IOException e)
{
LOG.error("IO exception occured " + e);
LOG.info("IO exception occured ", e);
return this.exportErrorView;
}
catch (I18nException e)
{
LOG.error("I18nException occured " + e);
LOG.info("I18nException occured ", e);
return this.exportErrorView;
}
catch (IllegalArgumentException e)
{
LOG.error("IllegalArgumentException occured " + e);
LOG.info("IllegalArgumentException occured ", e);
return this.exportErrorView;
}
return null;
}
/**
* Displays an edit dialog to the user, prefilled with the optional message code.
*
* @param code
* optional message code to load data of an existing message
* @param error
* an optional error message to be displayed (validation...)
* @param success
* an optional success message to be displayed
* @return the Model and View required to display the form
*/
@RequestMapping("/edit.html")
public ModelAndView edit( @RequestParam(value = CODE, required = false) String code,
@RequestParam(value = ERROR, required = false) String error,
@RequestParam(value = SUCCESS, required = false) String success)
{
ModelAndView mav = new ModelAndView(this.editView);
if (StringUtils.hasText(code))
{
try
{
MessageResourceEntry entry = this.managementService.getMessage(code);
if (entry != null)
{
mav.addObject(RESOURCE, entry);
}
}
catch (I18nException e)
{
LOG.error("Problem resolving code from backend " + e + " " + e.getCause());
}
}
if (StringUtils.hasText(error))
{
mav.addObject(ERROR, error);
}
if (StringUtils.hasText(success))
{
mav.addObject(SUCCESS, success);
}
mav.addObject(LANGS, this.managementService.getAvailableLanguages());
return mav;
}
/**
* Method inserts a new/updates an existing message in the system based on the submitted edit form.
*
* @param entry
* the message bound from the post
* @param errors
* Errors that occured during binding on the bean
* @return the success/error view, might be a redirect.
*/
@RequestMapping("/put.html")
public String put( MessageResourceEntry entry,
BindingResult errors)
{
if (!errors.hasErrors() && entry != null && StringUtils.hasText(entry.getCodeId()) && entry.size() > 0)
{
try
{
for (Entry<Locale, String> msg : entry.getNameMappings().entrySet())
{
if (StringUtils.hasLength(msg.getValue()))
{
this.managementService.putMessage(entry.getCodeId(), msg.getKey(), msg.getValue(), entry.getType());
}
}
return this.putSuccessView;
}
catch (I18nException e)
{
LOG.error("Error putting message to backend" + e + " " + e.getCause());
}
catch (IllegalArgumentException e)
{
LOG.error("Error putting message to backend " + e + " " + e.getCause());
}
return this.putFailView + "&" + CODE + "=" + entry.getCodeId();
}
return this.putFailView;
}
/**
* Method resolves file provided by name as ResourceStream from classloader and writes its content to the outputstream provided. Additionally a
* cache control header is set on a provided response object.
*
* @param name
* filename
* @param output
* outputstream
* @param response
* respons object to set cache control header in
*/
@RequestMapping(value = "/image/{name}", method = RequestMethod.GET)
public void image( @PathVariable("name") String name,
OutputStream output,
HttpServletResponse response)
{
try
{
response.setHeader("Cache-Control", "public");
FileCopyUtils.copy(this.getClass().getResourceAsStream(this.imagesDir + name), output);
}
catch (IOException e)
{
return;
}
catch (IllegalArgumentException e)
{
return;
}
}
// CHECKSTYLE:OFF
/** Setter for managementService. @param managementService the managementService to set */
public void setManagementService(MessageManagementService managementService)
{
this.managementService = managementService;
}
/** Setter for listView. @param listView the listView to set */
public void setListView(String listView)
{
this.listView = listView;
}
/** Setter for uploadView. @param uploadView the uploadView to set */
public void setUploadView(String uploadView)
{
this.uploadView = uploadView;
}
/** Setter for editView. @param editView the editView to set */
public void setEditView(String editView)
{
this.editView = editView;
}
/** Setter for putSuccessView. @param putSuccessView the putSuccessView to set */
public void setPutSuccessView(String putSuccessView)
{
this.putSuccessView = putSuccessView;
}
/** Setter for putFailView. @param putFailView the putFailView to set */
public void setPutFailView(String putFailView)
{
this.putFailView = putFailView;
}
/** Setter for confirmDelete. @param confirmDelete the confirmDelete to set */
public void setConfirmDelete(String confirmDelete)
{
this.confirmDelete = confirmDelete;
}
/** Setter for uploadSuccessView. @param uploadSuccessView the uploadSuccessView to set */
public void setUploadSuccessView(String uploadSuccessView)
{
this.uploadSuccessView = uploadSuccessView;
}
/** Setter for uploadFailView. @param uploadFailView the uploadFailView to set */
public void setUploadFailView(String uploadFailView)
{
this.uploadFailView = uploadFailView;
}
/** Setter for exportErrorView. @param exportErrorView the exportErrorView to set */
public void setExportErrorView(String exportErrorView)
{
this.exportErrorView = exportErrorView;
}
/** Setter for deleteFailView. @param deleteFailView the deleteFailView to set */
public void setDeleteFailView(String deleteFailView)
{
this.deleteFailView = deleteFailView;
}
/** Setter for deleteAbortView. @param deleteAbortView the deleteAbortView to set */
public void setDeleteAbortView(String deleteAbortView)
{
this.deleteAbortView = deleteAbortView;
}
/** Setter for deleteSuccessView. @param deleteSuccessView the deleteSuccessView to set */
public void setDeleteSuccessView(String deleteSuccessView)
{
this.deleteSuccessView = deleteSuccessView;
}
/** Setter for imagesDir. @param imagesDir the imagesDir to set */
public void setImagesDir(String imagesDir)
{
this.imagesDir = imagesDir;
}
/** Setter for reloadService. @param reloadService the reloadService to set */
public void setReloadService(ReloadService reloadService)
{
this.reloadService = reloadService;
}
/** Setter for reloadSuccessView. @param reloadSuccessView the reloadSuccessView to set */
public void setReloadSuccessView(String reloadSuccessView)
{
this.reloadSuccessView = reloadSuccessView;
}
/** Setter for reloadFailView. @param reloadFailView the reloadFailView to set */
public void setReloadFailView(String reloadFailView)
{
this.reloadFailView = reloadFailView;
}
// CHECKSTYLE:ON
}