X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/cd7fb617d6f3db9212634e2cc1b43b0bdb8091d7..b73b424de63c9a3672ad61fae004a88109fcd2e9:/cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/BaseController.java diff --git a/cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/BaseController.java b/cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/BaseController.java index fc23d82a5b..80202e8e5e 100644 --- a/cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/BaseController.java +++ b/cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/BaseController.java @@ -1,3 +1,4 @@ +// $Id$ /** * Copyright (C) 2007 EDIT * European Distributed Institute of Taxonomy @@ -9,19 +10,41 @@ package eu.etaxonomy.cdm.remote.controller; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import org.apache.log4j.Logger; -import org.springframework.util.Assert; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.hibernate.mapping.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +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.servlet.ModelAndView; import eu.etaxonomy.cdm.api.service.IService; +import eu.etaxonomy.cdm.api.service.pager.Pager; +import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl; +import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper; import eu.etaxonomy.cdm.model.common.CdmBase; +import eu.etaxonomy.cdm.model.reference.INomenclaturalReference; +import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor; /** * based on org.cateproject.controller.common @@ -32,68 +55,337 @@ import eu.etaxonomy.cdm.model.common.CdmBase; * @param */ -public abstract class BaseController> { - - public static final Logger logger = Logger.getLogger(BaseController.class); - - protected static final Integer DEFAULT_PAGE_SIZE = 30; - +public abstract class BaseController> extends AbstractController { + protected SERVICE service; - protected Pattern uuidParameterPattern = null; - - protected void setUuidParameterPattern(String pattern){ - uuidParameterPattern = Pattern.compile(pattern); - } + protected Class baseClass; public abstract void setService(SERVICE service); - /**@InitBinder + public BaseController (){ + + Type superClass = this.getClass().getGenericSuperclass(); + if(superClass instanceof ParameterizedType){ + ParameterizedType parametrizedSuperClass = (ParameterizedType) superClass; + Type[] typeArguments = parametrizedSuperClass.getActualTypeArguments(); + + if(typeArguments.length > 1 && typeArguments[0] instanceof Class){ + baseClass = (Class) typeArguments[0]; + } else { + logger.error("unable to find baseClass"); + } + } + } + + @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor()); - //TODO do we need this one?: binder.registerCustomEditor(Class.class, new ClassPropertyEditor()); } - */ - - protected UUID readValueUuid(HttpServletRequest request) { - String path = request.getServletPath(); - if(path != null) { - Matcher uuidMatcher = uuidParameterPattern.matcher(path); - if(uuidMatcher.matches() && uuidMatcher.groupCount() > 0){ - try { - UUID uuid = UUID.fromString(uuidMatcher.group(1)); - return uuid; - } catch (Exception e) { - logger.warn(uuidMatcher.group(1) + "is not a uuid"); + + //TODO implement bulk version of this method + @RequestMapping(method = RequestMethod.GET) + public T doGet(@PathVariable("uuid") UUID uuid, + HttpServletRequest request, + HttpServletResponse response) throws IOException { + if(request != null) + logger.info("doGet() " + request.getServletPath()); + T obj = (T) getCdmBaseInstance(uuid, response, initializationStrategy); + return obj; + } + + /** + * @param uuid + * @param request + * @param response + * @return + * @throws IOException + * + * TODO implement bulk version of this method + */ + @RequestMapping(value = "*", method = RequestMethod.GET) + public ModelAndView doGetMethod( + @PathVariable("uuid") UUID uuid, + // doPage request parametes + @RequestParam(value = "pageNumber", required = false) Integer pageNumber, + @RequestParam(value = "pageSize", required = false) Integer pageSize, + // doList request parametes + @RequestParam(value = "start", required = false) Integer start, + @RequestParam(value = "limit", required = false) Integer limit, + HttpServletRequest request, + HttpServletResponse response) throws IOException { + + ModelAndView modelAndView = new ModelAndView(); + + String servletPath = request.getServletPath(); + String baseName = FilenameUtils.getBaseName(servletPath); + + if(request != null) + logger.info("doGetMethod()[doGet" + StringUtils.capitalize(baseName) + "] " + request.getServletPath()); + + // )null); + + //Class propertyClass = propertyClass(instance, baseName); + + Object objectFromProperty = getCdmBaseProperty(uuid, baseName, response);// invokeProperty(instance, baseName, response); + + // CUT> + + if(objectFromProperty != null){ + + if( Collection.class.isAssignableFrom(objectFromProperty.getClass())){ + // Map types cannot be returned as list or in a pager! + + Collection c = (Collection)objectFromProperty; + if(start != null){ + // return list + limit = (limit == null ? DEFAULT_PAGE_SIZE : limit); + Collection sub_c = subCollection(c, start, limit); + modelAndView.addObject(sub_c); + + } else { + //FIXME use real paging mechanism of according service class instead of subCollection() + //FIXME use BaseListController.normalizeAndValidatePagerParameters(pageNumber, pageSize, response); + pageSize = (pageSize == null ? DEFAULT_PAGE_SIZE : pageSize); + pageNumber = (pageNumber == null ? 0 : pageNumber); + start = pageNumber * pageSize; + List sub_c = subCollection(c, start, pageSize); + Pager p = new DefaultPagerImpl(pageNumber, c.size(), pageSize, sub_c); + modelAndView.addObject(p); } + + } else { + modelAndView.addObject(objectFromProperty); } + + } + + if(modelAndView.isEmpty()){ + return null; + } else { + + return modelAndView; } - return null; + } + + public Object getCdmBaseProperty(UUID uuid, String property, HttpServletResponse response) throws IOException{ + + T instance = (T) HibernateProxyHelper.deproxy(getCdmBaseInstance(uuid, response, property)); + + Object objectFromProperty = invokeProperty(instance, property, response); + + return objectFromProperty; } - @RequestMapping(method = RequestMethod.GET) - public T doGet(HttpServletRequest request) { + private Class propertyClass(T instance, String baseName) { + PropertyDescriptor propertyDescriptor = null; + Class c = null; + try { + propertyDescriptor = PropertyUtils.getPropertyDescriptor(instance, baseName); + if(propertyDescriptor != null){ + c = propertyDescriptor.getClass(); + } + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return c; + } + + /** + * @param + * @param clazz + * @param uuid + * @param response + * @param pathProperties + * @return + * @throws IOException + */ + @SuppressWarnings("unchecked") + protected final SUB_T getCdmBaseInstance(Class clazz, UUID uuid, HttpServletResponse response, List pathProperties) + throws IOException { + + CdmBase cdmBaseObject = getCdmBaseInstance(uuid, response, pathProperties); + if(!clazz.isAssignableFrom(cdmBaseObject.getClass())){ + HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response); + } + return (SUB_T) cdmBaseObject; + } + + /** + * @param + * @param clazz + * @param uuid + * @param response + * @param pathProperty + * @return + * @throws IOException + */ + @SuppressWarnings("unchecked") + protected final SUB_T getCdmBaseInstance(Class clazz, UUID uuid, HttpServletResponse response, String pathProperty) + throws IOException { - UUID uuid = readValueUuid(request); - Assert.notNull(uuid, "no valid uuid"); - if(uuid == null){ - return null; + CdmBase cdmBaseObject = getCdmBaseInstance(uuid, response, pathProperty); + if(!clazz.isAssignableFrom(cdmBaseObject.getClass())){ + HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response); } - return service.findByUuid(uuid); + return (SUB_T) cdmBaseObject; + } + + /** + * @param uuid + * @param response + * @param pathProperty + * @return + * @throws IOException + */ + protected final T getCdmBaseInstance(UUID uuid, HttpServletResponse response, String pathProperty) + throws IOException { + return getCdmBaseInstance(baseClass, uuid, response, Arrays + .asList(new String[] { pathProperty })); } + + + /** + * @param uuid + * @param response + * @param pathProperties + * @return + * @throws IOException + */ + protected final T getCdmBaseInstance(UUID uuid, HttpServletResponse response, List pathProperties) + throws IOException { + return getCdmBaseInstance(baseClass, service, uuid, response, pathProperties); + } + + /** + * @param + * @param clazz + * @param service + * @param uuid + * @param response + * @param pathProperties + * @return + * @throws IOException + */ + protected final CDM_BASE getCdmBaseInstance(Class clazz, IService service, UUID uuid, HttpServletResponse response, List pathProperties) + throws IOException { + + CDM_BASE cdmBaseObject = service.load(uuid, pathProperties); + if (cdmBaseObject == null) { + HttpStatusMessage.UUID_NOT_FOUND.send(response); + } + return cdmBaseObject; + } + /** + * @param instance + * @param baseName + * @param response + * @return + * @throws IOException + */ + private final Object invokeProperty(T instance, + String baseName, HttpServletResponse response) throws IOException { + + Object result = null; + try { + PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(instance, baseName); + if(propertyDescriptor == null){ + throw new NoSuchMethodException("No such method: " + instance.getClass().getSimpleName() + ".get" + baseName); + } + Method method = propertyDescriptor.getReadMethod(); + + Class returnType = method.getReturnType(); + + if(CdmBase.class.isAssignableFrom(returnType) + || Collection.class.isAssignableFrom(returnType) + || Map.class.isAssignableFrom(returnType) + || INomenclaturalReference.class.isAssignableFrom(returnType)){ + + result = method.invoke(instance, (Object[])null); + + result = HibernateProxyHelper.deproxy(result); + + }else{ + HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response); + } + } catch (SecurityException e) { + logger.error("SecurityException: ", e); + HttpStatusMessage.INTERNAL_ERROR.send(response); + } catch (NoSuchMethodException e) { + HttpStatusMessage.PROPERTY_NOT_FOUND.send(response); + } catch (IllegalArgumentException e) { + HttpStatusMessage.PROPERTY_NOT_FOUND.send(response); + } catch (IllegalAccessException e) { + HttpStatusMessage.PROPERTY_NOT_FOUND.send(response); + } catch (InvocationTargetException e) { + HttpStatusMessage.PROPERTY_NOT_FOUND.send(response); + } + return result; + } + + private List subCollection(Collection c, Integer start, Integer length){ + List sub_c = new ArrayList(length); + if(c.size() > length){ + E[] a = (E[]) c.toArray(); + for(int i = start; i < start + length; i++){ + sub_c.add(a[i]); + } + } else { + sub_c.addAll(c); + } + return sub_c; + + } + + /* TODO implement - * - @RequestMapping(method = RequestMethod.POST) - public T doPost(@PathVariable(value = "uuid") UUID uuid, @ModelAttribute("object") T object, BindingResult result) { - validator.validate(object, result); - if (result.hasErrors()) { + + private Validator validator; + + private javax.validation.Validator javaxValidator; + + @RequestMapping(method = RequestMethod.PUT, headers="content-type=multipart/form-data") + public T doPutForm(@PathVariable(value = "uuid") UUID uuid, @ModelAttribute("object") T object, BindingResult result) { + object.setUuid(uuid); + validator.validate(object, result); + if (result.hasErrors()) { + throw new Error(); + // set http status code depending upon what happened, possibly return + // the put object and errors so that they can be rendered into a suitable error response + } else { + // requires merging detached object ?gilead? + service.save(object); + } + + return object; + } + + @RequestMapping(method = RequestMethod.PUT, headers="content-type=text/json") + public T doPutJSON(@PathVariable(value = "uuid") UUID uuid, @RequestBody String jsonMessage) { + JSONObject jsonObject = JSONObject.fromObject(jsonMessage); + T object = (T)JSONObject.toBean(jsonObject, this.getClass()); + + + Set> constraintViolations = javaxValidator.validate(object); + if (!constraintViolations.isEmpty()) { + throw new Error(); // set http status code depending upon what happened, possibly return // the put object and errors so that they can be rendered into a suitable error response } else { // requires merging detached object ?gilead? - service.update(object); + service.save(object); } + + return object; } @RequestMapping(method = RequestMethod.PUT) // the cdm-server may not allow clients to specify the uuid for resources