# HG changeset patch # User Mike Becker # Date 1602761512 -7200 # Node ID 947d0f6a6a838526a2cdb304109f44667556eb56 # Parent 6105ee2cceaff42b9ac7356a9146f9221f6c46c9 changes the way how to deal with child entities + adds component lead diff -r 6105ee2cceaf -r 947d0f6a6a83 setup/postgres/psql_create_tables.sql --- a/setup/postgres/psql_create_tables.sql Thu Oct 15 12:27:05 2020 +0200 +++ b/setup/postgres/psql_create_tables.sql Thu Oct 15 13:31:52 2020 +0200 @@ -40,7 +40,8 @@ name varchar(20) not null, color char(6) not null default '000000', ordinal integer not null default 0, - description text + description text, + lead integer references lpit_user(userid) ); create type issue_status as enum ( diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/ChildEntityDao.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/uapcore/lightpit/dao/ChildEntityDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -0,0 +1,116 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package de.uapcore.lightpit.dao; + +import java.sql.SQLException; +import java.util.List; + +public interface ChildEntityDao { + + /** + * Lists all entities being a child of the specified parent. + * @param parent the parent + * @return the list of child instances + * @throws SQLException on any kind of SQL errors + */ + List list(P parent) throws SQLException; + + /** + * Finds an entity by its integer ID. + * It is not guaranteed that referenced entities are automatically joined. + * + * @param id the id + * @return the enity or null if there is no such entity + * @throws SQLException on any kind of SQL errors + */ + T find(int id) throws SQLException; + + /** + * Inserts an instance into database. + * It is not guaranteed that generated fields will be updated in the instance. + * + * @param instance the instance to insert + * @param parent a reference to the parent + * @throws SQLException on any kind of SQL errors + */ + void save(T instance, P parent) throws SQLException; + + /** + * Updates an instance in the database. + * + * @param instance the instance to insert + * @return true if an instance has been updated, false if no instance with the specified ID was found + * @throws SQLException on any kind of SQL errors + */ + boolean update(T instance) throws SQLException; + + /** + * Updates an instance in the database changing the parent. + * This operation is not supported by default. + * + * @param instance the instance to insert + * @param newParent a reference to the new parent + * @return true if an instance has been updated, false if no instance with the specified ID was found + * @throws SQLException on any kind of SQL errors + * @see #isChangingParentSupported() + */ + default boolean update(T instance, P newParent) throws SQLException { + throw new UnsupportedOperationException(); + } + + /** + * Returns true if changing the parent is supported by this DAO. + * This method must return true, if {@link #update(Object, Object)} is implemented. + * @return true, if changing the parent is supported + */ + default boolean isChangingParentSupported() { + return false; + } + + /** + * Inserts or updates an instance in the database. + * Tries an update first and if that fails, performs a save. + * If changing a parent is not supported by this DAO, + * specifying an alternate parent for an existing instance has no effect. + * + * @param instance the instance to insert or update + * @param parent a reference to the parent + * @throws SQLException on any kind of SQL errors + * @see #update(Object) + * @see #update(Object, Object) + * @see #save(Object, Object) + */ + default void saveOrUpdate(T instance, P parent) throws SQLException { + if (isChangingParentSupported()) { + if (!update(instance, parent)) save(instance, parent); + } else { + if (!update(instance)) save(instance, parent); + } + } +} diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/ComponentDao.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/uapcore/lightpit/dao/ComponentDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -0,0 +1,36 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package de.uapcore.lightpit.dao; + +import de.uapcore.lightpit.entities.Component; +import de.uapcore.lightpit.entities.Project; + +public interface ComponentDao extends ChildEntityDao { + +} diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java --- a/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java Thu Oct 15 13:31:52 2020 +0200 @@ -35,5 +35,7 @@ VersionDao getVersionDao(); + ComponentDao getComponentDao(); + IssueDao getIssueDao(); } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/GenericDao.java --- a/src/main/java/de/uapcore/lightpit/dao/GenericDao.java Thu Oct 15 12:27:05 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2018 Mike Becker. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ -package de.uapcore.lightpit.dao; - -import java.sql.SQLException; - -public interface GenericDao { - - /** - * Finds an entity by its integer ID. - * It is not guaranteed that referenced entities are automatically joined. - * - * @param id the id - * @return the enity or null if there is no such entity - * @throws SQLException on any kind of SQL errors - */ - T find(int id) throws SQLException; - - /** - * Inserts an instance into database. - * It is not guaranteed that generated fields will be updated in the instance. - * - * @param instance the instance to insert - * @throws SQLException on any kind of SQL errors - */ - void save(T instance) throws SQLException; - - /** - * Updates an instance in the database. - * - * @param instance the instance to insert - * @return true if an instance has been updated, false if no instance with the specified ID was found - * @throws SQLException on any kind of SQL errors - */ - boolean update(T instance) throws SQLException; - - /** - * Inserts or updates an instance in the database. - * Tries an update first and if that fails, performs a save. - * - * @param instance the instance to insert or update - * @throws SQLException on any kind of SQL errors - * @see #update(Object) - * @see #save(Object) - */ - default void saveOrUpdate(T instance) throws SQLException { - if (!update(instance)) save(instance); - } -} diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/IssueDao.java --- a/src/main/java/de/uapcore/lightpit/dao/IssueDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/IssueDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -36,18 +36,7 @@ import java.sql.SQLException; import java.util.List; -public interface IssueDao extends GenericDao { - - /** - * Lists all issues for the specified project. - * This is not guaranteed to contain version information. - * Use {@link #joinVersionInformation(Issue)} to obtain this information for a specific issue. - * - * @param project the project - * @return a list of issues - * @throws SQLException on any kind of SQL error - */ - List list(Project project) throws SQLException; +public interface IssueDao extends ChildEntityDao { /** * Lists all issues that are somehow related to the specified version. @@ -82,11 +71,12 @@ * Implementations of this DAO must guarantee that the generated ID is stored in the instance. * * @param instance the instance to insert + * @param project the parent project * @throws SQLException on any kind of SQL error * @see Issue#setId(int) */ @Override - void save(Issue instance) throws SQLException; + void save(Issue instance, Project project) throws SQLException; /** * Retrieves the affected, scheduled and resolved versions for the specified issue. diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/ProjectDao.java --- a/src/main/java/de/uapcore/lightpit/dao/ProjectDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/ProjectDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -32,10 +32,7 @@ import de.uapcore.lightpit.entities.Project; import java.sql.SQLException; -import java.util.List; -public interface ProjectDao extends GenericDao { - List list() throws SQLException; - +public interface ProjectDao extends RootEntityDao { IssueSummary getIssueSummary(Project project) throws SQLException; } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/RootEntityDao.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/uapcore/lightpit/dao/RootEntityDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -0,0 +1,83 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package de.uapcore.lightpit.dao; + +import java.sql.SQLException; +import java.util.List; + +public interface RootEntityDao { + + /** + * Lists all entities. + * @return a list of all entities + * @throws SQLException on any kind of SQL errors + */ + List list() throws SQLException; + + /** + * Finds an entity by its integer ID. + * It is not guaranteed that referenced entities are automatically joined. + * + * @param id the id + * @return the enity or null if there is no such entity + * @throws SQLException on any kind of SQL errors + */ + T find(int id) throws SQLException; + + /** + * Inserts an instance into database. + * It is not guaranteed that generated fields will be updated in the instance. + * + * @param instance the instance to insert + * @throws SQLException on any kind of SQL errors + */ + void save(T instance) throws SQLException; + + /** + * Updates an instance in the database. + * + * @param instance the instance to insert + * @return true if an instance has been updated, false if no instance with the specified ID was found + * @throws SQLException on any kind of SQL errors + */ + boolean update(T instance) throws SQLException; + + /** + * Inserts or updates an instance in the database. + * Tries an update first and if that fails, performs a save. + * + * @param instance the instance to insert or update + * @throws SQLException on any kind of SQL errors + * @see #update(Object) + * @see #save(Object) + */ + default void saveOrUpdate(T instance) throws SQLException { + if (!update(instance)) save(instance); + } +} diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/UserDao.java --- a/src/main/java/de/uapcore/lightpit/dao/UserDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/UserDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -31,12 +31,9 @@ import de.uapcore.lightpit.entities.User; import java.sql.SQLException; -import java.util.List; import java.util.Optional; -public interface UserDao extends GenericDao { - - List list() throws SQLException; +public interface UserDao extends RootEntityDao { /** * Tries to find a user by their username. diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/VersionDao.java --- a/src/main/java/de/uapcore/lightpit/dao/VersionDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/VersionDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -31,17 +31,5 @@ import de.uapcore.lightpit.entities.Project; import de.uapcore.lightpit.entities.Version; -import java.sql.SQLException; -import java.util.List; - -public interface VersionDao extends GenericDao { - - /** - * Lists all versions for the specified project. - * - * @param project the project - * @return a list of versions - * @throws SQLException on any kind of SQL error - */ - List list(Project project) throws SQLException; +public interface VersionDao extends ChildEntityDao { } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGComponentDao.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGComponentDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -0,0 +1,139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package de.uapcore.lightpit.dao.postgres; + +import de.uapcore.lightpit.dao.ComponentDao; +import de.uapcore.lightpit.dao.Functions; +import de.uapcore.lightpit.entities.Component; +import de.uapcore.lightpit.entities.Project; +import de.uapcore.lightpit.entities.User; +import de.uapcore.lightpit.types.WebColor; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class PGComponentDao implements ComponentDao { + + private final PreparedStatement insert, update, list, find; + + public PGComponentDao(Connection connection) throws SQLException { + list = connection.prepareStatement( + "select id, name, color, ordinal, description, " + + "userid, username, givenname, lastname, mail " + + "from lpit_component " + + "left join lpit_user on lead = userid " + + "where project = ? " + + "order by ordinal desc, lower(name) desc"); + + find = connection.prepareStatement( + "select id, name, color, ordinal, description, " + + "userid, username, givenname, lastname, mail " + + "from lpit_component " + + "left join lpit_user on lead = userid " + + "where id = ? "); + + insert = connection.prepareStatement( + "insert into lpit_component (project, name, color, ordinal, description, lead) values (?, ?, ?, ?, ?, ?)" + ); + + update = connection.prepareStatement( + "update lpit_component set name = ?, color = ?, ordinal = ?, description = ?, lead = ? where id = ?" + ); + } + + private static Component mapColumns(ResultSet result) throws SQLException { + final var component = new Component(result.getInt("id")); + component.setName(result.getString("name")); + try { + component.setColor(new WebColor(result.getString("color"))); + } catch (IllegalArgumentException ex) { + // if someone tempered with the database we default the color to black + component.setColor(new WebColor("000000")); + } + component.setOrdinal(result.getInt("ordinal")); + component.setDescription(result.getString("description")); + component.setLead(PGUserDao.mapColumns(result)); + return component; + } + + @Override + public void save(Component instance, Project project) throws SQLException { + Objects.requireNonNull(instance.getName()); + insert.setInt(1, project.getId()); + insert.setString(2, instance.getName()); + insert.setString(3, instance.getColor().getHex()); + insert.setInt(4, instance.getOrdinal()); + Functions.setStringOrNull(insert, 5, instance.getDescription()); + Functions.setForeignKeyOrNull(insert, 6, instance.getLead(), User::getId); + insert.executeUpdate(); + } + + @Override + public boolean update(Component instance) throws SQLException { + if (instance.getId() < 0) return false; + Objects.requireNonNull(instance.getName()); + Objects.requireNonNull(instance.getColor()); + update.setString(1, instance.getName()); + update.setString(2, instance.getColor().getHex()); + update.setInt(3, instance.getOrdinal()); + Functions.setStringOrNull(update, 4, instance.getDescription()); + Functions.setForeignKeyOrNull(update, 5, instance.getLead(), User::getId); + update.setInt(6, instance.getId()); + return update.executeUpdate() > 0; + } + + @Override + public List list(Project project) throws SQLException { + list.setInt(1, project.getId()); + List components = new ArrayList<>(); + try (var result = list.executeQuery()) { + while (result.next()) { + components.add(mapColumns(result)); + } + } + return components; + } + + @Override + public Component find(int id) throws SQLException { + find.setInt(1, id); + try (var result = find.executeQuery()) { + if (result.next()) { + return mapColumns(result); + } else { + return null; + } + } + } +} diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Thu Oct 15 13:31:52 2020 +0200 @@ -38,12 +38,14 @@ private final UserDao userDao; private final ProjectDao projectDao; private final VersionDao versionDao; + private final ComponentDao componentDao; private final IssueDao issueDao; public PGDataAccessObjects(Connection connection) throws SQLException { userDao = new PGUserDao(connection); projectDao = new PGProjectDao(connection); versionDao = new PGVersionDao(connection); + componentDao = new PGComponentDao(connection); issueDao = new PGIssueDao(connection); } @@ -58,6 +60,11 @@ } @Override + public ComponentDao getComponentDao() { + return componentDao; + } + + @Override public VersionDao getVersionDao() { return versionDao; } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -120,20 +120,6 @@ ); } - private User obtainUser(ResultSet result) throws SQLException { - final int id = result.getInt("userid"); - if (id != 0) { - final var user = new User(id); - user.setUsername(result.getString("username")); - user.setGivenname(result.getString("givenname")); - user.setLastname(result.getString("lastname")); - user.setMail(result.getString("mail")); - return user; - } else { - return null; - } - } - private Issue mapColumns(ResultSet result) throws SQLException { final var project = new Project(result.getInt("project")); project.setName(result.getString("projectname")); @@ -143,7 +129,7 @@ issue.setCategory(IssueCategory.valueOf(result.getString("category"))); issue.setSubject(result.getString("subject")); issue.setDescription(result.getString("description")); - issue.setAssignee(obtainUser(result)); + issue.setAssignee(PGUserDao.mapColumns(result)); issue.setCreated(result.getTimestamp("created")); issue.setUpdated(result.getTimestamp("updated")); issue.setEta(result.getDate("eta")); @@ -176,9 +162,9 @@ } @Override - public void save(Issue instance) throws SQLException { + public void save(Issue instance, Project project) throws SQLException { Objects.requireNonNull(instance.getSubject()); - Objects.requireNonNull(instance.getProject()); + instance.setProject(project); insert.setInt(1, instance.getProject().getId()); insert.setString(2, instance.getStatus().name()); insert.setString(3, instance.getCategory().name()); @@ -275,7 +261,7 @@ comment.setUpdated(result.getTimestamp("updated")); comment.setUpdateCount(result.getInt("updatecount")); comment.setComment(result.getString("comment")); - comment.setAuthor(obtainUser(result)); + comment.setAuthor(PGUserDao.mapColumns(result)); comments.add(comment); } } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -85,16 +85,7 @@ proj.setName(result.getString("name")); proj.setDescription(result.getString("description")); proj.setRepoUrl(result.getString("repourl")); - - final int id = result.getInt("userid"); - if (id != 0) { - final var user = new User(id); - user.setUsername(result.getString("username")); - user.setGivenname(result.getString("givenname")); - user.setLastname(result.getString("lastname")); - user.setMail(result.getString("mail")); - proj.setOwner(user); - } + proj.setOwner(PGUserDao.mapColumns(result)); return proj; } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -63,7 +63,7 @@ update = connection.prepareStatement("update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?"); } - private User mapColumns(ResultSet result) throws SQLException { + static User mapColumns(ResultSet result) throws SQLException { final int id = result.getInt("userid"); if (id == 0) return null; final var user = new User(id); diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/dao/postgres/PGVersionDao.java --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGVersionDao.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGVersionDao.java Thu Oct 15 13:31:52 2020 +0200 @@ -47,16 +47,14 @@ public PGVersionDao(Connection connection) throws SQLException { list = connection.prepareStatement( - "select versionid, project, p.name as projectname, v.name, ordinal, status " + - "from lpit_version v " + - "join lpit_project p on v.project = p.projectid " + + "select versionid, project, name, ordinal, status " + + "from lpit_version " + "where project = ? " + - "order by ordinal desc, lower(v.name) desc"); + "order by ordinal desc, lower(name) desc"); find = connection.prepareStatement( - "select versionid, project, p.name as projectname, v.name, ordinal, status " + - "from lpit_version v " + - "join lpit_project p on v.project = p.projectid " + + "select versionid, project, name, ordinal, status " + + "from lpit_version " + "where versionid = ?"); insert = connection.prepareStatement( @@ -68,10 +66,7 @@ } private Version mapColumns(ResultSet result) throws SQLException { - final var project = new Project(result.getInt("project")); - project.setName(result.getString("projectname")); final var version = new Version(result.getInt("versionid")); - version.setProject(project); version.setName(result.getString("name")); version.setOrdinal(result.getInt("ordinal")); version.setStatus(VersionStatus.valueOf(result.getString("status"))); @@ -79,10 +74,9 @@ } @Override - public void save(Version instance) throws SQLException { + public void save(Version instance, Project project) throws SQLException { Objects.requireNonNull(instance.getName()); - Objects.requireNonNull(instance.getProject()); - insert.setInt(1, instance.getProject().getId()); + insert.setInt(1, project.getId()); insert.setString(2, instance.getName()); insert.setInt(3, instance.getOrdinal()); insert.setString(4, instance.getStatus().name()); @@ -106,9 +100,7 @@ List versions = new ArrayList<>(); try (var result = list.executeQuery()) { while (result.next()) { - final var v = mapColumns(result); - v.setProject(project); - versions.add(v); + versions.add(mapColumns(result)); } } return versions; diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/entities/Version.java --- a/src/main/java/de/uapcore/lightpit/entities/Version.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/entities/Version.java Thu Oct 15 13:31:52 2020 +0200 @@ -33,7 +33,6 @@ public final class Version implements Comparable { private final int id; - private Project project; private String name; /** * If we do not want versions to be ordered lexicographically we may specify an order. @@ -49,14 +48,6 @@ return id; } - public void setProject(Project project) { - this.project = project; - } - - public Project getProject() { - return project; - } - public String getName() { return name; } diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 13:31:52 2020 +0200 @@ -238,13 +238,7 @@ return ResponseType.NONE; } - if (viewModel.getVersionFilter() == null) { - final var version = new Version(-1); - version.setProject(viewModel.getProjectInfo().getProject()); - viewModel.setVersion(version); - } else { - viewModel.setVersion(viewModel.getVersionFilter()); - } + viewModel.setVersion(Optional.ofNullable(viewModel.getVersionFilter()).orElse(new Version(-1))); return forwardView(req, viewModel, "version-form"); } @@ -254,15 +248,14 @@ var version = new Version(-1); try { + final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); - version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); version.setName(getParameter(req, String.class, "name").orElseThrow()); getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); - dao.getVersionDao().saveOrUpdate(version); + dao.getVersionDao().saveOrUpdate(version, project); - // specifying the pid parameter will purposely reset the session selected version! - setRedirectLocation(req, "./projects/versions?pid=" + version.getProject().getId()); + setRedirectLocation(req, "./projects/versions?pid=" + project.getId()); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { LOG.warn("Form validation failure: {}", ex.getMessage()); @@ -332,7 +325,7 @@ stream.map(Version::new).collect(Collectors.toList()) ).ifPresent(issue::setResolvedVersions); - dao.getIssueDao().saveOrUpdate(issue); + dao.getIssueDao().saveOrUpdate(issue, issue.getProject()); // specifying the issue parameter keeps the edited issue as menu item setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId()); diff -r 6105ee2cceaf -r 947d0f6a6a83 src/main/webapp/WEB-INF/jsp/version-form.jsp --- a/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 12:27:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 13:31:52 2020 +0200 @@ -30,6 +30,7 @@ +
@@ -41,8 +42,8 @@ @@ -72,7 +73,7 @@
- - + +
- +