adds DAO for Project entity and save/update methods

Mon, 11 May 2020 19:09:06 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 11 May 2020 19:09:06 +0200
changeset 38
cf85ef18f231
parent 37
fecda0f466e6
child 39
e722861558bb

adds DAO for Project entity and save/update methods

src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/DatabaseFacade.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/AbstractDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/GenericDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/ProjectDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/Project.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/Version.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/VersionStatus.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sun May 10 10:58:31 2020 +0200
     1.2 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Mon May 11 19:09:06 2020 +0200
     1.3 @@ -28,6 +28,8 @@
     1.4   */
     1.5  package de.uapcore.lightpit;
     1.6  
     1.7 +import de.uapcore.lightpit.dao.DataAccessObjects;
     1.8 +import de.uapcore.lightpit.dao.postgres.PGDataAccessObjects;
     1.9  import org.slf4j.Logger;
    1.10  import org.slf4j.LoggerFactory;
    1.11  
    1.12 @@ -39,6 +41,8 @@
    1.13  import java.io.IOException;
    1.14  import java.lang.reflect.Method;
    1.15  import java.lang.reflect.Modifier;
    1.16 +import java.sql.Connection;
    1.17 +import java.sql.SQLException;
    1.18  import java.util.*;
    1.19  
    1.20  /**
    1.21 @@ -59,7 +63,7 @@
    1.22  
    1.23      @FunctionalInterface
    1.24      private interface HandlerMethod {
    1.25 -        ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException;
    1.26 +        ResponseType apply(HttpServletRequest request, HttpServletResponse response, DataAccessObjects dao) throws IOException, SQLException;
    1.27      }
    1.28  
    1.29      /**
    1.30 @@ -82,21 +86,30 @@
    1.31          return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME);
    1.32      }
    1.33  
    1.34 +
    1.35      /**
    1.36 -     * Gives implementing modules access to the {@link DatabaseFacade}.
    1.37 +     * Creates a set of data access objects for the specified connection.
    1.38       *
    1.39 -     * @return the database facade
    1.40 +     * @param connection the SQL connection
    1.41 +     * @return a set of data access objects
    1.42       */
    1.43 -    protected final DatabaseFacade getDatabaseFacade() {
    1.44 -        return (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME);
    1.45 +    private DataAccessObjects createDataAccessObjects(Connection connection) throws SQLException {
    1.46 +        final var df = (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME);
    1.47 +        switch (df.getSQLDialect()) {
    1.48 +            case Postgres:
    1.49 +                return new PGDataAccessObjects(connection);
    1.50 +            default:
    1.51 +                throw new AssertionError("Non-exhaustive switch - this is a bug.");
    1.52 +        }
    1.53      }
    1.54  
    1.55 -    private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp) throws IOException {
    1.56 +    private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException {
    1.57          try {
    1.58              LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName());
    1.59 -            return (ResponseType) method.invoke(this, req, resp);
    1.60 +            return (ResponseType) method.invoke(this, req, resp, dao);
    1.61          } catch (ReflectiveOperationException | ClassCastException ex) {
    1.62 -            LOG.error(String.format("invocation of method %s failed", method.getName()), ex);
    1.63 +            LOG.error("invocation of method {} failed: {}", method.getName(), ex.getMessage());
    1.64 +            LOG.debug("Details: ", ex);
    1.65              resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    1.66              return ResponseType.NONE;
    1.67          }
    1.68 @@ -140,15 +153,16 @@
    1.69                      }
    1.70  
    1.71                      Class<?>[] params = method.getParameterTypes();
    1.72 -                    if (params.length == 2
    1.73 +                    if (params.length == 3
    1.74                              && HttpServletRequest.class.isAssignableFrom(params[0])
    1.75 -                            && HttpServletResponse.class.isAssignableFrom(params[1])) {
    1.76 +                            && HttpServletResponse.class.isAssignableFrom(params[1])
    1.77 +                            && DataAccessObjects.class.isAssignableFrom(params[2])) {
    1.78  
    1.79                          final String requestPath = "/" + mapping.get().requestPath();
    1.80  
    1.81                          if (mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()).
    1.82                                  putIfAbsent(requestPath,
    1.83 -                                        (req, resp) -> invokeMapping(method, req, resp)) != null) {
    1.84 +                                        (req, resp, dao) -> invokeMapping(method, req, resp, dao)) != null) {
    1.85                              LOG.warn("{} {} has multiple mappings",
    1.86                                      mapping.get().method(),
    1.87                                      mapping.get().requestPath()
    1.88 @@ -238,8 +252,7 @@
    1.89          }
    1.90      }
    1.91  
    1.92 -    private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp)
    1.93 -            throws ServletException, IOException {
    1.94 +    private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    1.95  
    1.96          // choose the requested language as session language (if available) or fall back to english, otherwise
    1.97          HttpSession session = req.getSession();
    1.98 @@ -260,13 +273,21 @@
    1.99          req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName());
   1.100          Optional.ofNullable(moduleInfo).ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy));
   1.101  
   1.102 -
   1.103 -        // call the handler, if available, or send an HTTP 404 error
   1.104 -        Optional<HandlerMethod> mapping = findMapping(method, req);
   1.105 -        if (mapping.isPresent()) {
   1.106 -            forwardAsSpecified(mapping.get().apply(req, resp), req, resp);
   1.107 -        } else {
   1.108 -            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   1.109 +        // obtain a connection and create the data access objects
   1.110 +        final var db = (DatabaseFacade) req.getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME);
   1.111 +        try (final var connection = db.getDataSource().getConnection()) {
   1.112 +            final var dao = createDataAccessObjects(connection);
   1.113 +            // call the handler, if available, or send an HTTP 404 error
   1.114 +            final var mapping = findMapping(method, req);
   1.115 +            if (mapping.isPresent()) {
   1.116 +                forwardAsSpecified(mapping.get().apply(req, resp, dao), req, resp);
   1.117 +            } else {
   1.118 +                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   1.119 +            }
   1.120 +        } catch (SQLException ex) {
   1.121 +            LOG.error("Database exception (Code {}): {}", ex.getErrorCode(), ex.getMessage());
   1.122 +            LOG.debug("Details: ", ex);
   1.123 +            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Database Error - Code:" + ex.getErrorCode());
   1.124          }
   1.125      }
   1.126  
     2.1 --- a/src/main/java/de/uapcore/lightpit/DatabaseFacade.java	Sun May 10 10:58:31 2020 +0200
     2.2 +++ b/src/main/java/de/uapcore/lightpit/DatabaseFacade.java	Mon May 11 19:09:06 2020 +0200
     2.3 @@ -28,8 +28,6 @@
     2.4   */
     2.5  package de.uapcore.lightpit;
     2.6  
     2.7 -import de.uapcore.lightpit.dao.DataAccessObjects;
     2.8 -import de.uapcore.lightpit.dao.postgres.PGDataAccessObjects;
     2.9  import org.slf4j.Logger;
    2.10  import org.slf4j.LoggerFactory;
    2.11  
    2.12 @@ -91,29 +89,14 @@
    2.13  
    2.14      private static final String DS_JNDI_NAME = "jdbc/lightpit/app";
    2.15      private DataSource dataSource;
    2.16 -    private DataAccessObjects dataAccessObjects;
    2.17  
    2.18      /**
    2.19       * Returns the data source.
    2.20 -     * <p>
    2.21 -     * The Optional returned should never be empty. However, if something goes
    2.22 -     * wrong during initialization, the data source might be absent.
    2.23 -     * Hence, users of this data source are forced to check the existence.
    2.24       *
    2.25       * @return a data source
    2.26       */
    2.27 -    public Optional<DataSource> getDataSource() {
    2.28 -        // TODO: this should not be an optional, if an empty optional is actually an exception
    2.29 -        return Optional.ofNullable(dataSource);
    2.30 -    }
    2.31 -
    2.32 -    /**
    2.33 -     * Returns the data access objects.
    2.34 -     *
    2.35 -     * @return an interface to obtain the data access objects
    2.36 -     */
    2.37 -    public DataAccessObjects getDataAccessObjects() {
    2.38 -        return dataAccessObjects;
    2.39 +    public DataSource getDataSource() {
    2.40 +        return dataSource;
    2.41      }
    2.42  
    2.43      public Dialect getSQLDialect() {
    2.44 @@ -171,8 +154,6 @@
    2.45              }
    2.46          }
    2.47  
    2.48 -        dataAccessObjects = createDataAccessObjects(dialect);
    2.49 -
    2.50          try {
    2.51              LOG.debug("Trying to access JNDI context {}...", contextName);
    2.52              Context initialCtx = new InitialContext();
    2.53 @@ -191,15 +172,6 @@
    2.54          LOG.info("Database facade injected into ServletContext.");
    2.55      }
    2.56  
    2.57 -    private static DataAccessObjects createDataAccessObjects(Dialect dialect) {
    2.58 -        switch (dialect) {
    2.59 -            case Postgres:
    2.60 -                return new PGDataAccessObjects();
    2.61 -            default:
    2.62 -                throw new AssertionError("Non-exhaustive switch - this is a bug.");
    2.63 -        }
    2.64 -    }
    2.65 -
    2.66      @Override
    2.67      public void contextDestroyed(ServletContextEvent sce) {
    2.68          dataSource = null;
     3.1 --- a/src/main/java/de/uapcore/lightpit/dao/AbstractDao.java	Sun May 10 10:58:31 2020 +0200
     3.2 +++ b/src/main/java/de/uapcore/lightpit/dao/AbstractDao.java	Mon May 11 19:09:06 2020 +0200
     3.3 @@ -28,24 +28,65 @@
     3.4   */
     3.5  package de.uapcore.lightpit.dao;
     3.6  
     3.7 -import java.sql.Connection;
     3.8  import java.sql.PreparedStatement;
     3.9  import java.sql.ResultSet;
    3.10  import java.sql.SQLException;
    3.11 +import java.sql.Types;
    3.12  import java.util.ArrayList;
    3.13  import java.util.List;
    3.14 +import java.util.Optional;
    3.15 +import java.util.function.Function;
    3.16  
    3.17  public abstract class AbstractDao<T> implements GenericDao<T> {
    3.18  
    3.19 -    protected abstract PreparedStatement listQuery(Connection connection) throws SQLException;
    3.20 +    private final PreparedStatement listQuery;
    3.21  
    3.22 -    protected abstract T mapColumns(ResultSet result) throws SQLException;
    3.23 +    protected AbstractDao(PreparedStatement listQuery) {
    3.24 +        this.listQuery = listQuery;
    3.25 +    }
    3.26 +
    3.27 +    public final T mapColumns(ResultSet result) throws SQLException {
    3.28 +        return mapColumns(result, "");
    3.29 +    }
    3.30 +
    3.31 +    public abstract T mapColumns(ResultSet result, String qualifier) throws SQLException;
    3.32 +
    3.33 +    /**
    3.34 +     * Qualifies a column label if an qualifier is specified.
    3.35 +     *
    3.36 +     * @param qualifier an optional qualifier
    3.37 +     * @param label     the column label
    3.38 +     * @return the label, qualified if necessary
    3.39 +     */
    3.40 +    protected final String qual(String qualifier, String label) {
    3.41 +        if (qualifier == null || qualifier.isBlank()) {
    3.42 +            return label;
    3.43 +        } else {
    3.44 +            return qualifier + "." + label;
    3.45 +        }
    3.46 +    }
    3.47 +
    3.48 +    protected final void setStringOrNull(PreparedStatement stmt, int index, String str) throws SQLException {
    3.49 +        if (str == null || str.isBlank()) {
    3.50 +            stmt.setNull(index, Types.VARCHAR);
    3.51 +        } else {
    3.52 +            stmt.setString(index, str);
    3.53 +        }
    3.54 +    }
    3.55 +
    3.56 +    protected final <T> void setForeignKeyOrNull(PreparedStatement stmt, int index, T instance, Function<T, Integer> keyGetter) throws SQLException {
    3.57 +        Integer key = Optional.ofNullable(instance).map(keyGetter).orElse(null);
    3.58 +        if (key == null) {
    3.59 +            stmt.setNull(index, Types.INTEGER);
    3.60 +        } else {
    3.61 +            stmt.setInt(index, key);
    3.62 +        }
    3.63 +    }
    3.64  
    3.65      @Override
    3.66 -    public List<T> list(Connection conn) throws SQLException {
    3.67 +    public List<T> list() throws SQLException {
    3.68          List<T> list = new ArrayList<>();
    3.69 -        try (PreparedStatement stmt = listQuery(conn);
    3.70 -             ResultSet result = stmt.executeQuery()) {
    3.71 +        try (ResultSet result = listQuery.executeQuery()) {
    3.72              while (result.next()) {
    3.73                  list.add(mapColumns(result));
    3.74              }
     4.1 --- a/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java	Sun May 10 10:58:31 2020 +0200
     4.2 +++ b/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java	Mon May 11 19:09:06 2020 +0200
     4.3 @@ -30,4 +30,6 @@
     4.4  
     4.5  public interface DataAccessObjects {
     4.6      UserDao getUserDao();
     4.7 +
     4.8 +    ProjectDao getProjectDao();
     4.9  }
     5.1 --- a/src/main/java/de/uapcore/lightpit/dao/GenericDao.java	Sun May 10 10:58:31 2020 +0200
     5.2 +++ b/src/main/java/de/uapcore/lightpit/dao/GenericDao.java	Mon May 11 19:09:06 2020 +0200
     5.3 @@ -28,7 +28,6 @@
     5.4   */
     5.5  package de.uapcore.lightpit.dao;
     5.6  
     5.7 -import java.sql.Connection;
     5.8  import java.sql.SQLException;
     5.9  import java.util.List;
    5.10  
    5.11 @@ -36,9 +35,38 @@
    5.12      /**
    5.13       * Returns a list of all entities.
    5.14       *
    5.15 -     * @param connection conn the connection to use
    5.16       * @return a list of all objects
    5.17       * @throws SQLException on any kind of SQL errors
    5.18       */
    5.19 -    List<T> list(Connection connection) throws SQLException;
    5.20 +    List<T> list() throws SQLException;
    5.21 +
    5.22 +    /**
    5.23 +     * Inserts an instance into database.
    5.24 +     *
    5.25 +     * @param instance the instance to insert
    5.26 +     * @throws SQLException on any kind of SQL errors
    5.27 +     */
    5.28 +    void save(T instance) throws SQLException;
    5.29 +
    5.30 +    /**
    5.31 +     * Updates an instance in the database.
    5.32 +     *
    5.33 +     * @param instance the instance to insert
    5.34 +     * @return true if an instance has been updated, false if no instance with the specified ID was found
    5.35 +     * @throws SQLException on any kind of SQL errors
    5.36 +     */
    5.37 +    boolean update(T instance) throws SQLException;
    5.38 +
    5.39 +    /**
    5.40 +     * Inserts or updates an instance in the database.
    5.41 +     * Tries an update first and if that fails, performs a save.
    5.42 +     *
    5.43 +     * @param instance the instance to insert or update
    5.44 +     * @throws SQLException on any kind of SQL errors
    5.45 +     * @see #update(Object)
    5.46 +     * @see #save(Object)
    5.47 +     */
    5.48 +    default void saveOrUpdate(T instance) throws SQLException {
    5.49 +        if (!update(instance)) save(instance);
    5.50 +    }
    5.51  }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/main/java/de/uapcore/lightpit/dao/ProjectDao.java	Mon May 11 19:09:06 2020 +0200
     6.3 @@ -0,0 +1,34 @@
     6.4 +/*
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright 2018 Mike Becker. All rights reserved.
     6.8 + *
     6.9 + * Redistribution and use in source and binary forms, with or without
    6.10 + * modification, are permitted provided that the following conditions are met:
    6.11 + *
    6.12 + *   1. Redistributions of source code must retain the above copyright
    6.13 + *      notice, this list of conditions and the following disclaimer.
    6.14 + *
    6.15 + *   2. Redistributions in binary form must reproduce the above copyright
    6.16 + *      notice, this list of conditions and the following disclaimer in the
    6.17 + *      documentation and/or other materials provided with the distribution.
    6.18 + *
    6.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    6.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    6.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    6.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    6.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    6.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    6.29 + * POSSIBILITY OF SUCH DAMAGE.
    6.30 + *
    6.31 + */
    6.32 +package de.uapcore.lightpit.dao;
    6.33 +
    6.34 +import de.uapcore.lightpit.entities.Project;
    6.35 +
    6.36 +public interface ProjectDao extends GenericDao<Project> {
    6.37 +}
     7.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java	Sun May 10 10:58:31 2020 +0200
     7.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java	Mon May 11 19:09:06 2020 +0200
     7.3 @@ -29,14 +29,30 @@
     7.4  package de.uapcore.lightpit.dao.postgres;
     7.5  
     7.6  import de.uapcore.lightpit.dao.DataAccessObjects;
     7.7 +import de.uapcore.lightpit.dao.ProjectDao;
     7.8  import de.uapcore.lightpit.dao.UserDao;
     7.9  
    7.10 +import java.sql.Connection;
    7.11 +import java.sql.SQLException;
    7.12 +
    7.13  public class PGDataAccessObjects implements DataAccessObjects {
    7.14  
    7.15 -    private final UserDao userDao = new PGUserDao();
    7.16 +    private final UserDao userDao;
    7.17 +    private final ProjectDao projectDao;
    7.18 +
    7.19 +    public PGDataAccessObjects(Connection connection) throws SQLException {
    7.20 +        final PGUserDao pgUserDao = new PGUserDao(connection);
    7.21 +        userDao = pgUserDao;
    7.22 +        projectDao = new PGProjectDao(connection, pgUserDao);
    7.23 +    }
    7.24  
    7.25      @Override
    7.26      public UserDao getUserDao() {
    7.27          return userDao;
    7.28      }
    7.29 +
    7.30 +    @Override
    7.31 +    public ProjectDao getProjectDao() {
    7.32 +        return projectDao;
    7.33 +    }
    7.34  }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java	Mon May 11 19:09:06 2020 +0200
     8.3 @@ -0,0 +1,92 @@
     8.4 +/*
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + *
     8.7 + * Copyright 2018 Mike Becker. All rights reserved.
     8.8 + *
     8.9 + * Redistribution and use in source and binary forms, with or without
    8.10 + * modification, are permitted provided that the following conditions are met:
    8.11 + *
    8.12 + *   1. Redistributions of source code must retain the above copyright
    8.13 + *      notice, this list of conditions and the following disclaimer.
    8.14 + *
    8.15 + *   2. Redistributions in binary form must reproduce the above copyright
    8.16 + *      notice, this list of conditions and the following disclaimer in the
    8.17 + *      documentation and/or other materials provided with the distribution.
    8.18 + *
    8.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    8.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    8.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    8.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    8.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    8.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    8.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    8.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    8.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    8.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    8.29 + * POSSIBILITY OF SUCH DAMAGE.
    8.30 + *
    8.31 + */
    8.32 +package de.uapcore.lightpit.dao.postgres;
    8.33 +
    8.34 +import de.uapcore.lightpit.dao.AbstractDao;
    8.35 +import de.uapcore.lightpit.dao.ProjectDao;
    8.36 +import de.uapcore.lightpit.entities.Project;
    8.37 +import de.uapcore.lightpit.entities.User;
    8.38 +
    8.39 +import java.sql.Connection;
    8.40 +import java.sql.PreparedStatement;
    8.41 +import java.sql.ResultSet;
    8.42 +import java.sql.SQLException;
    8.43 +import java.util.Objects;
    8.44 +
    8.45 +public final class PGProjectDao extends AbstractDao<Project> implements ProjectDao {
    8.46 +
    8.47 +    private final PGUserDao userDao;
    8.48 +
    8.49 +    private final PreparedStatement insert;
    8.50 +    private final PreparedStatement update;
    8.51 +
    8.52 +    public PGProjectDao(Connection connection, PGUserDao userDao) throws SQLException {
    8.53 +        super(connection.prepareStatement(
    8.54 +                "select * from lpit_project join lpit_user owner on lpit_project.owner = owner.userid"));
    8.55 +
    8.56 +        insert = connection.prepareStatement(
    8.57 +                "insert into lpit_project (name, description, repourl, owner) values (?, ?, ?, ?)"
    8.58 +        );
    8.59 +        update = connection.prepareStatement(
    8.60 +                "update lpit_project set name = ?, description = ?, repourl = ?, owner = ? where id = ?"
    8.61 +        );
    8.62 +
    8.63 +        this.userDao = userDao;
    8.64 +    }
    8.65 +
    8.66 +    @Override
    8.67 +    public Project mapColumns(ResultSet result, String q) throws SQLException {
    8.68 +        final var proj = new Project(result.getInt(qual(q, "id")));
    8.69 +        proj.setName(result.getString(qual(q, "name")));
    8.70 +        proj.setDescription(result.getString(qual(q, "description")));
    8.71 +        proj.setRepoUrl(result.getString(qual(q, "repourl")));
    8.72 +        proj.setOwner(userDao.mapColumns(result, "owner"));
    8.73 +        return proj;
    8.74 +    }
    8.75 +
    8.76 +    @Override
    8.77 +    public void save(Project instance) throws SQLException {
    8.78 +        Objects.requireNonNull(instance.getName());
    8.79 +        insert.setString(1, instance.getName());
    8.80 +        setStringOrNull(insert, 2, instance.getDescription());
    8.81 +        setStringOrNull(insert, 3, instance.getRepoUrl());
    8.82 +        setForeignKeyOrNull(insert, 4, instance.getOwner(), User::getUserID);
    8.83 +        insert.executeUpdate();
    8.84 +    }
    8.85 +
    8.86 +    @Override
    8.87 +    public boolean update(Project instance) throws SQLException {
    8.88 +        Objects.requireNonNull(instance.getName());
    8.89 +        update.setString(1, instance.getName());
    8.90 +        setStringOrNull(update, 2, instance.getDescription());
    8.91 +        setStringOrNull(update, 3, instance.getRepoUrl());
    8.92 +        setForeignKeyOrNull(update, 4, instance.getOwner(), User::getUserID);
    8.93 +        return update.executeUpdate() > 0;
    8.94 +    }
    8.95 +}
     9.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java	Sun May 10 10:58:31 2020 +0200
     9.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java	Mon May 11 19:09:06 2020 +0200
     9.3 @@ -36,20 +36,45 @@
     9.4  import java.sql.PreparedStatement;
     9.5  import java.sql.ResultSet;
     9.6  import java.sql.SQLException;
     9.7 +import java.util.Objects;
     9.8  
     9.9  public final class PGUserDao extends AbstractDao<User> implements UserDao {
    9.10  
    9.11 +    private final PreparedStatement insert;
    9.12 +    private final PreparedStatement update;
    9.13 +
    9.14 +    public PGUserDao(Connection connection) throws SQLException {
    9.15 +        super(connection.prepareStatement("select * from lpit_user where userid >= 0 order by username"));
    9.16 +
    9.17 +        insert = connection.prepareStatement("insert into lpit_user (username, lastname, givenname, mail) values (?, ?, ?, ?)");
    9.18 +        update = connection.prepareStatement("update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?");
    9.19 +    }
    9.20 +
    9.21      @Override
    9.22 -    protected User mapColumns(ResultSet result) throws SQLException {
    9.23 -        final var user = new User(result.getInt("userid"));
    9.24 -        user.setUsername(result.getString("username"));
    9.25 -        user.setGivenname(result.getString("givenname"));
    9.26 -        user.setLastname(result.getString("lastname"));
    9.27 +    public User mapColumns(ResultSet result, String q) throws SQLException {
    9.28 +        final var user = new User(result.getInt(qual(q, "userid")));
    9.29 +        user.setUsername(result.getString(qual(q, "username")));
    9.30 +        user.setGivenname(result.getString(qual(q, "givenname")));
    9.31 +        user.setLastname(result.getString(qual(q, "lastname")));
    9.32          return user;
    9.33      }
    9.34  
    9.35      @Override
    9.36 -    protected PreparedStatement listQuery(Connection conn) throws SQLException {
    9.37 -        return conn.prepareStatement("select * from lpit_user where userid >= 0 order by username");
    9.38 +    public void save(User instance) throws SQLException {
    9.39 +        Objects.requireNonNull(instance.getUsername());
    9.40 +        insert.setString(1, instance.getUsername());
    9.41 +        setStringOrNull(insert, 2, instance.getLastname());
    9.42 +        setStringOrNull(insert, 3, instance.getGivenname());
    9.43 +        setStringOrNull(insert, 4, instance.getMail());
    9.44 +        insert.executeUpdate();
    9.45 +    }
    9.46 +
    9.47 +    @Override
    9.48 +    public boolean update(User instance) throws SQLException {
    9.49 +        setStringOrNull(update, 1, instance.getLastname());
    9.50 +        setStringOrNull(update, 2, instance.getGivenname());
    9.51 +        setStringOrNull(update, 3, instance.getMail());
    9.52 +        update.setInt(4, instance.getUserID());
    9.53 +        return update.executeUpdate() > 0;
    9.54      }
    9.55  }
    10.1 --- a/src/main/java/de/uapcore/lightpit/entities/Project.java	Sun May 10 10:58:31 2020 +0200
    10.2 +++ b/src/main/java/de/uapcore/lightpit/entities/Project.java	Mon May 11 19:09:06 2020 +0200
    10.3 @@ -1,3 +1,31 @@
    10.4 +/*
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright 2018 Mike Becker. All rights reserved.
    10.8 + *
    10.9 + * Redistribution and use in source and binary forms, with or without
   10.10 + * modification, are permitted provided that the following conditions are met:
   10.11 + *
   10.12 + *   1. Redistributions of source code must retain the above copyright
   10.13 + *      notice, this list of conditions and the following disclaimer.
   10.14 + *
   10.15 + *   2. Redistributions in binary form must reproduce the above copyright
   10.16 + *      notice, this list of conditions and the following disclaimer in the
   10.17 + *      documentation and/or other materials provided with the distribution.
   10.18 + *
   10.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   10.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   10.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   10.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   10.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   10.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   10.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   10.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   10.29 + * POSSIBILITY OF SUCH DAMAGE.
   10.30 + *
   10.31 + */
   10.32  package de.uapcore.lightpit.entities;
   10.33  
   10.34  import java.util.ArrayList;
    11.1 --- a/src/main/java/de/uapcore/lightpit/entities/Version.java	Sun May 10 10:58:31 2020 +0200
    11.2 +++ b/src/main/java/de/uapcore/lightpit/entities/Version.java	Mon May 11 19:09:06 2020 +0200
    11.3 @@ -1,3 +1,31 @@
    11.4 +/*
    11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 + *
    11.7 + * Copyright 2018 Mike Becker. All rights reserved.
    11.8 + *
    11.9 + * Redistribution and use in source and binary forms, with or without
   11.10 + * modification, are permitted provided that the following conditions are met:
   11.11 + *
   11.12 + *   1. Redistributions of source code must retain the above copyright
   11.13 + *      notice, this list of conditions and the following disclaimer.
   11.14 + *
   11.15 + *   2. Redistributions in binary form must reproduce the above copyright
   11.16 + *      notice, this list of conditions and the following disclaimer in the
   11.17 + *      documentation and/or other materials provided with the distribution.
   11.18 + *
   11.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   11.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   11.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   11.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   11.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   11.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   11.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   11.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   11.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   11.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   11.29 + * POSSIBILITY OF SUCH DAMAGE.
   11.30 + *
   11.31 + */
   11.32  package de.uapcore.lightpit.entities;
   11.33  
   11.34  import java.util.Objects;
    12.1 --- a/src/main/java/de/uapcore/lightpit/entities/VersionStatus.java	Sun May 10 10:58:31 2020 +0200
    12.2 +++ b/src/main/java/de/uapcore/lightpit/entities/VersionStatus.java	Mon May 11 19:09:06 2020 +0200
    12.3 @@ -1,3 +1,31 @@
    12.4 +/*
    12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    12.6 + *
    12.7 + * Copyright 2018 Mike Becker. All rights reserved.
    12.8 + *
    12.9 + * Redistribution and use in source and binary forms, with or without
   12.10 + * modification, are permitted provided that the following conditions are met:
   12.11 + *
   12.12 + *   1. Redistributions of source code must retain the above copyright
   12.13 + *      notice, this list of conditions and the following disclaimer.
   12.14 + *
   12.15 + *   2. Redistributions in binary form must reproduce the above copyright
   12.16 + *      notice, this list of conditions and the following disclaimer in the
   12.17 + *      documentation and/or other materials provided with the distribution.
   12.18 + *
   12.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   12.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   12.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   12.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   12.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   12.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   12.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   12.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   12.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   12.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   12.29 + * POSSIBILITY OF SUCH DAMAGE.
   12.30 + *
   12.31 + */
   12.32  package de.uapcore.lightpit.entities;
   12.33  
   12.34  public enum VersionStatus {

mercurial