1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Mon May 11 19:09:06 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Tue May 12 22:03:00 2020 +0200 1.3 @@ -60,12 +60,6 @@ 1.4 */ 1.5 private LightPITModule.ELProxy moduleInfo = null; 1.6 1.7 - 1.8 - @FunctionalInterface 1.9 - private interface HandlerMethod { 1.10 - ResponseType apply(HttpServletRequest request, HttpServletResponse response, DataAccessObjects dao) throws IOException, SQLException; 1.11 - } 1.12 - 1.13 /** 1.14 * Invocation mapping gathered from the {@link RequestMapping} annotations. 1.15 * <p> 1.16 @@ -75,7 +69,7 @@ 1.17 * The reason for this is the different handling of empty paths in 1.18 * {@link HttpServletRequest#getPathInfo()}. 1.19 */ 1.20 - private final Map<HttpMethod, Map<String, HandlerMethod>> mappings = new HashMap<>(); 1.21 + private final Map<HttpMethod, Map<String, Method>> mappings = new HashMap<>(); 1.22 1.23 /** 1.24 * Gives implementing modules access to the {@link ModuleManager}. 1.25 @@ -95,12 +89,10 @@ 1.26 */ 1.27 private DataAccessObjects createDataAccessObjects(Connection connection) throws SQLException { 1.28 final var df = (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME); 1.29 - switch (df.getSQLDialect()) { 1.30 - case Postgres: 1.31 - return new PGDataAccessObjects(connection); 1.32 - default: 1.33 - throw new AssertionError("Non-exhaustive switch - this is a bug."); 1.34 + if (df.getSQLDialect() == DatabaseFacade.Dialect.Postgres) { 1.35 + return new PGDataAccessObjects(connection); 1.36 } 1.37 + throw new AssertionError("Non-exhaustive if-else - this is a bug."); 1.38 } 1.39 1.40 private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException { 1.41 @@ -160,9 +152,9 @@ 1.42 1.43 final String requestPath = "/" + mapping.get().requestPath(); 1.44 1.45 - if (mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()). 1.46 - putIfAbsent(requestPath, 1.47 - (req, resp, dao) -> invokeMapping(method, req, resp, dao)) != null) { 1.48 + if (mappings 1.49 + .computeIfAbsent(mapping.get().method(), k -> new HashMap<>()) 1.50 + .putIfAbsent(requestPath, method) != null) { 1.51 LOG.warn("{} {} has multiple mappings", 1.52 mapping.get().method(), 1.53 mapping.get().requestPath() 1.54 @@ -232,10 +224,10 @@ 1.55 req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp); 1.56 } 1.57 1.58 - private Optional<HandlerMethod> findMapping(HttpMethod method, HttpServletRequest req) { 1.59 - return Optional.ofNullable(mappings.get(method)).map( 1.60 - (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/")) 1.61 - ); 1.62 + private Optional<Method> findMapping(HttpMethod method, HttpServletRequest req) { 1.63 + return Optional.ofNullable(mappings.get(method)) 1.64 + .map(rm -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/")) 1.65 + ); 1.66 } 1.67 1.68 private void forwardAsSpecified(ResponseType type, HttpServletRequest req, HttpServletResponse resp) 1.69 @@ -277,15 +269,24 @@ 1.70 final var db = (DatabaseFacade) req.getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME); 1.71 try (final var connection = db.getDataSource().getConnection()) { 1.72 final var dao = createDataAccessObjects(connection); 1.73 - // call the handler, if available, or send an HTTP 404 error 1.74 - final var mapping = findMapping(method, req); 1.75 - if (mapping.isPresent()) { 1.76 - forwardAsSpecified(mapping.get().apply(req, resp, dao), req, resp); 1.77 - } else { 1.78 - resp.sendError(HttpServletResponse.SC_NOT_FOUND); 1.79 + try { 1.80 + connection.setAutoCommit(false); 1.81 + // call the handler, if available, or send an HTTP 404 error 1.82 + final var mapping = findMapping(method, req); 1.83 + if (mapping.isPresent()) { 1.84 + forwardAsSpecified(invokeMapping(mapping.get(), req, resp, dao), req, resp); 1.85 + } else { 1.86 + resp.sendError(HttpServletResponse.SC_NOT_FOUND); 1.87 + } 1.88 + connection.commit(); 1.89 + } catch (SQLException ex) { 1.90 + LOG.warn("Database transaction failed (Code {}): {}", ex.getErrorCode(), ex.getMessage()); 1.91 + LOG.debug("Details: ", ex); 1.92 + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unhandled Transaction Error - Code:" + ex.getErrorCode()); 1.93 + connection.rollback(); 1.94 } 1.95 } catch (SQLException ex) { 1.96 - LOG.error("Database exception (Code {}): {}", ex.getErrorCode(), ex.getMessage()); 1.97 + LOG.error("Severe Database Exception (Code {}): {}", ex.getErrorCode(), ex.getMessage()); 1.98 LOG.debug("Details: ", ex); 1.99 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Database Error - Code:" + ex.getErrorCode()); 1.100 }