Fixed a problem where the generic method call would only work on methods declared...
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / BaseController.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10
11 package eu.etaxonomy.cdm.remote.controller;
12
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;
20
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
23
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;
34
35 import eu.etaxonomy.cdm.api.service.IService;
36 import eu.etaxonomy.cdm.model.common.CdmBase;
37 import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
38
39 //$Id$
40 /**
41 * based on org.cateproject.controller.common
42 * @author b.clark
43 * @author a.kohlbecker
44 *
45 * @param <T>
46 * @param <SERVICE>
47 */
48
49 public abstract class BaseController<T extends CdmBase, SERVICE extends IService<T>> extends AbstractController {
50
51 protected SERVICE service;
52
53 public abstract void setService(SERVICE service);
54
55 @InitBinder
56 public void initBinder(WebDataBinder binder) {
57 binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
58 }
59
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);
65 return obj;
66 }
67
68 /**
69 * @param request
70 * @param response
71 * @param obj
72 * @return
73 * @throws IOException
74 */
75 protected <CDM_BASE> CDM_BASE getCdmBase(HttpServletRequest request, HttpServletResponse response,
76 List<String> initStrategy, Class<CDM_BASE> clazz) throws IOException {
77 T obj = null;
78 try {
79 UUID uuid = readValueUuid(request, null);
80 Assert.notNull(uuid, HttpStatusMessage.UUID_MISSING.toString());
81
82 if(initStrategy == null){
83 // may be null is set to null via the setter
84 obj = service.find(uuid);
85 } else {
86 obj = service.load(uuid, initStrategy);
87 }
88 Assert.notNull(obj, HttpStatusMessage.UUID_NOT_FOUND.toString());
89
90 } catch (IllegalArgumentException iae) {
91 HttpStatusMessage.fromString(iae.getMessage()).send(response);
92 }
93 CDM_BASE t;
94 try {
95 t = (CDM_BASE)obj;
96 return t;
97 } catch (Exception e) {
98 HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response);
99 return null;
100 }
101 }
102
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);
109 }
110 return (T) cdmBaseObject;
111 }
112
113 protected T getCdmBaseInstance(UUID uuid, HttpServletResponse response, String pathProperty) throws IOException{
114 return getCdmBaseInstance(uuid, response, Arrays.asList(new String[]{pathProperty}));
115 }
116
117
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());
123
124 ModelAndView modelAndView = new ModelAndView();
125
126 String servletPath = request.getServletPath();
127 String baseName = FilenameUtils.getBaseName(servletPath);
128
129 T instance = getCdmBaseInstance(uuid, response, Arrays.asList(new String[]{baseName + ".titleCache"}));
130
131 try {
132 String methodName = "get" + StringUtils.capitalize(baseName);
133 Method method = instance.getClass().getMethod(methodName, null);
134
135 Class<?> returnType = method.getReturnType();
136
137 if(CdmBase.class.isAssignableFrom(returnType)){
138 CdmBase resultInstance = (CdmBase) method.invoke(instance, null);
139 modelAndView.addObject(resultInstance);
140 }
141 else if(Collection.class.isAssignableFrom(returnType) || Map.class.isAssignableFrom(returnType)){
142 // TODO
143 logger.warn("Collections or Maps not implemented yet.");
144 }else{
145 HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response);
146 }
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);
158 }
159
160 return modelAndView;
161 }
162
163
164 /* TODO implement
165
166 private Validator validator;
167
168 private javax.validation.Validator javaxValidator;
169
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()) {
175 throw new Error();
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
178 } else {
179 // requires merging detached object ?gilead?
180 service.save(object);
181 }
182
183 return object;
184 }
185
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());
190
191
192 Set<ConstraintViolation<T>> constraintViolations = javaxValidator.validate(object);
193 if (!constraintViolations.isEmpty()) {
194 throw new Error();
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
197 } else {
198 // requires merging detached object ?gilead?
199 service.save(object);
200 }
201
202 return object;
203 }
204
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
211 } else {
212 service.save(object);
213 }
214 }
215
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
222 }
223 }
224 */
225
226
227 }