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

Wed, 06 Jan 2021 15:39:56 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 06 Jan 2021 15:39:56 +0100
changeset 180
009700915269
parent 179
623c340058f3
child 182
53f0e2685ad5
permissions
-rw-r--r--

merge resource bundles

universe@7 1 /*
universe@7 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@34 3 *
universe@180 4 * Copyright 2021 Mike Becker. All rights reserved.
universe@34 5 *
universe@7 6 * Redistribution and use in source and binary forms, with or without
universe@7 7 * modification, are permitted provided that the following conditions are met:
universe@7 8 *
universe@7 9 * 1. Redistributions of source code must retain the above copyright
universe@7 10 * notice, this list of conditions and the following disclaimer.
universe@7 11 *
universe@7 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@7 13 * notice, this list of conditions and the following disclaimer in the
universe@7 14 * documentation and/or other materials provided with the distribution.
universe@7 15 *
universe@7 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@7 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@7 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@7 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@7 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@7 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@7 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@7 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@7 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@7 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@7 26 * POSSIBILITY OF SUCH DAMAGE.
universe@34 27 *
universe@7 28 */
universe@7 29 package de.uapcore.lightpit;
universe@7 30
universe@167 31 import de.uapcore.lightpit.dao.DataAccessObject;
universe@167 32 import de.uapcore.lightpit.dao.PostgresDataAccessObject;
universe@33 33 import org.slf4j.Logger;
universe@33 34 import org.slf4j.LoggerFactory;
universe@33 35
universe@7 36 import javax.servlet.ServletException;
universe@7 37 import javax.servlet.http.HttpServlet;
universe@7 38 import javax.servlet.http.HttpServletRequest;
universe@7 39 import javax.servlet.http.HttpServletResponse;
universe@13 40 import javax.servlet.http.HttpSession;
universe@33 41 import java.io.IOException;
universe@83 42 import java.lang.reflect.*;
universe@38 43 import java.sql.Connection;
universe@38 44 import java.sql.SQLException;
universe@33 45 import java.util.*;
universe@63 46 import java.util.function.Function;
universe@163 47 import java.util.stream.Collectors;
universe@7 48
universe@7 49 /**
universe@7 50 * A special implementation of a HTTPServlet which is focused on implementing
universe@79 51 * the necessary functionality for LightPIT pages.
universe@7 52 */
universe@179 53 public abstract class AbstractServlet extends HttpServlet {
universe@34 54
universe@179 55 private static final Logger LOG = LoggerFactory.getLogger(AbstractServlet.class);
universe@34 56
universe@158 57 private static final String SITE_JSP = jspPath("site");
universe@33 58
universe@10 59 /**
universe@11 60 * Invocation mapping gathered from the {@link RequestMapping} annotations.
universe@34 61 * <p>
universe@18 62 * Paths in this map must always start with a leading slash, although
universe@18 63 * the specification in the annotation must not start with a leading slash.
universe@34 64 * <p>
universe@34 65 * The reason for this is the different handling of empty paths in
universe@18 66 * {@link HttpServletRequest#getPathInfo()}.
universe@11 67 */
universe@130 68 private final Map<HttpMethod, Map<PathPattern, Method>> mappings = new HashMap<>();
universe@11 69
universe@11 70 /**
universe@38 71 * Creates a set of data access objects for the specified connection.
universe@33 72 *
universe@38 73 * @param connection the SQL connection
universe@38 74 * @return a set of data access objects
universe@17 75 */
universe@167 76 private DataAccessObject createDataAccessObjects(Connection connection) {
universe@151 77 final var df = (DataSourceProvider) getServletContext().getAttribute(DataSourceProvider.Companion.getSC_ATTR_NAME());
universe@158 78 if (df.getDialect() == DataSourceProvider.Dialect.Postgres) {
universe@167 79 return new PostgresDataAccessObject(connection);
universe@38 80 }
universe@151 81 throw new UnsupportedOperationException("Non-exhaustive if-else - this is a bug.");
universe@17 82 }
universe@33 83
universe@167 84 private void invokeMapping(Map.Entry<PathPattern, Method> mapping, HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException {
universe@130 85 final var pathPattern = mapping.getKey();
universe@130 86 final var method = mapping.getValue();
universe@11 87 try {
universe@14 88 LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName());
universe@42 89 final var paramTypes = method.getParameterTypes();
universe@42 90 final var paramValues = new Object[paramTypes.length];
universe@42 91 for (int i = 0; i < paramTypes.length; i++) {
universe@42 92 if (paramTypes[i].isAssignableFrom(HttpServletRequest.class)) {
universe@42 93 paramValues[i] = req;
universe@42 94 } else if (paramTypes[i].isAssignableFrom(HttpServletResponse.class)) {
universe@42 95 paramValues[i] = resp;
universe@42 96 }
universe@167 97 if (paramTypes[i].isAssignableFrom(DataAccessObject.class)) {
universe@42 98 paramValues[i] = dao;
universe@42 99 }
universe@130 100 if (paramTypes[i].isAssignableFrom(PathParameters.class)) {
universe@130 101 paramValues[i] = pathPattern.obtainPathParameters(sanitizeRequestPath(req));
universe@130 102 }
universe@42 103 }
universe@157 104 method.invoke(this, paramValues);
universe@73 105 } catch (InvocationTargetException ex) {
universe@73 106 LOG.error("invocation of method {}::{} failed: {}",
universe@73 107 method.getDeclaringClass().getName(), method.getName(), ex.getTargetException().getMessage());
universe@73 108 LOG.debug("Details: ", ex.getTargetException());
universe@73 109 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getTargetException().getMessage());
universe@12 110 } catch (ReflectiveOperationException | ClassCastException ex) {
universe@73 111 LOG.error("invocation of method {}::{} failed: {}",
universe@73 112 method.getDeclaringClass().getName(), method.getName(), ex.getMessage());
universe@38 113 LOG.debug("Details: ", ex);
universe@73 114 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
universe@11 115 }
universe@11 116 }
universe@11 117
universe@11 118 @Override
universe@11 119 public void init() throws ServletException {
universe@78 120 scanForRequestMappings();
universe@33 121
universe@12 122 LOG.trace("{} initialized", getServletName());
universe@12 123 }
universe@12 124
universe@12 125 private void scanForRequestMappings() {
universe@12 126 try {
universe@11 127 Method[] methods = getClass().getDeclaredMethods();
universe@11 128 for (Method method : methods) {
universe@11 129 Optional<RequestMapping> mapping = Optional.ofNullable(method.getAnnotation(RequestMapping.class));
universe@11 130 if (mapping.isPresent()) {
universe@130 131 if (mapping.get().requestPath().isBlank()) {
universe@130 132 LOG.warn("{} is annotated with {} but request path is empty",
universe@130 133 method.getName(), RequestMapping.class.getSimpleName()
universe@130 134 );
universe@130 135 continue;
universe@130 136 }
universe@130 137
universe@11 138 if (!Modifier.isPublic(method.getModifiers())) {
universe@11 139 LOG.warn("{} is annotated with {} but is not public",
universe@11 140 method.getName(), RequestMapping.class.getSimpleName()
universe@11 141 );
universe@11 142 continue;
universe@11 143 }
universe@11 144 if (Modifier.isAbstract(method.getModifiers())) {
universe@11 145 LOG.warn("{} is annotated with {} but is abstract",
universe@11 146 method.getName(), RequestMapping.class.getSimpleName()
universe@11 147 );
universe@11 148 continue;
universe@11 149 }
universe@12 150
universe@42 151 boolean paramsInjectible = true;
universe@42 152 for (var param : method.getParameterTypes()) {
universe@42 153 paramsInjectible &= HttpServletRequest.class.isAssignableFrom(param)
universe@167 154 || HttpServletResponse.class.isAssignableFrom(param)
universe@167 155 || PathParameters.class.isAssignableFrom(param)
universe@167 156 || DataAccessObject.class.isAssignableFrom(param);
universe@42 157 }
universe@42 158 if (paramsInjectible) {
universe@130 159 try {
universe@130 160 PathPattern pathPattern = new PathPattern(mapping.get().requestPath());
universe@12 161
universe@131 162 final var methodMappings = mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>());
universe@131 163 final var currentMapping = methodMappings.putIfAbsent(pathPattern, method);
universe@131 164 if (currentMapping != null) {
universe@131 165 LOG.warn("Cannot map {} {} to {} in class {} - this would override the mapping to {}",
universe@130 166 mapping.get().method(),
universe@131 167 mapping.get().requestPath(),
universe@131 168 method.getName(),
universe@131 169 getClass().getSimpleName(),
universe@131 170 currentMapping.getName()
universe@130 171 );
universe@130 172 }
universe@130 173
universe@130 174 LOG.debug("{} {} maps to {}::{}",
universe@11 175 mapping.get().method(),
universe@130 176 mapping.get().requestPath(),
universe@130 177 getClass().getSimpleName(),
universe@130 178 method.getName()
universe@130 179 );
universe@130 180 } catch (IllegalArgumentException ex) {
universe@130 181 LOG.warn("Request mapping for {} failed: path pattern '{}' is syntactically invalid",
universe@130 182 method.getName(), mapping.get().requestPath()
universe@11 183 );
universe@11 184 }
universe@11 185 } else {
universe@130 186 LOG.warn("{} is annotated with {} but has the wrong parameters - only HttpServletRequest, HttpServletResponse, PathParameters, and DataAccessObjects are allowed",
universe@11 187 method.getName(), RequestMapping.class.getSimpleName()
universe@11 188 );
universe@11 189 }
universe@11 190 }
universe@11 191 }
universe@12 192 } catch (SecurityException ex) {
universe@12 193 LOG.error("Scan for request mappings on declared methods failed.", ex);
universe@11 194 }
universe@11 195 }
universe@11 196
universe@11 197 @Override
universe@11 198 public void destroy() {
universe@11 199 mappings.clear();
universe@11 200 LOG.trace("{} destroyed", getServletName());
universe@11 201 }
universe@34 202
universe@13 203 /**
universe@74 204 * Sets the name of the content page.
universe@34 205 * <p>
universe@13 206 * It is sufficient to specify the name without any extension. The extension
universe@13 207 * is added automatically if not specified.
universe@34 208 *
universe@74 209 * @param req the servlet request object
universe@74 210 * @param pageName the name of the content page
universe@74 211 * @see Constants#REQ_ATTR_CONTENT_PAGE
universe@13 212 */
universe@74 213 protected void setContentPage(HttpServletRequest req, String pageName) {
universe@158 214 req.setAttribute(Constants.REQ_ATTR_CONTENT_PAGE, jspPath(pageName));
universe@13 215 }
universe@34 216
universe@11 217 /**
universe@96 218 * Sets the navigation menu.
universe@71 219 *
universe@109 220 * @param req the servlet request object
universe@109 221 * @param jspName the name of the menu's jsp file
universe@96 222 * @see Constants#REQ_ATTR_NAVIGATION
universe@71 223 */
universe@109 224 protected void setNavigationMenu(HttpServletRequest req, String jspName) {
universe@158 225 req.setAttribute(Constants.REQ_ATTR_NAVIGATION, jspPath(jspName));
universe@71 226 }
universe@71 227
universe@71 228 /**
universe@47 229 * @param req the servlet request object
universe@47 230 * @param location the location where to redirect
universe@47 231 * @see Constants#REQ_ATTR_REDIRECT_LOCATION
universe@47 232 */
universe@63 233 protected void setRedirectLocation(HttpServletRequest req, String location) {
universe@47 234 if (location.startsWith("./")) {
universe@158 235 location = location.replaceFirst("\\./", baseHref(req));
universe@47 236 }
universe@47 237 req.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, location);
universe@47 238 }
universe@47 239
universe@47 240 /**
universe@163 241 * Specifies the names of additional stylesheets used by this Servlet.
universe@34 242 * <p>
universe@13 243 * It is sufficient to specify the name without any extension. The extension
universe@13 244 * is added automatically if not specified.
universe@34 245 *
universe@163 246 * @param req the servlet request object
universe@163 247 * @param stylesheets the names of the stylesheets
universe@11 248 */
universe@163 249 public void setStylesheet(HttpServletRequest req, String ... stylesheets) {
universe@163 250 req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Arrays
universe@163 251 .stream(stylesheets)
universe@163 252 .map(s -> enforceExt(s, ".css"))
universe@163 253 .collect(Collectors.toUnmodifiableList()));
universe@10 254 }
universe@34 255
universe@47 256 /**
universe@86 257 * Sets the view model object.
universe@86 258 * The type must match the expected type in the JSP file.
universe@86 259 *
universe@86 260 * @param req the servlet request object
universe@86 261 * @param viewModel the view model object
universe@86 262 */
universe@86 263 public void setViewModel(HttpServletRequest req, Object viewModel) {
universe@86 264 req.setAttribute(Constants.REQ_ATTR_VIEWMODEL, viewModel);
universe@86 265 }
universe@86 266
universe@131 267 private <T> Optional<T> parseParameter(String paramValue, Class<T> clazz) {
universe@131 268 if (paramValue == null) return Optional.empty();
universe@131 269 if (clazz.equals(Boolean.class)) {
universe@168 270 if (paramValue.equalsIgnoreCase("false") || paramValue.equals("0")) {
universe@131 271 return Optional.of((T) Boolean.FALSE);
universe@131 272 } else {
universe@131 273 return Optional.of((T) Boolean.TRUE);
universe@131 274 }
universe@131 275 }
universe@131 276 if (clazz.equals(String.class)) return Optional.of((T) paramValue);
universe@131 277 if (java.sql.Date.class.isAssignableFrom(clazz)) {
universe@131 278 try {
universe@131 279 return Optional.of((T) java.sql.Date.valueOf(paramValue));
universe@131 280 } catch (IllegalArgumentException ex) {
universe@131 281 return Optional.empty();
universe@131 282 }
universe@131 283 }
universe@131 284 try {
universe@131 285 final Constructor<T> ctor = clazz.getConstructor(String.class);
universe@131 286 return Optional.of(ctor.newInstance(paramValue));
universe@131 287 } catch (ReflectiveOperationException e) {
universe@131 288 // does not type check and is not convertible - treat as if the parameter was never set
universe@131 289 return Optional.empty();
universe@131 290 }
universe@131 291 }
universe@131 292
universe@86 293 /**
universe@47 294 * Obtains a request parameter of the specified type.
universe@47 295 * The specified type must have a single-argument constructor accepting a string to perform conversion.
universe@47 296 * The constructor of the specified type may throw an exception on conversion failures.
universe@47 297 *
universe@71 298 * @param req the servlet request object
universe@47 299 * @param clazz the class object of the expected type
universe@71 300 * @param name the name of the parameter
universe@71 301 * @param <T> the expected type
universe@47 302 * @return the parameter value or an empty optional, if no parameter with the specified name was found
universe@47 303 */
universe@71 304 protected <T> Optional<T> getParameter(HttpServletRequest req, Class<T> clazz, String name) {
universe@83 305 if (clazz.isArray()) {
universe@83 306 final String[] paramValues = req.getParameterValues(name);
universe@83 307 int len = paramValues == null ? 0 : paramValues.length;
universe@83 308 final var array = (T) Array.newInstance(clazz.getComponentType(), len);
universe@86 309 for (int i = 0; i < len; i++) {
universe@83 310 try {
universe@83 311 final Constructor<?> ctor = clazz.getComponentType().getConstructor(String.class);
universe@83 312 Array.set(array, i, ctor.newInstance(paramValues[i]));
universe@83 313 } catch (ReflectiveOperationException e) {
universe@83 314 throw new RuntimeException(e);
universe@83 315 }
universe@83 316 }
universe@83 317 return Optional.of(array);
universe@83 318 } else {
universe@131 319 return parseParameter(req.getParameter(name), clazz);
universe@80 320 }
universe@47 321 }
universe@47 322
universe@63 323 /**
universe@63 324 * Tries to look up an entity with a key obtained from a request parameter.
universe@63 325 *
universe@71 326 * @param req the servlet request object
universe@63 327 * @param clazz the class representing the type of the request parameter
universe@71 328 * @param name the name of the request parameter
universe@71 329 * @param find the find function (typically a DAO function)
universe@71 330 * @param <T> the type of the request parameter
universe@71 331 * @param <R> the type of the looked up entity
universe@63 332 * @return the retrieved entity or an empty optional if there is no such entity or the request parameter was missing
universe@63 333 * @throws SQLException if the find function throws an exception
universe@63 334 */
universe@167 335 protected <T, R> Optional<R> findByParameter(HttpServletRequest req, Class<T> clazz, String name, Function<? super T, ? extends R> find) {
universe@63 336 final var param = getParameter(req, clazz, name);
universe@63 337 if (param.isPresent()) {
universe@63 338 return Optional.ofNullable(find.apply(param.get()));
universe@63 339 } else {
universe@63 340 return Optional.empty();
universe@63 341 }
universe@63 342 }
universe@63 343
universe@168 344 protected void setAttributeFromParameter(HttpServletRequest req, String name) {
universe@168 345 final var parm = req.getParameter(name);
universe@168 346 if (parm != null) {
universe@168 347 req.setAttribute(name, parm);
universe@168 348 }
universe@168 349 }
universe@168 350
universe@45 351 private String sanitizeRequestPath(HttpServletRequest req) {
universe@45 352 return Optional.ofNullable(req.getPathInfo()).orElse("/");
universe@45 353 }
universe@45 354
universe@130 355 private Optional<Map.Entry<PathPattern, Method>> findMapping(HttpMethod method, HttpServletRequest req) {
universe@130 356 return Optional.ofNullable(mappings.get(method)).flatMap(rm ->
universe@130 357 rm.entrySet().stream().filter(
universe@130 358 kv -> kv.getKey().matches(sanitizeRequestPath(req))
universe@130 359 ).findAny()
universe@130 360 );
universe@11 361 }
universe@34 362
universe@157 363 protected void renderSite(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
universe@157 364 req.getRequestDispatcher(SITE_JSP).forward(req, resp);
universe@12 365 }
universe@34 366
universe@158 367 protected Optional<String[]> availableLanguages() {
universe@158 368 return Optional.ofNullable(getServletContext().getInitParameter(Constants.CTX_ATTR_LANGUAGES)).map((x) -> x.split("\\s*,\\s*"));
universe@158 369 }
universe@158 370
universe@158 371 private static String baseHref(HttpServletRequest req) {
universe@158 372 return String.format("%s://%s:%d%s/",
universe@158 373 req.getScheme(),
universe@158 374 req.getServerName(),
universe@158 375 req.getServerPort(),
universe@158 376 req.getContextPath());
universe@158 377 }
universe@158 378
universe@158 379 private static String enforceExt(String filename, String ext) {
universe@158 380 return filename.endsWith(ext) ? filename : filename + ext;
universe@158 381 }
universe@158 382
universe@158 383 private static String jspPath(String filename) {
universe@158 384 return enforceExt(Constants.JSP_PATH_PREFIX + filename, ".jsp");
universe@158 385 }
universe@158 386
universe@38 387 private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
universe@160 388 // the very first thing to do is to force UTF-8
universe@160 389 req.setCharacterEncoding("UTF-8");
universe@27 390
universe@13 391 // choose the requested language as session language (if available) or fall back to english, otherwise
universe@20 392 HttpSession session = req.getSession();
universe@13 393 if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
universe@158 394 Optional<List<String>> availableLanguages = availableLanguages().map(Arrays::asList);
universe@13 395 Optional<Locale> reqLocale = Optional.of(req.getLocale());
universe@13 396 Locale sessionLocale = reqLocale.filter((rl) -> availableLanguages.map((al) -> al.contains(rl.getLanguage())).orElse(false)).orElse(Locale.ENGLISH);
universe@13 397 session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale);
universe@34 398 LOG.debug("Setting language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
universe@14 399 } else {
universe@15 400 Locale sessionLocale = (Locale) session.getAttribute(Constants.SESSION_ATTR_LANGUAGE);
universe@15 401 resp.setLocale(sessionLocale);
universe@15 402 LOG.trace("Continuing session {} with language {}", session.getId(), sessionLocale);
universe@13 403 }
universe@34 404
universe@21 405 // set some internal request attributes
universe@158 406 final String fullPath = req.getServletPath() + Optional.ofNullable(req.getPathInfo()).orElse("");
universe@158 407 req.setAttribute(Constants.REQ_ATTR_BASE_HREF, baseHref(req));
universe@53 408 req.setAttribute(Constants.REQ_ATTR_PATH, fullPath);
universe@34 409
universe@53 410 // if this is an error path, bypass the normal flow
universe@53 411 if (fullPath.startsWith("/error/")) {
universe@53 412 final var mapping = findMapping(method, req);
universe@53 413 if (mapping.isPresent()) {
universe@157 414 invokeMapping(mapping.get(), req, resp, null);
universe@53 415 }
universe@53 416 return;
universe@53 417 }
universe@53 418
universe@38 419 // obtain a connection and create the data access objects
universe@151 420 final var db = (DataSourceProvider) req.getServletContext().getAttribute(DataSourceProvider.Companion.getSC_ATTR_NAME());
universe@53 421 final var ds = db.getDataSource();
universe@53 422 if (ds == null) {
universe@53 423 resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "JNDI DataSource lookup failed. See log for details.");
universe@53 424 return;
universe@53 425 }
universe@53 426 try (final var connection = ds.getConnection()) {
universe@38 427 final var dao = createDataAccessObjects(connection);
universe@39 428 try {
universe@39 429 connection.setAutoCommit(false);
universe@39 430 // call the handler, if available, or send an HTTP 404 error
universe@39 431 final var mapping = findMapping(method, req);
universe@39 432 if (mapping.isPresent()) {
universe@157 433 invokeMapping(mapping.get(), req, resp, dao);
universe@39 434 } else {
universe@39 435 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@39 436 }
universe@39 437 connection.commit();
universe@39 438 } catch (SQLException ex) {
universe@39 439 LOG.warn("Database transaction failed (Code {}): {}", ex.getErrorCode(), ex.getMessage());
universe@39 440 LOG.debug("Details: ", ex);
universe@54 441 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unhandled Transaction Error - Code: " + ex.getErrorCode());
universe@39 442 connection.rollback();
universe@38 443 }
universe@38 444 } catch (SQLException ex) {
universe@39 445 LOG.error("Severe Database Exception (Code {}): {}", ex.getErrorCode(), ex.getMessage());
universe@38 446 LOG.debug("Details: ", ex);
universe@54 447 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Database Error - Code: " + ex.getErrorCode());
universe@12 448 }
universe@12 449 }
universe@34 450
universe@7 451 @Override
universe@7 452 protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
universe@7 453 throws ServletException, IOException {
universe@12 454 doProcess(HttpMethod.GET, req, resp);
universe@7 455 }
universe@7 456
universe@7 457 @Override
universe@7 458 protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
universe@7 459 throws ServletException, IOException {
universe@12 460 doProcess(HttpMethod.POST, req, resp);
universe@7 461 }
universe@7 462 }

mercurial