3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.remote
.controller
;
13 import java
.io
.IOException
;
14 import java
.lang
.reflect
.InvocationTargetException
;
15 import java
.lang
.reflect
.Method
;
16 import java
.util
.Arrays
;
17 import java
.util
.Collection
;
18 import java
.util
.List
;
19 import java
.util
.UUID
;
21 import javax
.servlet
.http
.HttpServletRequest
;
22 import javax
.servlet
.http
.HttpServletResponse
;
24 import org
.apache
.commons
.io
.FilenameUtils
;
25 import org
.apache
.commons
.lang
.StringUtils
;
26 import org
.hibernate
.mapping
.Map
;
27 import org
.springframework
.util
.Assert
;
28 import org
.springframework
.web
.bind
.WebDataBinder
;
29 import org
.springframework
.web
.bind
.annotation
.InitBinder
;
30 import org
.springframework
.web
.bind
.annotation
.PathVariable
;
31 import org
.springframework
.web
.bind
.annotation
.RequestMapping
;
32 import org
.springframework
.web
.bind
.annotation
.RequestMethod
;
33 import org
.springframework
.web
.servlet
.ModelAndView
;
35 import eu
.etaxonomy
.cdm
.api
.service
.IService
;
36 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
37 import eu
.etaxonomy
.cdm
.remote
.editor
.UUIDPropertyEditor
;
41 * based on org.cateproject.controller.common
43 * @author a.kohlbecker
49 public abstract class BaseController
<T
extends CdmBase
, SERVICE
extends IService
<T
>> extends AbstractController
{
51 protected SERVICE service
;
53 public abstract void setService(SERVICE service
);
56 public void initBinder(WebDataBinder binder
) {
57 binder
.registerCustomEditor(UUID
.class, new UUIDPropertyEditor());
60 @SuppressWarnings("unchecked")
61 @RequestMapping(method
= RequestMethod
.GET
)
62 public T
doGet(HttpServletRequest request
, HttpServletResponse response
) throws IOException
{
63 logger
.info("doGet() " + request
.getServletPath());
64 T obj
= (T
) getCdmBase(request
, response
, initializationStrategy
, CdmBase
.class);
75 protected <CDM_BASE
> CDM_BASE
getCdmBase(HttpServletRequest request
, HttpServletResponse response
,
76 List
<String
> initStrategy
, Class
<CDM_BASE
> clazz
) throws IOException
{
79 UUID uuid
= readValueUuid(request
, null);
80 Assert
.notNull(uuid
, HttpStatusMessage
.UUID_MISSING
.toString());
82 if(initStrategy
== null){
83 // may be null is set to null via the setter
84 obj
= service
.find(uuid
);
86 obj
= service
.load(uuid
, initStrategy
);
88 Assert
.notNull(obj
, HttpStatusMessage
.UUID_NOT_FOUND
.toString());
90 } catch (IllegalArgumentException iae
) {
91 HttpStatusMessage
.fromString(iae
.getMessage()).send(response
);
97 } catch (Exception e
) {
98 HttpStatusMessage
.UUID_REFERENCES_WRONG_TYPE
.send(response
);
103 protected T
getCdmBaseInstance(UUID uuid
,
104 HttpServletResponse response
,
105 List
<String
> pathProperties
) throws IOException
{
106 CdmBase cdmBaseObject
= service
.load(uuid
, pathProperties
);
107 if(cdmBaseObject
== null){
108 HttpStatusMessage
.UUID_NOT_FOUND
.send(response
);
110 return (T
) cdmBaseObject
;
113 protected T
getCdmBaseInstance(UUID uuid
, HttpServletResponse response
, String pathProperty
) throws IOException
{
114 return getCdmBaseInstance(uuid
, response
, Arrays
.asList(new String
[]{pathProperty
}));
118 @RequestMapping(value
= "{uuid}/*", method
= RequestMethod
.GET
)
119 public ModelAndView
doGetMethod(@PathVariable("uuid") UUID uuid
,
120 HttpServletRequest request
,
121 HttpServletResponse response
) throws IOException
{
122 logger
.info("doGetMethod() " + request
.getServletPath());
124 ModelAndView modelAndView
= new ModelAndView();
126 String servletPath
= request
.getServletPath();
127 String baseName
= FilenameUtils
.getBaseName(servletPath
);
129 T instance
= getCdmBaseInstance(uuid
, response
, Arrays
.asList(new String
[]{baseName
+ ".titleCache"}));
132 String methodName
= "get" + StringUtils
.capitalize(baseName
);
133 Method method
= instance
.getClass().getMethod(methodName
, null);
135 Class
<?
> returnType
= method
.getReturnType();
137 if(CdmBase
.class.isAssignableFrom(returnType
)){
138 CdmBase resultInstance
= (CdmBase
) method
.invoke(instance
, null);
139 modelAndView
.addObject(resultInstance
);
141 else if(Collection
.class.isAssignableFrom(returnType
) || Map
.class.isAssignableFrom(returnType
)){
143 logger
.warn("Collections or Maps not implemented yet.");
145 HttpStatusMessage
.UUID_REFERENCES_WRONG_TYPE
.send(response
);
147 } catch (SecurityException e
) {
148 logger
.error("SecurityException: ", e
);
149 HttpStatusMessage
.INTERNAL_ERROR
.send(response
);
150 } catch (NoSuchMethodException e
) {
151 HttpStatusMessage
.PROPERTY_NOT_FOUND
.send(response
);
152 } catch (IllegalArgumentException e
) {
153 HttpStatusMessage
.PROPERTY_NOT_FOUND
.send(response
);
154 } catch (IllegalAccessException e
) {
155 HttpStatusMessage
.PROPERTY_NOT_FOUND
.send(response
);
156 } catch (InvocationTargetException e
) {
157 HttpStatusMessage
.PROPERTY_NOT_FOUND
.send(response
);
166 private Validator validator;
168 private javax.validation.Validator javaxValidator;
170 @RequestMapping(method = RequestMethod.PUT, headers="content-type=multipart/form-data")
171 public T doPutForm(@PathVariable(value = "uuid") UUID uuid, @ModelAttribute("object") T object, BindingResult result) {
172 object.setUuid(uuid);
173 validator.validate(object, result);
174 if (result.hasErrors()) {
176 // set http status code depending upon what happened, possibly return
177 // the put object and errors so that they can be rendered into a suitable error response
179 // requires merging detached object ?gilead?
180 service.save(object);
186 @RequestMapping(method = RequestMethod.PUT, headers="content-type=text/json")
187 public T doPutJSON(@PathVariable(value = "uuid") UUID uuid, @RequestBody String jsonMessage) {
188 JSONObject jsonObject = JSONObject.fromObject(jsonMessage);
189 T object = (T)JSONObject.toBean(jsonObject, this.getClass());
192 Set<ConstraintViolation<T>> constraintViolations = javaxValidator.validate(object);
193 if (!constraintViolations.isEmpty()) {
195 // set http status code depending upon what happened, possibly return
196 // the put object and errors so that they can be rendered into a suitable error response
198 // requires merging detached object ?gilead?
199 service.save(object);
205 @RequestMapping(method = RequestMethod.PUT) // the cdm-server may not allow clients to specify the uuid for resources
206 public T doPut(@PathVariable(value = "uuid") UUID uuid, @ModelAttribute("object") T object, BindingResult result) {
207 validator.validate(object, result);
208 if (result.hasErrors()) {
209 // set http status code depending upon what happened, possibly return
210 // the put object and errors so that they can be rendered into a suitable error response
212 service.save(object);
216 @RequestMapping(method = RequestMethod.DELETE)
217 public void doDelete(@PathVariable(value = "uuid") UUID uuid) {
218 T object = service.find(uuid);
219 // provided the object exists
220 service.delete(uuid);
221 // might return 204 or 200