package no.niths.application.rest; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletResponse; import no.niths.application.rest.exception.ObjectNotFoundException; import no.niths.application.rest.interfaces.GenericRESTController; import no.niths.application.rest.lists.ListAdapter; import no.niths.common.constants.SecurityConstants; import no.niths.common.helpers.LazyFixer; import no.niths.common.helpers.ValidationHelper; import no.niths.services.interfaces.GenericService; import org.hibernate.TransientObjectException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; /** * Abstract class that holds logic for CRUD operations on a given domain type * * To add new controllers, create an interface that extends * GenericRESTController<your_domain>, then create a class that extends * AbstractRESTControllerImpl<your_domain> and implements YourInterface * * Autowire your service and create a new list in * package no.niths.application.rest.list and * Override the two methods: * public GenericService<Your_domain> getService() public * ListAdapter<Your_domain> getList() to return your service and your list * * Add extra methods by defining them in the interface and override them in the * implementation class Call super.methodName(parameter) to execute CRUD methods * * @param <T> * The domain type * */ public abstract class AbstractRESTControllerImpl<T> extends RESTExceptionHandler implements GenericRESTController<T> { private static final Logger logger = LoggerFactory .getLogger(AbstractRESTControllerImpl.class); private LazyFixer<T> nullifier = new LazyFixer<T>(); /** * Persists the domain * <p> * Usage in own class: * </p> * <pre> * {@code * PreAuthorize(SecurityConstants.ONLY_ADMIN)//Optional security public * void create(@RequestBody Your_domain domain){ * super.create(domain); * } * * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs * method = RequestMethod.POST * value = HttpStatus.CREATED * reason = "Created" * } * </pre> * * @param domain the domain to persist * */ @Override @RequestMapping(method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.CREATED, reason = "Created") @PreAuthorize(SecurityConstants.ONLY_ADMIN) @ResponseBody public T create(@RequestBody T domain, HttpServletResponse res) { logger.debug(domain +""); Long id = getService().create(domain); T domainObject = getService().getById(id); res.addHeader( "location", String.valueOf(id)); return domainObject; } /** * Returns the domain object with the given id * <p> * Usage in your own class: * </p> * <pre> * {@code * Override * public You_Domain getById(@PathVariable Long id) { * return super.getById(id); * } * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs/{id} * value = "{id}", * method = RequestMethod.GET, * headers = RESTConstants.ACCEPT_HEADER * } * </pre> * @param id * the id of the domain object * @return the domain object * @throws ObjectNotFoundException * when object is not found * */ @Override @RequestMapping(value = "{id}", method = RequestMethod.GET, headers = RESTConstants.ACCEPT_HEADER) @ResponseBody public T getById(@PathVariable Long id) { T domain = getService().getById(id); ValidationHelper.isObjectNull(domain); nullifier.clearSubRelations(domain); logger.debug(domain.toString()); return domain; } /** * * Returns an array list with all domain objects of the type * <p> * Usage in your own class: * </p> * <pre> * {@code * Override * PreAuthorize(SecurityConstants.ONLY_ADMIN) //Optional security * public ArrayList<Your_Domain> getAll(Your_Domain domain) { * ArrayList<Your_Domain> all = super.getAll(domain); * return roles; * } * * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs * method = RequestMethod.GET * headers = RESTConstants.ACCEPT_HEADER * } * </pre> * @param domain * will search the DB for instances with the same attributes, if * null, all will be returned * @return List of all domain objects * */ @Override @RequestMapping(method = RequestMethod.GET, headers = RESTConstants.ACCEPT_HEADER) @ResponseBody public ArrayList<T> getAll(T domain) { renewList(getService().getAll(domain)); return getList(); } /** * * Returns an array list with all exams like getAll(domain), * but also supports pagination * <pre> * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs/paginated/{firstResult}/{maxResults} * method = RequestMethod.GET * headers = RESTConstants.ACCEPT_HEADER * </pre> * * @param domain object with attributes to search for * @param firstResult the first result in the result set * @param maxResults the number of result to return */ @Override @RequestMapping(value = "paginated/{firstResult}/{maxResults}", method = RequestMethod.GET, headers = RESTConstants.ACCEPT_HEADER) @ResponseBody public ArrayList<T> getAll(T domain,@PathVariable int firstResult, @PathVariable int maxResults) { renewList(getService().getAll(domain, firstResult, maxResults)); return getList(); } /** * Update the domain object * * * Usage in your own class: * * <pre> * {@code * Override * PreAuthorize(SecurityConstants.ONLY_ADMIN)//Optional security public * void update(@RequestBody Your_domain domain){ * super.update(domain); * } * * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs * method = RequestMethod.PUT * value = HttpStatus.OK, * reason = "Update OK" * } * </pre> * * @param domain * the domain * @throws ObjectNotFoundException * when object is not found * */ @Override @RequestMapping(method = RequestMethod.PUT) @ResponseStatus(value = HttpStatus.OK, reason = "Update OK") @PreAuthorize(SecurityConstants.ONLY_ADMIN) public void update(T domain) { logger.debug("Update"); logger.debug(domain + ""); try { getService().mergeUpdate(domain); } catch (TransientObjectException e) { throw new ObjectNotFoundException(e.getMessage().toString()); } } /** * {@inheritDoc} */ public void renewList(List<T> list) { getList().clear(); getList().addAll(list); getList().setData(getList()); // Used for XML marshaling ValidationHelper.isListEmpty(getList()); nullifier.clearRelations(getList()); } /** * Deletes the domain object with the given id * * * Usage in your own class: * * <pre> * {@code * Override * PreAuthorize(SecurityConstants.ONLY_ADMIN)//Optional security public * void hibernateDelete(@PathVariable long id){ * super.hibernateDelete(id); * } * * URL = {@value no.niths.common.constants.MiscConstants#NITHS_BASE_DOMAIN}/YOUR_DOMAINs/{id} * RequestMapping(value = "{id}", method = RequestMethod.DELETE) * ResponseStatus(value = HttpStatus.OK, reason = "Deleted") * } * </pre> * * @param id * the if of the domain object to be deleted */ @Override @RequestMapping(value = "{id}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK, reason = "Deleted") @PreAuthorize(SecurityConstants.ONLY_ADMIN) public void delete(@PathVariable long id) { try { getService().hibernateDelete(id); } catch (HibernateOptimisticLockingFailureException e) { throw new ObjectNotFoundException("Could not find the object"); } } /** * Represents the service * * Must override in own implementation * * <pre> * {@code * Override * public GenericService<Your_domain> getService() { * return yourService; * } * } * </pre> * * @return the service of a given type */ public abstract GenericService<T> getService(); /** * Adapter for XML presentation of a list * * Must override in own implementation * * <pre> * {@code * Override * public ListAdapter<Your_Domain> getList() { * return your_domainList; * } * } * </pre> * * @return Array list of a given type */ public abstract ListAdapter<T> getList(); }