43 import java.lang.reflect.Method; |
43 import java.lang.reflect.Method; |
44 import java.lang.reflect.Modifier; |
44 import java.lang.reflect.Modifier; |
45 import java.sql.Connection; |
45 import java.sql.Connection; |
46 import java.sql.SQLException; |
46 import java.sql.SQLException; |
47 import java.util.*; |
47 import java.util.*; |
|
48 import java.util.function.Function; |
48 |
49 |
49 /** |
50 /** |
50 * A special implementation of a HTTPServlet which is focused on implementing |
51 * A special implementation of a HTTPServlet which is focused on implementing |
51 * the necessary functionality for {@link LightPITModule}s. |
52 * the necessary functionality for {@link LightPITModule}s. |
52 */ |
53 */ |
58 |
59 |
59 /** |
60 /** |
60 * The EL proxy is necessary, because the EL resolver cannot handle annotation properties. |
61 * The EL proxy is necessary, because the EL resolver cannot handle annotation properties. |
61 */ |
62 */ |
62 private LightPITModule.ELProxy moduleInfo = null; |
63 private LightPITModule.ELProxy moduleInfo = null; |
|
64 |
|
65 @FunctionalInterface |
|
66 protected interface SQLFindFunction<K, T> { |
|
67 T apply(K key) throws SQLException; |
|
68 |
|
69 default <V> SQLFindFunction<V, T> compose(Function<? super V, ? extends K> before) throws SQLException { |
|
70 Objects.requireNonNull(before); |
|
71 return (v) -> this.apply(before.apply(v)); |
|
72 } |
|
73 |
|
74 default <V> SQLFindFunction<K, V> andThen(Function<? super T, ? extends V> after) throws SQLException { |
|
75 Objects.requireNonNull(after); |
|
76 return (t) -> after.apply(this.apply(t)); |
|
77 } |
|
78 |
|
79 static <K> Function<K, K> identity() { |
|
80 return (t) -> t; |
|
81 } |
|
82 } |
63 |
83 |
64 /** |
84 /** |
65 * Invocation mapping gathered from the {@link RequestMapping} annotations. |
85 * Invocation mapping gathered from the {@link RequestMapping} annotations. |
66 * <p> |
86 * <p> |
67 * Paths in this map must always start with a leading slash, although |
87 * Paths in this map must always start with a leading slash, although |
222 * |
242 * |
223 * @param req the servlet request object |
243 * @param req the servlet request object |
224 * @param fragmentName the name of the fragment |
244 * @param fragmentName the name of the fragment |
225 * @see Constants#DYN_FRAGMENT_PATH_PREFIX |
245 * @see Constants#DYN_FRAGMENT_PATH_PREFIX |
226 */ |
246 */ |
227 public void setDynamicFragment(HttpServletRequest req, String fragmentName) { |
247 protected void setDynamicFragment(HttpServletRequest req, String fragmentName) { |
228 req.setAttribute(Constants.REQ_ATTR_FRAGMENT, Functions.dynFragmentPath(fragmentName)); |
248 req.setAttribute(Constants.REQ_ATTR_FRAGMENT, Functions.dynFragmentPath(fragmentName)); |
229 } |
249 } |
230 |
250 |
231 /** |
251 /** |
232 * @param req the servlet request object |
252 * @param req the servlet request object |
233 * @param location the location where to redirect |
253 * @param location the location where to redirect |
234 * @see Constants#REQ_ATTR_REDIRECT_LOCATION |
254 * @see Constants#REQ_ATTR_REDIRECT_LOCATION |
235 */ |
255 */ |
236 public void setRedirectLocation(HttpServletRequest req, String location) { |
256 protected void setRedirectLocation(HttpServletRequest req, String location) { |
237 if (location.startsWith("./")) { |
257 if (location.startsWith("./")) { |
238 location = location.replaceFirst("\\./", Functions.baseHref(req)); |
258 location = location.replaceFirst("\\./", Functions.baseHref(req)); |
239 } |
259 } |
240 req.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, location); |
260 req.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, location); |
241 } |
261 } |
265 * @param clazz the class object of the expected type |
285 * @param clazz the class object of the expected type |
266 * @param name the name of the parameter |
286 * @param name the name of the parameter |
267 * @param <T> the expected type |
287 * @param <T> the expected type |
268 * @return the parameter value or an empty optional, if no parameter with the specified name was found |
288 * @return the parameter value or an empty optional, if no parameter with the specified name was found |
269 */ |
289 */ |
270 public<T> Optional<T> getParameter(HttpServletRequest req, Class<T> clazz, String name) { |
290 protected<T> Optional<T> getParameter(HttpServletRequest req, Class<T> clazz, String name) { |
271 final String paramValue = req.getParameter(name); |
291 final String paramValue = req.getParameter(name); |
272 if (paramValue == null) return Optional.empty(); |
292 if (paramValue == null) return Optional.empty(); |
273 if (clazz.equals(String.class)) return Optional.of((T)paramValue); |
293 if (clazz.equals(String.class)) return Optional.of((T)paramValue); |
274 try { |
294 try { |
275 final Constructor<T> ctor = clazz.getConstructor(String.class); |
295 final Constructor<T> ctor = clazz.getConstructor(String.class); |
276 return Optional.of(ctor.newInstance(paramValue)); |
296 return Optional.of(ctor.newInstance(paramValue)); |
277 } catch (ReflectiveOperationException e) { |
297 } catch (ReflectiveOperationException e) { |
278 throw new RuntimeException(e); |
298 throw new RuntimeException(e); |
279 } |
299 } |
280 |
300 |
|
301 } |
|
302 |
|
303 /** |
|
304 * Tries to look up an entity with a key obtained from a request parameter. |
|
305 * |
|
306 * @param req the servlet request object |
|
307 * @param clazz the class representing the type of the request parameter |
|
308 * @param name the name of the request parameter |
|
309 * @param find the find function (typically a DAO function) |
|
310 * @param <T> the type of the request parameter |
|
311 * @param <R> the type of the looked up entity |
|
312 * @return the retrieved entity or an empty optional if there is no such entity or the request parameter was missing |
|
313 * @throws SQLException if the find function throws an exception |
|
314 */ |
|
315 protected<T,R> Optional<R> findByParameter(HttpServletRequest req, Class<T> clazz, String name, SQLFindFunction<? super T, ? extends R> find) throws SQLException { |
|
316 final var param = getParameter(req, clazz, name); |
|
317 if (param.isPresent()) { |
|
318 return Optional.ofNullable(find.apply(param.get())); |
|
319 } else { |
|
320 return Optional.empty(); |
|
321 } |
281 } |
322 } |
282 |
323 |
283 private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp) |
324 private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp) |
284 throws IOException, ServletException { |
325 throws IOException, ServletException { |
285 |
326 |