src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java

changeset 179
623c340058f3
parent 178
88207b860cba
child 180
009700915269
     1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Mon Jan 04 17:30:10 2021 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,471 +0,0 @@
     1.4 -/*
     1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     1.6 - *
     1.7 - * Copyright 2018 Mike Becker. All rights reserved.
     1.8 - *
     1.9 - * Redistribution and use in source and binary forms, with or without
    1.10 - * modification, are permitted provided that the following conditions are met:
    1.11 - *
    1.12 - *   1. Redistributions of source code must retain the above copyright
    1.13 - *      notice, this list of conditions and the following disclaimer.
    1.14 - *
    1.15 - *   2. Redistributions in binary form must reproduce the above copyright
    1.16 - *      notice, this list of conditions and the following disclaimer in the
    1.17 - *      documentation and/or other materials provided with the distribution.
    1.18 - *
    1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    1.29 - * POSSIBILITY OF SUCH DAMAGE.
    1.30 - *
    1.31 - */
    1.32 -package de.uapcore.lightpit;
    1.33 -
    1.34 -import de.uapcore.lightpit.dao.DataAccessObject;
    1.35 -import de.uapcore.lightpit.dao.PostgresDataAccessObject;
    1.36 -import org.slf4j.Logger;
    1.37 -import org.slf4j.LoggerFactory;
    1.38 -
    1.39 -import javax.servlet.ServletException;
    1.40 -import javax.servlet.http.HttpServlet;
    1.41 -import javax.servlet.http.HttpServletRequest;
    1.42 -import javax.servlet.http.HttpServletResponse;
    1.43 -import javax.servlet.http.HttpSession;
    1.44 -import java.io.IOException;
    1.45 -import java.lang.reflect.*;
    1.46 -import java.sql.Connection;
    1.47 -import java.sql.SQLException;
    1.48 -import java.util.*;
    1.49 -import java.util.function.Function;
    1.50 -import java.util.stream.Collectors;
    1.51 -
    1.52 -/**
    1.53 - * A special implementation of a HTTPServlet which is focused on implementing
    1.54 - * the necessary functionality for LightPIT pages.
    1.55 - */
    1.56 -public abstract class AbstractLightPITServlet extends HttpServlet {
    1.57 -
    1.58 -    private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class);
    1.59 -
    1.60 -    private static final String SITE_JSP = jspPath("site");
    1.61 -
    1.62 -    /**
    1.63 -     * Invocation mapping gathered from the {@link RequestMapping} annotations.
    1.64 -     * <p>
    1.65 -     * Paths in this map must always start with a leading slash, although
    1.66 -     * the specification in the annotation must not start with a leading slash.
    1.67 -     * <p>
    1.68 -     * The reason for this is the different handling of empty paths in
    1.69 -     * {@link HttpServletRequest#getPathInfo()}.
    1.70 -     */
    1.71 -    private final Map<HttpMethod, Map<PathPattern, Method>> mappings = new HashMap<>();
    1.72 -
    1.73 -    /**
    1.74 -     * Returns the name of the resource bundle associated with this servlet.
    1.75 -     *
    1.76 -     * @return the resource bundle base name
    1.77 -     */
    1.78 -    protected abstract String getResourceBundleName();
    1.79 -
    1.80 -
    1.81 -    /**
    1.82 -     * Creates a set of data access objects for the specified connection.
    1.83 -     *
    1.84 -     * @param connection the SQL connection
    1.85 -     * @return a set of data access objects
    1.86 -     */
    1.87 -    private DataAccessObject createDataAccessObjects(Connection connection) {
    1.88 -        final var df = (DataSourceProvider) getServletContext().getAttribute(DataSourceProvider.Companion.getSC_ATTR_NAME());
    1.89 -        if (df.getDialect() == DataSourceProvider.Dialect.Postgres) {
    1.90 -            return new PostgresDataAccessObject(connection);
    1.91 -        }
    1.92 -        throw new UnsupportedOperationException("Non-exhaustive if-else - this is a bug.");
    1.93 -    }
    1.94 -
    1.95 -    private void invokeMapping(Map.Entry<PathPattern, Method> mapping, HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException {
    1.96 -        final var pathPattern = mapping.getKey();
    1.97 -        final var method = mapping.getValue();
    1.98 -        try {
    1.99 -            LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName());
   1.100 -            final var paramTypes = method.getParameterTypes();
   1.101 -            final var paramValues = new Object[paramTypes.length];
   1.102 -            for (int i = 0; i < paramTypes.length; i++) {
   1.103 -                if (paramTypes[i].isAssignableFrom(HttpServletRequest.class)) {
   1.104 -                    paramValues[i] = req;
   1.105 -                } else if (paramTypes[i].isAssignableFrom(HttpServletResponse.class)) {
   1.106 -                    paramValues[i] = resp;
   1.107 -                }
   1.108 -                if (paramTypes[i].isAssignableFrom(DataAccessObject.class)) {
   1.109 -                    paramValues[i] = dao;
   1.110 -                }
   1.111 -                if (paramTypes[i].isAssignableFrom(PathParameters.class)) {
   1.112 -                    paramValues[i] = pathPattern.obtainPathParameters(sanitizeRequestPath(req));
   1.113 -                }
   1.114 -            }
   1.115 -            method.invoke(this, paramValues);
   1.116 -        } catch (InvocationTargetException ex) {
   1.117 -            LOG.error("invocation of method {}::{} failed: {}",
   1.118 -                    method.getDeclaringClass().getName(), method.getName(), ex.getTargetException().getMessage());
   1.119 -            LOG.debug("Details: ", ex.getTargetException());
   1.120 -            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getTargetException().getMessage());
   1.121 -        } catch (ReflectiveOperationException | ClassCastException ex) {
   1.122 -            LOG.error("invocation of method {}::{} failed: {}",
   1.123 -                    method.getDeclaringClass().getName(), method.getName(), ex.getMessage());
   1.124 -            LOG.debug("Details: ", ex);
   1.125 -            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
   1.126 -        }
   1.127 -    }
   1.128 -
   1.129 -    @Override
   1.130 -    public void init() throws ServletException {
   1.131 -        scanForRequestMappings();
   1.132 -
   1.133 -        LOG.trace("{} initialized", getServletName());
   1.134 -    }
   1.135 -
   1.136 -    private void scanForRequestMappings() {
   1.137 -        try {
   1.138 -            Method[] methods = getClass().getDeclaredMethods();
   1.139 -            for (Method method : methods) {
   1.140 -                Optional<RequestMapping> mapping = Optional.ofNullable(method.getAnnotation(RequestMapping.class));
   1.141 -                if (mapping.isPresent()) {
   1.142 -                    if (mapping.get().requestPath().isBlank()) {
   1.143 -                        LOG.warn("{} is annotated with {} but request path is empty",
   1.144 -                                method.getName(), RequestMapping.class.getSimpleName()
   1.145 -                        );
   1.146 -                        continue;
   1.147 -                    }
   1.148 -
   1.149 -                    if (!Modifier.isPublic(method.getModifiers())) {
   1.150 -                        LOG.warn("{} is annotated with {} but is not public",
   1.151 -                                method.getName(), RequestMapping.class.getSimpleName()
   1.152 -                        );
   1.153 -                        continue;
   1.154 -                    }
   1.155 -                    if (Modifier.isAbstract(method.getModifiers())) {
   1.156 -                        LOG.warn("{} is annotated with {} but is abstract",
   1.157 -                                method.getName(), RequestMapping.class.getSimpleName()
   1.158 -                        );
   1.159 -                        continue;
   1.160 -                    }
   1.161 -
   1.162 -                    boolean paramsInjectible = true;
   1.163 -                    for (var param : method.getParameterTypes()) {
   1.164 -                        paramsInjectible &= HttpServletRequest.class.isAssignableFrom(param)
   1.165 -                                            || HttpServletResponse.class.isAssignableFrom(param)
   1.166 -                                            || PathParameters.class.isAssignableFrom(param)
   1.167 -                                            || DataAccessObject.class.isAssignableFrom(param);
   1.168 -                    }
   1.169 -                    if (paramsInjectible) {
   1.170 -                        try {
   1.171 -                            PathPattern pathPattern = new PathPattern(mapping.get().requestPath());
   1.172 -
   1.173 -                            final var methodMappings = mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>());
   1.174 -                            final var currentMapping = methodMappings.putIfAbsent(pathPattern, method);
   1.175 -                            if (currentMapping != null) {
   1.176 -                                LOG.warn("Cannot map {} {} to {} in class {} - this would override the mapping to {}",
   1.177 -                                        mapping.get().method(),
   1.178 -                                        mapping.get().requestPath(),
   1.179 -                                        method.getName(),
   1.180 -                                        getClass().getSimpleName(),
   1.181 -                                        currentMapping.getName()
   1.182 -                                );
   1.183 -                            }
   1.184 -
   1.185 -                            LOG.debug("{} {} maps to {}::{}",
   1.186 -                                    mapping.get().method(),
   1.187 -                                    mapping.get().requestPath(),
   1.188 -                                    getClass().getSimpleName(),
   1.189 -                                    method.getName()
   1.190 -                            );
   1.191 -                        } catch (IllegalArgumentException ex) {
   1.192 -                            LOG.warn("Request mapping for {} failed: path pattern '{}' is syntactically invalid",
   1.193 -                                    method.getName(), mapping.get().requestPath()
   1.194 -                            );
   1.195 -                        }
   1.196 -                    } else {
   1.197 -                        LOG.warn("{} is annotated with {} but has the wrong parameters - only HttpServletRequest, HttpServletResponse, PathParameters, and DataAccessObjects are allowed",
   1.198 -                                method.getName(), RequestMapping.class.getSimpleName()
   1.199 -                        );
   1.200 -                    }
   1.201 -                }
   1.202 -            }
   1.203 -        } catch (SecurityException ex) {
   1.204 -            LOG.error("Scan for request mappings on declared methods failed.", ex);
   1.205 -        }
   1.206 -    }
   1.207 -
   1.208 -    @Override
   1.209 -    public void destroy() {
   1.210 -        mappings.clear();
   1.211 -        LOG.trace("{} destroyed", getServletName());
   1.212 -    }
   1.213 -
   1.214 -    /**
   1.215 -     * Sets the name of the content page.
   1.216 -     * <p>
   1.217 -     * It is sufficient to specify the name without any extension. The extension
   1.218 -     * is added automatically if not specified.
   1.219 -     *
   1.220 -     * @param req      the servlet request object
   1.221 -     * @param pageName the name of the content page
   1.222 -     * @see Constants#REQ_ATTR_CONTENT_PAGE
   1.223 -     */
   1.224 -    protected void setContentPage(HttpServletRequest req, String pageName) {
   1.225 -        req.setAttribute(Constants.REQ_ATTR_CONTENT_PAGE, jspPath(pageName));
   1.226 -    }
   1.227 -
   1.228 -    /**
   1.229 -     * Sets the navigation menu.
   1.230 -     *
   1.231 -     * @param req     the servlet request object
   1.232 -     * @param jspName the name of the menu's jsp file
   1.233 -     * @see Constants#REQ_ATTR_NAVIGATION
   1.234 -     */
   1.235 -    protected void setNavigationMenu(HttpServletRequest req, String jspName) {
   1.236 -        req.setAttribute(Constants.REQ_ATTR_NAVIGATION, jspPath(jspName));
   1.237 -    }
   1.238 -
   1.239 -    /**
   1.240 -     * @param req      the servlet request object
   1.241 -     * @param location the location where to redirect
   1.242 -     * @see Constants#REQ_ATTR_REDIRECT_LOCATION
   1.243 -     */
   1.244 -    protected void setRedirectLocation(HttpServletRequest req, String location) {
   1.245 -        if (location.startsWith("./")) {
   1.246 -            location = location.replaceFirst("\\./", baseHref(req));
   1.247 -        }
   1.248 -        req.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, location);
   1.249 -    }
   1.250 -
   1.251 -    /**
   1.252 -     * Specifies the names of additional stylesheets used by this Servlet.
   1.253 -     * <p>
   1.254 -     * It is sufficient to specify the name without any extension. The extension
   1.255 -     * is added automatically if not specified.
   1.256 -     *
   1.257 -     * @param req         the servlet request object
   1.258 -     * @param stylesheets the names of the stylesheets
   1.259 -     */
   1.260 -    public void setStylesheet(HttpServletRequest req, String ... stylesheets) {
   1.261 -        req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Arrays
   1.262 -                .stream(stylesheets)
   1.263 -                .map(s -> enforceExt(s, ".css"))
   1.264 -                .collect(Collectors.toUnmodifiableList()));
   1.265 -    }
   1.266 -
   1.267 -    /**
   1.268 -     * Sets the view model object.
   1.269 -     * The type must match the expected type in the JSP file.
   1.270 -     *
   1.271 -     * @param req       the servlet request object
   1.272 -     * @param viewModel the view model object
   1.273 -     */
   1.274 -    public void setViewModel(HttpServletRequest req, Object viewModel) {
   1.275 -        req.setAttribute(Constants.REQ_ATTR_VIEWMODEL, viewModel);
   1.276 -    }
   1.277 -
   1.278 -    private <T> Optional<T> parseParameter(String paramValue, Class<T> clazz) {
   1.279 -        if (paramValue == null) return Optional.empty();
   1.280 -        if (clazz.equals(Boolean.class)) {
   1.281 -            if (paramValue.equalsIgnoreCase("false") || paramValue.equals("0")) {
   1.282 -                return Optional.of((T) Boolean.FALSE);
   1.283 -            } else {
   1.284 -                return Optional.of((T) Boolean.TRUE);
   1.285 -            }
   1.286 -        }
   1.287 -        if (clazz.equals(String.class)) return Optional.of((T) paramValue);
   1.288 -        if (java.sql.Date.class.isAssignableFrom(clazz)) {
   1.289 -            try {
   1.290 -                return Optional.of((T) java.sql.Date.valueOf(paramValue));
   1.291 -            } catch (IllegalArgumentException ex) {
   1.292 -                return Optional.empty();
   1.293 -            }
   1.294 -        }
   1.295 -        try {
   1.296 -            final Constructor<T> ctor = clazz.getConstructor(String.class);
   1.297 -            return Optional.of(ctor.newInstance(paramValue));
   1.298 -        } catch (ReflectiveOperationException e) {
   1.299 -            // does not type check and is not convertible - treat as if the parameter was never set
   1.300 -            return Optional.empty();
   1.301 -        }
   1.302 -    }
   1.303 -
   1.304 -    /**
   1.305 -     * Obtains a request parameter of the specified type.
   1.306 -     * The specified type must have a single-argument constructor accepting a string to perform conversion.
   1.307 -     * The constructor of the specified type may throw an exception on conversion failures.
   1.308 -     *
   1.309 -     * @param req   the servlet request object
   1.310 -     * @param clazz the class object of the expected type
   1.311 -     * @param name  the name of the parameter
   1.312 -     * @param <T>   the expected type
   1.313 -     * @return the parameter value or an empty optional, if no parameter with the specified name was found
   1.314 -     */
   1.315 -    protected <T> Optional<T> getParameter(HttpServletRequest req, Class<T> clazz, String name) {
   1.316 -        if (clazz.isArray()) {
   1.317 -            final String[] paramValues = req.getParameterValues(name);
   1.318 -            int len = paramValues == null ? 0 : paramValues.length;
   1.319 -            final var array = (T) Array.newInstance(clazz.getComponentType(), len);
   1.320 -            for (int i = 0; i < len; i++) {
   1.321 -                try {
   1.322 -                    final Constructor<?> ctor = clazz.getComponentType().getConstructor(String.class);
   1.323 -                    Array.set(array, i, ctor.newInstance(paramValues[i]));
   1.324 -                } catch (ReflectiveOperationException e) {
   1.325 -                    throw new RuntimeException(e);
   1.326 -                }
   1.327 -            }
   1.328 -            return Optional.of(array);
   1.329 -        } else {
   1.330 -            return parseParameter(req.getParameter(name), clazz);
   1.331 -        }
   1.332 -    }
   1.333 -
   1.334 -    /**
   1.335 -     * Tries to look up an entity with a key obtained from a request parameter.
   1.336 -     *
   1.337 -     * @param req   the servlet request object
   1.338 -     * @param clazz the class representing the type of the request parameter
   1.339 -     * @param name  the name of the request parameter
   1.340 -     * @param find  the find function (typically a DAO function)
   1.341 -     * @param <T>   the type of the request parameter
   1.342 -     * @param <R>   the type of the looked up entity
   1.343 -     * @return the retrieved entity or an empty optional if there is no such entity or the request parameter was missing
   1.344 -     * @throws SQLException if the find function throws an exception
   1.345 -     */
   1.346 -    protected <T, R> Optional<R> findByParameter(HttpServletRequest req, Class<T> clazz, String name, Function<? super T, ? extends R> find) {
   1.347 -        final var param = getParameter(req, clazz, name);
   1.348 -        if (param.isPresent()) {
   1.349 -            return Optional.ofNullable(find.apply(param.get()));
   1.350 -        } else {
   1.351 -            return Optional.empty();
   1.352 -        }
   1.353 -    }
   1.354 -
   1.355 -    protected void setAttributeFromParameter(HttpServletRequest req, String name) {
   1.356 -        final var parm = req.getParameter(name);
   1.357 -        if (parm != null) {
   1.358 -            req.setAttribute(name, parm);
   1.359 -        }
   1.360 -    }
   1.361 -
   1.362 -    private String sanitizeRequestPath(HttpServletRequest req) {
   1.363 -        return Optional.ofNullable(req.getPathInfo()).orElse("/");
   1.364 -    }
   1.365 -
   1.366 -    private Optional<Map.Entry<PathPattern, Method>> findMapping(HttpMethod method, HttpServletRequest req) {
   1.367 -        return Optional.ofNullable(mappings.get(method)).flatMap(rm ->
   1.368 -                rm.entrySet().stream().filter(
   1.369 -                        kv -> kv.getKey().matches(sanitizeRequestPath(req))
   1.370 -                ).findAny()
   1.371 -        );
   1.372 -    }
   1.373 -
   1.374 -    protected void renderSite(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   1.375 -        req.getRequestDispatcher(SITE_JSP).forward(req, resp);
   1.376 -    }
   1.377 -
   1.378 -    protected Optional<String[]> availableLanguages() {
   1.379 -        return Optional.ofNullable(getServletContext().getInitParameter(Constants.CTX_ATTR_LANGUAGES)).map((x) -> x.split("\\s*,\\s*"));
   1.380 -    }
   1.381 -
   1.382 -    private static String baseHref(HttpServletRequest req) {
   1.383 -        return String.format("%s://%s:%d%s/",
   1.384 -                req.getScheme(),
   1.385 -                req.getServerName(),
   1.386 -                req.getServerPort(),
   1.387 -                req.getContextPath());
   1.388 -    }
   1.389 -
   1.390 -    private static String enforceExt(String filename, String ext) {
   1.391 -        return filename.endsWith(ext) ? filename : filename + ext;
   1.392 -    }
   1.393 -
   1.394 -    private static String jspPath(String filename) {
   1.395 -        return enforceExt(Constants.JSP_PATH_PREFIX + filename, ".jsp");
   1.396 -    }
   1.397 -
   1.398 -    private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   1.399 -        // the very first thing to do is to force UTF-8
   1.400 -        req.setCharacterEncoding("UTF-8");
   1.401 -
   1.402 -        // choose the requested language as session language (if available) or fall back to english, otherwise
   1.403 -        HttpSession session = req.getSession();
   1.404 -        if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
   1.405 -            Optional<List<String>> availableLanguages = availableLanguages().map(Arrays::asList);
   1.406 -            Optional<Locale> reqLocale = Optional.of(req.getLocale());
   1.407 -            Locale sessionLocale = reqLocale.filter((rl) -> availableLanguages.map((al) -> al.contains(rl.getLanguage())).orElse(false)).orElse(Locale.ENGLISH);
   1.408 -            session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale);
   1.409 -            LOG.debug("Setting language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
   1.410 -        } else {
   1.411 -            Locale sessionLocale = (Locale) session.getAttribute(Constants.SESSION_ATTR_LANGUAGE);
   1.412 -            resp.setLocale(sessionLocale);
   1.413 -            LOG.trace("Continuing session {} with language {}", session.getId(), sessionLocale);
   1.414 -        }
   1.415 -
   1.416 -        // set some internal request attributes
   1.417 -        final String fullPath = req.getServletPath() + Optional.ofNullable(req.getPathInfo()).orElse("");
   1.418 -        req.setAttribute(Constants.REQ_ATTR_BASE_HREF, baseHref(req));
   1.419 -        req.setAttribute(Constants.REQ_ATTR_PATH, fullPath);
   1.420 -        req.setAttribute(Constants.REQ_ATTR_RESOURCE_BUNDLE, getResourceBundleName());
   1.421 -
   1.422 -        // if this is an error path, bypass the normal flow
   1.423 -        if (fullPath.startsWith("/error/")) {
   1.424 -            final var mapping = findMapping(method, req);
   1.425 -            if (mapping.isPresent()) {
   1.426 -                invokeMapping(mapping.get(), req, resp, null);
   1.427 -            }
   1.428 -            return;
   1.429 -        }
   1.430 -
   1.431 -        // obtain a connection and create the data access objects
   1.432 -        final var db = (DataSourceProvider) req.getServletContext().getAttribute(DataSourceProvider.Companion.getSC_ATTR_NAME());
   1.433 -        final var ds = db.getDataSource();
   1.434 -        if (ds == null) {
   1.435 -            resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "JNDI DataSource lookup failed. See log for details.");
   1.436 -            return;
   1.437 -        }
   1.438 -        try (final var connection = ds.getConnection()) {
   1.439 -            final var dao = createDataAccessObjects(connection);
   1.440 -            try {
   1.441 -                connection.setAutoCommit(false);
   1.442 -                // call the handler, if available, or send an HTTP 404 error
   1.443 -                final var mapping = findMapping(method, req);
   1.444 -                if (mapping.isPresent()) {
   1.445 -                    invokeMapping(mapping.get(), req, resp, dao);
   1.446 -                } else {
   1.447 -                    resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   1.448 -                }
   1.449 -                connection.commit();
   1.450 -            } catch (SQLException ex) {
   1.451 -                LOG.warn("Database transaction failed (Code {}): {}", ex.getErrorCode(), ex.getMessage());
   1.452 -                LOG.debug("Details: ", ex);
   1.453 -                resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unhandled Transaction Error - Code: " + ex.getErrorCode());
   1.454 -                connection.rollback();
   1.455 -            }
   1.456 -        } catch (SQLException ex) {
   1.457 -            LOG.error("Severe Database Exception (Code {}): {}", ex.getErrorCode(), ex.getMessage());
   1.458 -            LOG.debug("Details: ", ex);
   1.459 -            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Database Error - Code: " + ex.getErrorCode());
   1.460 -        }
   1.461 -    }
   1.462 -
   1.463 -    @Override
   1.464 -    protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
   1.465 -            throws ServletException, IOException {
   1.466 -        doProcess(HttpMethod.GET, req, resp);
   1.467 -    }
   1.468 -
   1.469 -    @Override
   1.470 -    protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
   1.471 -            throws ServletException, IOException {
   1.472 -        doProcess(HttpMethod.POST, req, resp);
   1.473 -    }
   1.474 -}

mercurial