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

Tue, 05 Jan 2021 19:19:31 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 05 Jan 2021 19:19:31 +0100
changeset 179
623c340058f3
parent 168
src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java@1c3694ae224c
child 180
009700915269
permissions
-rw-r--r--

migrates the utility classes for the AbstractServlet

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

mercurial