Thu, 15 Oct 2020 13:31:52 +0200
changes the way how to deal with child entities + adds component lead
1.1 --- a/setup/postgres/psql_create_tables.sql Thu Oct 15 12:27:05 2020 +0200 1.2 +++ b/setup/postgres/psql_create_tables.sql Thu Oct 15 13:31:52 2020 +0200 1.3 @@ -40,7 +40,8 @@ 1.4 name varchar(20) not null, 1.5 color char(6) not null default '000000', 1.6 ordinal integer not null default 0, 1.7 - description text 1.8 + description text, 1.9 + lead integer references lpit_user(userid) 1.10 ); 1.11 1.12 create type issue_status as enum (
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/main/java/de/uapcore/lightpit/dao/ChildEntityDao.java Thu Oct 15 13:31:52 2020 +0200 2.3 @@ -0,0 +1,116 @@ 2.4 +/* 2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2.6 + * 2.7 + * Copyright 2018 Mike Becker. All rights reserved. 2.8 + * 2.9 + * Redistribution and use in source and binary forms, with or without 2.10 + * modification, are permitted provided that the following conditions are met: 2.11 + * 2.12 + * 1. Redistributions of source code must retain the above copyright 2.13 + * notice, this list of conditions and the following disclaimer. 2.14 + * 2.15 + * 2. Redistributions in binary form must reproduce the above copyright 2.16 + * notice, this list of conditions and the following disclaimer in the 2.17 + * documentation and/or other materials provided with the distribution. 2.18 + * 2.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2.29 + * POSSIBILITY OF SUCH DAMAGE. 2.30 + * 2.31 + */ 2.32 +package de.uapcore.lightpit.dao; 2.33 + 2.34 +import java.sql.SQLException; 2.35 +import java.util.List; 2.36 + 2.37 +public interface ChildEntityDao<T, P> { 2.38 + 2.39 + /** 2.40 + * Lists all entities being a child of the specified parent. 2.41 + * @param parent the parent 2.42 + * @return the list of child instances 2.43 + * @throws SQLException on any kind of SQL errors 2.44 + */ 2.45 + List<T> list(P parent) throws SQLException; 2.46 + 2.47 + /** 2.48 + * Finds an entity by its integer ID. 2.49 + * It is not guaranteed that referenced entities are automatically joined. 2.50 + * 2.51 + * @param id the id 2.52 + * @return the enity or null if there is no such entity 2.53 + * @throws SQLException on any kind of SQL errors 2.54 + */ 2.55 + T find(int id) throws SQLException; 2.56 + 2.57 + /** 2.58 + * Inserts an instance into database. 2.59 + * It is not guaranteed that generated fields will be updated in the instance. 2.60 + * 2.61 + * @param instance the instance to insert 2.62 + * @param parent a reference to the parent 2.63 + * @throws SQLException on any kind of SQL errors 2.64 + */ 2.65 + void save(T instance, P parent) throws SQLException; 2.66 + 2.67 + /** 2.68 + * Updates an instance in the database. 2.69 + * 2.70 + * @param instance the instance to insert 2.71 + * @return true if an instance has been updated, false if no instance with the specified ID was found 2.72 + * @throws SQLException on any kind of SQL errors 2.73 + */ 2.74 + boolean update(T instance) throws SQLException; 2.75 + 2.76 + /** 2.77 + * Updates an instance in the database changing the parent. 2.78 + * This operation is not supported by default. 2.79 + * 2.80 + * @param instance the instance to insert 2.81 + * @param newParent a reference to the new parent 2.82 + * @return true if an instance has been updated, false if no instance with the specified ID was found 2.83 + * @throws SQLException on any kind of SQL errors 2.84 + * @see #isChangingParentSupported() 2.85 + */ 2.86 + default boolean update(T instance, P newParent) throws SQLException { 2.87 + throw new UnsupportedOperationException(); 2.88 + } 2.89 + 2.90 + /** 2.91 + * Returns true if changing the parent is supported by this DAO. 2.92 + * This method must return true, if {@link #update(Object, Object)} is implemented. 2.93 + * @return true, if changing the parent is supported 2.94 + */ 2.95 + default boolean isChangingParentSupported() { 2.96 + return false; 2.97 + } 2.98 + 2.99 + /** 2.100 + * Inserts or updates an instance in the database. 2.101 + * Tries an update first and if that fails, performs a save. 2.102 + * If changing a parent is not supported by this DAO, 2.103 + * specifying an alternate parent for an existing instance has no effect. 2.104 + * 2.105 + * @param instance the instance to insert or update 2.106 + * @param parent a reference to the parent 2.107 + * @throws SQLException on any kind of SQL errors 2.108 + * @see #update(Object) 2.109 + * @see #update(Object, Object) 2.110 + * @see #save(Object, Object) 2.111 + */ 2.112 + default void saveOrUpdate(T instance, P parent) throws SQLException { 2.113 + if (isChangingParentSupported()) { 2.114 + if (!update(instance, parent)) save(instance, parent); 2.115 + } else { 2.116 + if (!update(instance)) save(instance, parent); 2.117 + } 2.118 + } 2.119 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/main/java/de/uapcore/lightpit/dao/ComponentDao.java Thu Oct 15 13:31:52 2020 +0200 3.3 @@ -0,0 +1,36 @@ 3.4 +/* 3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3.6 + * 3.7 + * Copyright 2018 Mike Becker. All rights reserved. 3.8 + * 3.9 + * Redistribution and use in source and binary forms, with or without 3.10 + * modification, are permitted provided that the following conditions are met: 3.11 + * 3.12 + * 1. Redistributions of source code must retain the above copyright 3.13 + * notice, this list of conditions and the following disclaimer. 3.14 + * 3.15 + * 2. Redistributions in binary form must reproduce the above copyright 3.16 + * notice, this list of conditions and the following disclaimer in the 3.17 + * documentation and/or other materials provided with the distribution. 3.18 + * 3.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 3.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 3.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3.29 + * POSSIBILITY OF SUCH DAMAGE. 3.30 + * 3.31 + */ 3.32 +package de.uapcore.lightpit.dao; 3.33 + 3.34 +import de.uapcore.lightpit.entities.Component; 3.35 +import de.uapcore.lightpit.entities.Project; 3.36 + 3.37 +public interface ComponentDao extends ChildEntityDao<Component, Project> { 3.38 + 3.39 +}
4.1 --- a/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java Thu Oct 15 12:27:05 2020 +0200 4.2 +++ b/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java Thu Oct 15 13:31:52 2020 +0200 4.3 @@ -35,5 +35,7 @@ 4.4 4.5 VersionDao getVersionDao(); 4.6 4.7 + ComponentDao getComponentDao(); 4.8 + 4.9 IssueDao getIssueDao(); 4.10 }
5.1 --- a/src/main/java/de/uapcore/lightpit/dao/GenericDao.java Thu Oct 15 12:27:05 2020 +0200 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,75 +0,0 @@ 5.4 -/* 5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 - * 5.7 - * Copyright 2018 Mike Becker. All rights reserved. 5.8 - * 5.9 - * Redistribution and use in source and binary forms, with or without 5.10 - * modification, are permitted provided that the following conditions are met: 5.11 - * 5.12 - * 1. Redistributions of source code must retain the above copyright 5.13 - * notice, this list of conditions and the following disclaimer. 5.14 - * 5.15 - * 2. Redistributions in binary form must reproduce the above copyright 5.16 - * notice, this list of conditions and the following disclaimer in the 5.17 - * documentation and/or other materials provided with the distribution. 5.18 - * 5.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.29 - * POSSIBILITY OF SUCH DAMAGE. 5.30 - * 5.31 - */ 5.32 -package de.uapcore.lightpit.dao; 5.33 - 5.34 -import java.sql.SQLException; 5.35 - 5.36 -public interface GenericDao<T> { 5.37 - 5.38 - /** 5.39 - * Finds an entity by its integer ID. 5.40 - * It is not guaranteed that referenced entities are automatically joined. 5.41 - * 5.42 - * @param id the id 5.43 - * @return the enity or null if there is no such entity 5.44 - * @throws SQLException on any kind of SQL errors 5.45 - */ 5.46 - T find(int id) throws SQLException; 5.47 - 5.48 - /** 5.49 - * Inserts an instance into database. 5.50 - * It is not guaranteed that generated fields will be updated in the instance. 5.51 - * 5.52 - * @param instance the instance to insert 5.53 - * @throws SQLException on any kind of SQL errors 5.54 - */ 5.55 - void save(T instance) throws SQLException; 5.56 - 5.57 - /** 5.58 - * Updates an instance in the database. 5.59 - * 5.60 - * @param instance the instance to insert 5.61 - * @return true if an instance has been updated, false if no instance with the specified ID was found 5.62 - * @throws SQLException on any kind of SQL errors 5.63 - */ 5.64 - boolean update(T instance) throws SQLException; 5.65 - 5.66 - /** 5.67 - * Inserts or updates an instance in the database. 5.68 - * Tries an update first and if that fails, performs a save. 5.69 - * 5.70 - * @param instance the instance to insert or update 5.71 - * @throws SQLException on any kind of SQL errors 5.72 - * @see #update(Object) 5.73 - * @see #save(Object) 5.74 - */ 5.75 - default void saveOrUpdate(T instance) throws SQLException { 5.76 - if (!update(instance)) save(instance); 5.77 - } 5.78 -}
6.1 --- a/src/main/java/de/uapcore/lightpit/dao/IssueDao.java Thu Oct 15 12:27:05 2020 +0200 6.2 +++ b/src/main/java/de/uapcore/lightpit/dao/IssueDao.java Thu Oct 15 13:31:52 2020 +0200 6.3 @@ -36,18 +36,7 @@ 6.4 import java.sql.SQLException; 6.5 import java.util.List; 6.6 6.7 -public interface IssueDao extends GenericDao<Issue> { 6.8 - 6.9 - /** 6.10 - * Lists all issues for the specified project. 6.11 - * This is not guaranteed to contain version information. 6.12 - * Use {@link #joinVersionInformation(Issue)} to obtain this information for a specific issue. 6.13 - * 6.14 - * @param project the project 6.15 - * @return a list of issues 6.16 - * @throws SQLException on any kind of SQL error 6.17 - */ 6.18 - List<Issue> list(Project project) throws SQLException; 6.19 +public interface IssueDao extends ChildEntityDao<Issue, Project> { 6.20 6.21 /** 6.22 * Lists all issues that are somehow related to the specified version. 6.23 @@ -82,11 +71,12 @@ 6.24 * Implementations of this DAO must guarantee that the generated ID is stored in the instance. 6.25 * 6.26 * @param instance the instance to insert 6.27 + * @param project the parent project 6.28 * @throws SQLException on any kind of SQL error 6.29 * @see Issue#setId(int) 6.30 */ 6.31 @Override 6.32 - void save(Issue instance) throws SQLException; 6.33 + void save(Issue instance, Project project) throws SQLException; 6.34 6.35 /** 6.36 * Retrieves the affected, scheduled and resolved versions for the specified issue.
7.1 --- a/src/main/java/de/uapcore/lightpit/dao/ProjectDao.java Thu Oct 15 12:27:05 2020 +0200 7.2 +++ b/src/main/java/de/uapcore/lightpit/dao/ProjectDao.java Thu Oct 15 13:31:52 2020 +0200 7.3 @@ -32,10 +32,7 @@ 7.4 import de.uapcore.lightpit.entities.Project; 7.5 7.6 import java.sql.SQLException; 7.7 -import java.util.List; 7.8 7.9 -public interface ProjectDao extends GenericDao<Project> { 7.10 - List<Project> list() throws SQLException; 7.11 - 7.12 +public interface ProjectDao extends RootEntityDao<Project> { 7.13 IssueSummary getIssueSummary(Project project) throws SQLException; 7.14 }
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/main/java/de/uapcore/lightpit/dao/RootEntityDao.java Thu Oct 15 13:31:52 2020 +0200 8.3 @@ -0,0 +1,83 @@ 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; 8.33 + 8.34 +import java.sql.SQLException; 8.35 +import java.util.List; 8.36 + 8.37 +public interface RootEntityDao<T> { 8.38 + 8.39 + /** 8.40 + * Lists all entities. 8.41 + * @return a list of all entities 8.42 + * @throws SQLException on any kind of SQL errors 8.43 + */ 8.44 + List<T> list() throws SQLException; 8.45 + 8.46 + /** 8.47 + * Finds an entity by its integer ID. 8.48 + * It is not guaranteed that referenced entities are automatically joined. 8.49 + * 8.50 + * @param id the id 8.51 + * @return the enity or null if there is no such entity 8.52 + * @throws SQLException on any kind of SQL errors 8.53 + */ 8.54 + T find(int id) throws SQLException; 8.55 + 8.56 + /** 8.57 + * Inserts an instance into database. 8.58 + * It is not guaranteed that generated fields will be updated in the instance. 8.59 + * 8.60 + * @param instance the instance to insert 8.61 + * @throws SQLException on any kind of SQL errors 8.62 + */ 8.63 + void save(T instance) throws SQLException; 8.64 + 8.65 + /** 8.66 + * Updates an instance in the database. 8.67 + * 8.68 + * @param instance the instance to insert 8.69 + * @return true if an instance has been updated, false if no instance with the specified ID was found 8.70 + * @throws SQLException on any kind of SQL errors 8.71 + */ 8.72 + boolean update(T instance) throws SQLException; 8.73 + 8.74 + /** 8.75 + * Inserts or updates an instance in the database. 8.76 + * Tries an update first and if that fails, performs a save. 8.77 + * 8.78 + * @param instance the instance to insert or update 8.79 + * @throws SQLException on any kind of SQL errors 8.80 + * @see #update(Object) 8.81 + * @see #save(Object) 8.82 + */ 8.83 + default void saveOrUpdate(T instance) throws SQLException { 8.84 + if (!update(instance)) save(instance); 8.85 + } 8.86 +}
9.1 --- a/src/main/java/de/uapcore/lightpit/dao/UserDao.java Thu Oct 15 12:27:05 2020 +0200 9.2 +++ b/src/main/java/de/uapcore/lightpit/dao/UserDao.java Thu Oct 15 13:31:52 2020 +0200 9.3 @@ -31,12 +31,9 @@ 9.4 import de.uapcore.lightpit.entities.User; 9.5 9.6 import java.sql.SQLException; 9.7 -import java.util.List; 9.8 import java.util.Optional; 9.9 9.10 -public interface UserDao extends GenericDao<User> { 9.11 - 9.12 - List<User> list() throws SQLException; 9.13 +public interface UserDao extends RootEntityDao<User> { 9.14 9.15 /** 9.16 * Tries to find a user by their username.
10.1 --- a/src/main/java/de/uapcore/lightpit/dao/VersionDao.java Thu Oct 15 12:27:05 2020 +0200 10.2 +++ b/src/main/java/de/uapcore/lightpit/dao/VersionDao.java Thu Oct 15 13:31:52 2020 +0200 10.3 @@ -31,17 +31,5 @@ 10.4 import de.uapcore.lightpit.entities.Project; 10.5 import de.uapcore.lightpit.entities.Version; 10.6 10.7 -import java.sql.SQLException; 10.8 -import java.util.List; 10.9 - 10.10 -public interface VersionDao extends GenericDao<Version> { 10.11 - 10.12 - /** 10.13 - * Lists all versions for the specified project. 10.14 - * 10.15 - * @param project the project 10.16 - * @return a list of versions 10.17 - * @throws SQLException on any kind of SQL error 10.18 - */ 10.19 - List<Version> list(Project project) throws SQLException; 10.20 +public interface VersionDao extends ChildEntityDao<Version, Project> { 10.21 }
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGComponentDao.java Thu Oct 15 13:31:52 2020 +0200 11.3 @@ -0,0 +1,139 @@ 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.dao.postgres; 11.33 + 11.34 +import de.uapcore.lightpit.dao.ComponentDao; 11.35 +import de.uapcore.lightpit.dao.Functions; 11.36 +import de.uapcore.lightpit.entities.Component; 11.37 +import de.uapcore.lightpit.entities.Project; 11.38 +import de.uapcore.lightpit.entities.User; 11.39 +import de.uapcore.lightpit.types.WebColor; 11.40 + 11.41 +import java.sql.Connection; 11.42 +import java.sql.PreparedStatement; 11.43 +import java.sql.ResultSet; 11.44 +import java.sql.SQLException; 11.45 +import java.util.ArrayList; 11.46 +import java.util.List; 11.47 +import java.util.Objects; 11.48 + 11.49 +public final class PGComponentDao implements ComponentDao { 11.50 + 11.51 + private final PreparedStatement insert, update, list, find; 11.52 + 11.53 + public PGComponentDao(Connection connection) throws SQLException { 11.54 + list = connection.prepareStatement( 11.55 + "select id, name, color, ordinal, description, " + 11.56 + "userid, username, givenname, lastname, mail " + 11.57 + "from lpit_component " + 11.58 + "left join lpit_user on lead = userid " + 11.59 + "where project = ? " + 11.60 + "order by ordinal desc, lower(name) desc"); 11.61 + 11.62 + find = connection.prepareStatement( 11.63 + "select id, name, color, ordinal, description, " + 11.64 + "userid, username, givenname, lastname, mail " + 11.65 + "from lpit_component " + 11.66 + "left join lpit_user on lead = userid " + 11.67 + "where id = ? "); 11.68 + 11.69 + insert = connection.prepareStatement( 11.70 + "insert into lpit_component (project, name, color, ordinal, description, lead) values (?, ?, ?, ?, ?, ?)" 11.71 + ); 11.72 + 11.73 + update = connection.prepareStatement( 11.74 + "update lpit_component set name = ?, color = ?, ordinal = ?, description = ?, lead = ? where id = ?" 11.75 + ); 11.76 + } 11.77 + 11.78 + private static Component mapColumns(ResultSet result) throws SQLException { 11.79 + final var component = new Component(result.getInt("id")); 11.80 + component.setName(result.getString("name")); 11.81 + try { 11.82 + component.setColor(new WebColor(result.getString("color"))); 11.83 + } catch (IllegalArgumentException ex) { 11.84 + // if someone tempered with the database we default the color to black 11.85 + component.setColor(new WebColor("000000")); 11.86 + } 11.87 + component.setOrdinal(result.getInt("ordinal")); 11.88 + component.setDescription(result.getString("description")); 11.89 + component.setLead(PGUserDao.mapColumns(result)); 11.90 + return component; 11.91 + } 11.92 + 11.93 + @Override 11.94 + public void save(Component instance, Project project) throws SQLException { 11.95 + Objects.requireNonNull(instance.getName()); 11.96 + insert.setInt(1, project.getId()); 11.97 + insert.setString(2, instance.getName()); 11.98 + insert.setString(3, instance.getColor().getHex()); 11.99 + insert.setInt(4, instance.getOrdinal()); 11.100 + Functions.setStringOrNull(insert, 5, instance.getDescription()); 11.101 + Functions.setForeignKeyOrNull(insert, 6, instance.getLead(), User::getId); 11.102 + insert.executeUpdate(); 11.103 + } 11.104 + 11.105 + @Override 11.106 + public boolean update(Component instance) throws SQLException { 11.107 + if (instance.getId() < 0) return false; 11.108 + Objects.requireNonNull(instance.getName()); 11.109 + Objects.requireNonNull(instance.getColor()); 11.110 + update.setString(1, instance.getName()); 11.111 + update.setString(2, instance.getColor().getHex()); 11.112 + update.setInt(3, instance.getOrdinal()); 11.113 + Functions.setStringOrNull(update, 4, instance.getDescription()); 11.114 + Functions.setForeignKeyOrNull(update, 5, instance.getLead(), User::getId); 11.115 + update.setInt(6, instance.getId()); 11.116 + return update.executeUpdate() > 0; 11.117 + } 11.118 + 11.119 + @Override 11.120 + public List<Component> list(Project project) throws SQLException { 11.121 + list.setInt(1, project.getId()); 11.122 + List<Component> components = new ArrayList<>(); 11.123 + try (var result = list.executeQuery()) { 11.124 + while (result.next()) { 11.125 + components.add(mapColumns(result)); 11.126 + } 11.127 + } 11.128 + return components; 11.129 + } 11.130 + 11.131 + @Override 11.132 + public Component find(int id) throws SQLException { 11.133 + find.setInt(1, id); 11.134 + try (var result = find.executeQuery()) { 11.135 + if (result.next()) { 11.136 + return mapColumns(result); 11.137 + } else { 11.138 + return null; 11.139 + } 11.140 + } 11.141 + } 11.142 +}
12.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Thu Oct 15 12:27:05 2020 +0200 12.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Thu Oct 15 13:31:52 2020 +0200 12.3 @@ -38,12 +38,14 @@ 12.4 private final UserDao userDao; 12.5 private final ProjectDao projectDao; 12.6 private final VersionDao versionDao; 12.7 + private final ComponentDao componentDao; 12.8 private final IssueDao issueDao; 12.9 12.10 public PGDataAccessObjects(Connection connection) throws SQLException { 12.11 userDao = new PGUserDao(connection); 12.12 projectDao = new PGProjectDao(connection); 12.13 versionDao = new PGVersionDao(connection); 12.14 + componentDao = new PGComponentDao(connection); 12.15 issueDao = new PGIssueDao(connection); 12.16 } 12.17 12.18 @@ -58,6 +60,11 @@ 12.19 } 12.20 12.21 @Override 12.22 + public ComponentDao getComponentDao() { 12.23 + return componentDao; 12.24 + } 12.25 + 12.26 + @Override 12.27 public VersionDao getVersionDao() { 12.28 return versionDao; 12.29 }
13.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java Thu Oct 15 12:27:05 2020 +0200 13.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java Thu Oct 15 13:31:52 2020 +0200 13.3 @@ -120,20 +120,6 @@ 13.4 ); 13.5 } 13.6 13.7 - private User obtainUser(ResultSet result) throws SQLException { 13.8 - final int id = result.getInt("userid"); 13.9 - if (id != 0) { 13.10 - final var user = new User(id); 13.11 - user.setUsername(result.getString("username")); 13.12 - user.setGivenname(result.getString("givenname")); 13.13 - user.setLastname(result.getString("lastname")); 13.14 - user.setMail(result.getString("mail")); 13.15 - return user; 13.16 - } else { 13.17 - return null; 13.18 - } 13.19 - } 13.20 - 13.21 private Issue mapColumns(ResultSet result) throws SQLException { 13.22 final var project = new Project(result.getInt("project")); 13.23 project.setName(result.getString("projectname")); 13.24 @@ -143,7 +129,7 @@ 13.25 issue.setCategory(IssueCategory.valueOf(result.getString("category"))); 13.26 issue.setSubject(result.getString("subject")); 13.27 issue.setDescription(result.getString("description")); 13.28 - issue.setAssignee(obtainUser(result)); 13.29 + issue.setAssignee(PGUserDao.mapColumns(result)); 13.30 issue.setCreated(result.getTimestamp("created")); 13.31 issue.setUpdated(result.getTimestamp("updated")); 13.32 issue.setEta(result.getDate("eta")); 13.33 @@ -176,9 +162,9 @@ 13.34 } 13.35 13.36 @Override 13.37 - public void save(Issue instance) throws SQLException { 13.38 + public void save(Issue instance, Project project) throws SQLException { 13.39 Objects.requireNonNull(instance.getSubject()); 13.40 - Objects.requireNonNull(instance.getProject()); 13.41 + instance.setProject(project); 13.42 insert.setInt(1, instance.getProject().getId()); 13.43 insert.setString(2, instance.getStatus().name()); 13.44 insert.setString(3, instance.getCategory().name()); 13.45 @@ -275,7 +261,7 @@ 13.46 comment.setUpdated(result.getTimestamp("updated")); 13.47 comment.setUpdateCount(result.getInt("updatecount")); 13.48 comment.setComment(result.getString("comment")); 13.49 - comment.setAuthor(obtainUser(result)); 13.50 + comment.setAuthor(PGUserDao.mapColumns(result)); 13.51 comments.add(comment); 13.52 } 13.53 }
14.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Thu Oct 15 12:27:05 2020 +0200 14.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Thu Oct 15 13:31:52 2020 +0200 14.3 @@ -85,16 +85,7 @@ 14.4 proj.setName(result.getString("name")); 14.5 proj.setDescription(result.getString("description")); 14.6 proj.setRepoUrl(result.getString("repourl")); 14.7 - 14.8 - final int id = result.getInt("userid"); 14.9 - if (id != 0) { 14.10 - final var user = new User(id); 14.11 - user.setUsername(result.getString("username")); 14.12 - user.setGivenname(result.getString("givenname")); 14.13 - user.setLastname(result.getString("lastname")); 14.14 - user.setMail(result.getString("mail")); 14.15 - proj.setOwner(user); 14.16 - } 14.17 + proj.setOwner(PGUserDao.mapColumns(result)); 14.18 14.19 return proj; 14.20 }
15.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Thu Oct 15 12:27:05 2020 +0200 15.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Thu Oct 15 13:31:52 2020 +0200 15.3 @@ -63,7 +63,7 @@ 15.4 update = connection.prepareStatement("update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?"); 15.5 } 15.6 15.7 - private User mapColumns(ResultSet result) throws SQLException { 15.8 + static User mapColumns(ResultSet result) throws SQLException { 15.9 final int id = result.getInt("userid"); 15.10 if (id == 0) return null; 15.11 final var user = new User(id);
16.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGVersionDao.java Thu Oct 15 12:27:05 2020 +0200 16.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGVersionDao.java Thu Oct 15 13:31:52 2020 +0200 16.3 @@ -47,16 +47,14 @@ 16.4 16.5 public PGVersionDao(Connection connection) throws SQLException { 16.6 list = connection.prepareStatement( 16.7 - "select versionid, project, p.name as projectname, v.name, ordinal, status " + 16.8 - "from lpit_version v " + 16.9 - "join lpit_project p on v.project = p.projectid " + 16.10 + "select versionid, project, name, ordinal, status " + 16.11 + "from lpit_version " + 16.12 "where project = ? " + 16.13 - "order by ordinal desc, lower(v.name) desc"); 16.14 + "order by ordinal desc, lower(name) desc"); 16.15 16.16 find = connection.prepareStatement( 16.17 - "select versionid, project, p.name as projectname, v.name, ordinal, status " + 16.18 - "from lpit_version v " + 16.19 - "join lpit_project p on v.project = p.projectid " + 16.20 + "select versionid, project, name, ordinal, status " + 16.21 + "from lpit_version " + 16.22 "where versionid = ?"); 16.23 16.24 insert = connection.prepareStatement( 16.25 @@ -68,10 +66,7 @@ 16.26 } 16.27 16.28 private Version mapColumns(ResultSet result) throws SQLException { 16.29 - final var project = new Project(result.getInt("project")); 16.30 - project.setName(result.getString("projectname")); 16.31 final var version = new Version(result.getInt("versionid")); 16.32 - version.setProject(project); 16.33 version.setName(result.getString("name")); 16.34 version.setOrdinal(result.getInt("ordinal")); 16.35 version.setStatus(VersionStatus.valueOf(result.getString("status"))); 16.36 @@ -79,10 +74,9 @@ 16.37 } 16.38 16.39 @Override 16.40 - public void save(Version instance) throws SQLException { 16.41 + public void save(Version instance, Project project) throws SQLException { 16.42 Objects.requireNonNull(instance.getName()); 16.43 - Objects.requireNonNull(instance.getProject()); 16.44 - insert.setInt(1, instance.getProject().getId()); 16.45 + insert.setInt(1, project.getId()); 16.46 insert.setString(2, instance.getName()); 16.47 insert.setInt(3, instance.getOrdinal()); 16.48 insert.setString(4, instance.getStatus().name()); 16.49 @@ -106,9 +100,7 @@ 16.50 List<Version> versions = new ArrayList<>(); 16.51 try (var result = list.executeQuery()) { 16.52 while (result.next()) { 16.53 - final var v = mapColumns(result); 16.54 - v.setProject(project); 16.55 - versions.add(v); 16.56 + versions.add(mapColumns(result)); 16.57 } 16.58 } 16.59 return versions;
17.1 --- a/src/main/java/de/uapcore/lightpit/entities/Version.java Thu Oct 15 12:27:05 2020 +0200 17.2 +++ b/src/main/java/de/uapcore/lightpit/entities/Version.java Thu Oct 15 13:31:52 2020 +0200 17.3 @@ -33,7 +33,6 @@ 17.4 public final class Version implements Comparable<Version> { 17.5 17.6 private final int id; 17.7 - private Project project; 17.8 private String name; 17.9 /** 17.10 * If we do not want versions to be ordered lexicographically we may specify an order. 17.11 @@ -49,14 +48,6 @@ 17.12 return id; 17.13 } 17.14 17.15 - public void setProject(Project project) { 17.16 - this.project = project; 17.17 - } 17.18 - 17.19 - public Project getProject() { 17.20 - return project; 17.21 - } 17.22 - 17.23 public String getName() { 17.24 return name; 17.25 }
18.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 12:27:05 2020 +0200 18.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 13:31:52 2020 +0200 18.3 @@ -238,13 +238,7 @@ 18.4 return ResponseType.NONE; 18.5 } 18.6 18.7 - if (viewModel.getVersionFilter() == null) { 18.8 - final var version = new Version(-1); 18.9 - version.setProject(viewModel.getProjectInfo().getProject()); 18.10 - viewModel.setVersion(version); 18.11 - } else { 18.12 - viewModel.setVersion(viewModel.getVersionFilter()); 18.13 - } 18.14 + viewModel.setVersion(Optional.ofNullable(viewModel.getVersionFilter()).orElse(new Version(-1))); 18.15 18.16 return forwardView(req, viewModel, "version-form"); 18.17 } 18.18 @@ -254,15 +248,14 @@ 18.19 18.20 var version = new Version(-1); 18.21 try { 18.22 + final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); 18.23 version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); 18.24 - version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); 18.25 version.setName(getParameter(req, String.class, "name").orElseThrow()); 18.26 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); 18.27 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); 18.28 - dao.getVersionDao().saveOrUpdate(version); 18.29 + dao.getVersionDao().saveOrUpdate(version, project); 18.30 18.31 - // specifying the pid parameter will purposely reset the session selected version! 18.32 - setRedirectLocation(req, "./projects/versions?pid=" + version.getProject().getId()); 18.33 + setRedirectLocation(req, "./projects/versions?pid=" + project.getId()); 18.34 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 18.35 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { 18.36 LOG.warn("Form validation failure: {}", ex.getMessage()); 18.37 @@ -332,7 +325,7 @@ 18.38 stream.map(Version::new).collect(Collectors.toList()) 18.39 ).ifPresent(issue::setResolvedVersions); 18.40 18.41 - dao.getIssueDao().saveOrUpdate(issue); 18.42 + dao.getIssueDao().saveOrUpdate(issue, issue.getProject()); 18.43 18.44 // specifying the issue parameter keeps the edited issue as menu item 18.45 setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId());
19.1 --- a/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 12:27:05 2020 +0200 19.2 +++ b/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 13:31:52 2020 +0200 19.3 @@ -30,6 +30,7 @@ 19.4 19.5 <jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.VersionEditView" scope="request" /> 19.6 <c:set var="version" scope="page" value="${viewmodel.version}"/> 19.7 +<c:set var="project" scope="page" value="${viewmodel.projectInfo.project}"/> 19.8 19.9 <form action="./projects/versions/commit" method="post"> 19.10 <table class="formtable" style="width: 35ch"> 19.11 @@ -41,8 +42,8 @@ 19.12 <tr> 19.13 <th><fmt:message key="version.project"/></th> 19.14 <td> 19.15 - <c:out value="${version.project.name}" /> 19.16 - <input type="hidden" name="pid" value="${version.project.id}" /> 19.17 + <c:out value="${project.name}" /> 19.18 + <input type="hidden" name="pid" value="${project.id}" /> 19.19 </td> 19.20 </tr> 19.21 <tr> 19.22 @@ -72,7 +73,7 @@ 19.23 <tr> 19.24 <td colspan="2"> 19.25 <input type="hidden" name="id" value="${version.id}"/> 19.26 - <a href="./projects/versions?pid=${version.project.id}" class="button"> 19.27 + <a href="./projects/versions?pid=${project.id}" class="button"> 19.28 <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> 19.29 </a> 19.30 <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button>