Skip to content

Commit 157c07d

Browse files
OndrejVaneppicha
authored andcommitted
#6 Allow for String AP parameters
- sql scripts refactor for string parametrization - added method for inserting substrings into sql queries - substrings extracted to the AP classes - allow reparametrization on configuration page
1 parent 5f1bc21 commit 157c07d

12 files changed

Lines changed: 170 additions & 63 deletions

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
public class Constants {
44
public static final String ANTI_PATTERN_CATALOGUE_URL = "https://github.com/ReliSA/Software-process-antipatterns-catalogue/blob/master/catalogue/";
5+
public static final String SUBSTRING_DELIMITER = "||";
56
}

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/DatabaseConnection.java

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@
66
import cz.zcu.fav.kiv.antipatterndetectionapp.utils.Utils;
77

88
import java.sql.*;
9-
import java.util.*;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.Map;
1012

13+
/**
14+
* A class that takes care of database connections and running queries.
15+
*/
1116
public class DatabaseConnection {
1217

1318
private Connection databaseConnection;
1419

20+
/**
21+
* Constructor that takes application properties from configuration file name application.properties
22+
* and creating new database connection with given parameters.
23+
*/
1524
public DatabaseConnection() {
1625
ApplicationProperties applicationProperties = ((ApplicationProperties) SpringApplicationContext.getContext()
1726
.getBean("applicationProperties"));
@@ -21,6 +30,14 @@ public DatabaseConnection() {
2130
this.databaseConnection = createConnection(connectionUrl, dataSourceUsername, dataSourcePassword);
2231
}
2332

33+
/**
34+
* Method for creating database connection with given parameters.
35+
*
36+
* @param connectionUrl database url to connect
37+
* @param dataSourceUsername database username
38+
* @param dataSourcePassword database user password
39+
* @return new database connection
40+
*/
2441
private Connection createConnection(String connectionUrl, String dataSourceUsername, String dataSourcePassword) {
2542
Connection conn = null;
2643
try {
@@ -32,27 +49,45 @@ private Connection createConnection(String connectionUrl, String dataSourceUsern
3249
return conn;
3350
}
3451

35-
public void closeConnection() {
52+
/**
53+
* Method for closing database connection. It is necessary to close the database
54+
* connection when the database connection is not used due to the accumulation
55+
* of unused connections.
56+
*/
57+
void closeConnection() {
3658
try {
3759
this.databaseConnection.close();
3860
} catch (SQLException e) {
3961
e.printStackTrace();
4062
}
4163
}
4264

65+
/**
66+
* Simple getter for getting the database connection.
67+
*
68+
* @return database connection
69+
*/
4370
public Connection getDatabaseConnection() {
4471
return databaseConnection;
4572
}
4673

74+
/**
75+
* Method for analyzing a given project. These methods are intended
76+
* for queries that have a single select output (for example Road To Nowhere).
77+
*
78+
* @param project analyzed project
79+
* @param queries list of queries
80+
* @return result set of results
81+
*/
4782
public ResultSet executeQueries(Project project, List<String> queries) {
4883
Statement stmt;
4984
ResultSet resultSet = null;
5085
try {
5186
stmt = this.getDatabaseConnection().createStatement();
5287

5388
for (String query : queries) {
54-
if(queries.indexOf(query) != queries.size()-1){
55-
if(query.contains("?"))
89+
if (queries.indexOf(query) != queries.size() - 1) {
90+
if (query.contains("?"))
5691
query = query.replace("?", project.getId().toString());
5792
stmt.executeQuery(query);
5893
} else {
@@ -66,24 +101,24 @@ public ResultSet executeQueries(Project project, List<String> queries) {
66101
return resultSet;
67102
}
68103

69-
public List<List<Map<String,Object>>> executeQueriesWithMultipleResults(Project project, List<String> queries) {
104+
public List<List<Map<String, Object>>> executeQueriesWithMultipleResults(Project project, List<String> queries) {
70105
Statement stmt;
71-
List<List<Map<String,Object>>> allResults = new ArrayList<>();
106+
List<List<Map<String, Object>>> allResults = new ArrayList<>();
72107
ResultSet resultSet = null;
73108
try {
74109
stmt = this.getDatabaseConnection().createStatement();
75110

76111
for (String query : queries) {
77-
if(queries.indexOf(query) != queries.size()-1){
78-
if(query.contains("?"))
112+
if (queries.indexOf(query) != queries.size() - 1) {
113+
if (query.contains("?"))
79114
query = query.replace("?", project.getId().toString());
80115
resultSet = stmt.executeQuery(query);
81116
} else {
82117
resultSet = stmt.executeQuery(query);
83118
}
84119

85120
if (query.toLowerCase().startsWith("select")) {
86-
allResults.add(resultSetToArrayList(resultSet));
121+
allResults.add(Utils.resultSetToArrayList(resultSet));
87122
}
88123

89124
}
@@ -93,19 +128,4 @@ public List<List<Map<String,Object>>> executeQueriesWithMultipleResults(Project
93128

94129
return allResults;
95130
}
96-
97-
private List<Map<String,Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
98-
ResultSetMetaData md = rs.getMetaData();
99-
int columns = md.getColumnCount();
100-
List<Map<String, Object>> list = new ArrayList<>();
101-
while (rs.next()) {
102-
Map<String, Object> row = new HashMap<>(columns);
103-
for (int i = 1; i <= columns; ++i) {
104-
row.put(md.getColumnName(i), rs.getObject(i));
105-
}
106-
list.add(row);
107-
}
108-
109-
return list;
110-
}
111131
}

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/detectors/BusinessAsUsualDetectorImpl.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors;
22

3+
import cz.zcu.fav.kiv.antipatterndetectionapp.Constants;
34
import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.DatabaseConnection;
45
import cz.zcu.fav.kiv.antipatterndetectionapp.model.*;
6+
import cz.zcu.fav.kiv.antipatterndetectionapp.utils.Utils;
57
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
79

8-
import java.util.ArrayList;
9-
import java.util.HashMap;
10-
import java.util.List;
11-
import java.util.Map;
10+
import java.util.*;
1211

1312
public class BusinessAsUsualDetectorImpl implements AntiPatternDetector {
1413

@@ -23,6 +22,12 @@ public class BusinessAsUsualDetectorImpl implements AntiPatternDetector {
2322
put("divisionOfIterationsWithRetrospective", new Configuration<Float>("divisionOfIterationsWithRetrospective",
2423
"Division of iterations with retrospective",
2524
"Minimum percentage of the total number of iterations with a retrospective (0,1)", 0.66666f));
25+
put("searchSubstringsWithRetrospective", new Configuration<String>("searchSubstringsWithRetrospective",
26+
"Search substrings with retrospective",
27+
"Substring that will be search in wikipages and activities",
28+
"%retr%" + Constants.SUBSTRING_DELIMITER +
29+
"%revi%" + Constants.SUBSTRING_DELIMITER +
30+
"%week%scrum%"));
2631
}},
2732
"Business_As_Usual.md");
2833

@@ -35,6 +40,10 @@ private float getDivisionOfIterationsWithRetrospective() {
3540
return (float) antiPattern.getConfigurations().get("divisionOfIterationsWithRetrospective").getValue();
3641
}
3742

43+
private List<String> getSearchSubstringsWithRetrospective() {
44+
return Arrays.asList(((String) antiPattern.getConfigurations().get("searchSubstringsWithRetrospective").getValue()).split("\\|\\|"));
45+
}
46+
3847
@Override
3948
public AntiPattern getAntiPatternModel() {
4049
return this.antiPattern;
@@ -75,7 +84,8 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
7584
Map<String, Integer> iterationsResults = new HashMap<>();
7685

7786
// projít výsledky dotazů a dát do jedné mapy => v této mapě by měly být všechny iterace
78-
List<List<Map<String, Object>>> resultSets = databaseConnection.executeQueriesWithMultipleResults(project, this.sqlQueries);
87+
List<List<Map<String, Object>>> resultSets = databaseConnection.executeQueriesWithMultipleResults(project,
88+
Utils.fillQueryWithSearchSubstrings(this.sqlQueries, getSearchSubstringsWithRetrospective()));
7989
for (int i = 0; i < resultSets.size(); i++) {
8090
List<Map<String, Object>> rs = resultSets.get(i);
8191

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/detectors/LongOrNonExistentFeedbackLoopsDetectorImpl.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors;
22

3+
import cz.zcu.fav.kiv.antipatterndetectionapp.Constants;
34
import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.DatabaseConnection;
45
import cz.zcu.fav.kiv.antipatterndetectionapp.model.*;
56
import cz.zcu.fav.kiv.antipatterndetectionapp.utils.Utils;
@@ -8,10 +9,7 @@
89

910
import java.math.BigDecimal;
1011
import java.sql.Date;
11-
import java.util.ArrayList;
12-
import java.util.HashMap;
13-
import java.util.List;
14-
import java.util.Map;
12+
import java.util.*;
1513

1614
public class LongOrNonExistentFeedbackLoopsDetectorImpl implements AntiPatternDetector {
1715

@@ -33,8 +31,18 @@ public class LongOrNonExistentFeedbackLoopsDetectorImpl implements AntiPatternDe
3331
"Maximum gap between feedback loop rate",
3432
"Value that multiplies average iteration length for given project. Result" +
3533
" is maximum threshold value for gap between feedback loops in days.", 2f));
34+
put("searchSubstringsWithFeedbackLoop", new Configuration<String>("searchSubstringsWithFeedbackLoop",
35+
"Search substrings with feedback loop",
36+
"Substring that will be search in wikipages and activities",
37+
"%schůz%zákazník%" + Constants.SUBSTRING_DELIMITER +
38+
"%předvedení%zákazník%" + Constants.SUBSTRING_DELIMITER +
39+
"%zákazn%demo%" + Constants.SUBSTRING_DELIMITER +
40+
"%schůz%zadavat%" + Constants.SUBSTRING_DELIMITER +
41+
"%inform%schůz%" + Constants.SUBSTRING_DELIMITER +
42+
"%zákazn%" + Constants.SUBSTRING_DELIMITER +
43+
"%zadavatel%"));
3644
}}
37-
);
45+
);
3846

3947
private final String SQL_FILE_NAME = "long_or_non_existent_feedback_loops.sql";
4048
// sql queries loaded from sql file
@@ -48,6 +56,10 @@ private float getMaxGapBetweenFeedbackLoopRate() {
4856
return (float) antiPattern.getConfigurations().get("maxGapBetweenFeedbackLoopRate").getValue();
4957
}
5058

59+
private List<String> getSearchSubstringsWithFeedbackLoop() {
60+
return Arrays.asList(((String) antiPattern.getConfigurations().get("searchSubstringsWithFeedbackLoop").getValue()).split("\\|\\|"));
61+
}
62+
5163
@Override
5264
public AntiPattern getAntiPatternModel() {
5365
return this.antiPattern;
@@ -91,7 +103,8 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
91103
Date projectStartDate = null;
92104
Date projectEndDate = null;
93105

94-
List<List<Map<String, Object>>> resultSets = databaseConnection.executeQueriesWithMultipleResults(project, this.sqlQueries);
106+
List<List<Map<String, Object>>> resultSets = databaseConnection.executeQueriesWithMultipleResults(project,
107+
Utils.fillQueryWithSearchSubstrings(this.sqlQueries, getSearchSubstringsWithFeedbackLoop()));
95108
for (int i = 0; i < resultSets.size(); i++) {
96109
List<Map<String, Object>> rs = resultSets.get(i);
97110

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/detectors/RoadToNowhereDetectorImpl.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors;
22

3+
import cz.zcu.fav.kiv.antipatterndetectionapp.Constants;
34
import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.DatabaseConnection;
45
import cz.zcu.fav.kiv.antipatterndetectionapp.model.*;
6+
import cz.zcu.fav.kiv.antipatterndetectionapp.utils.Utils;
57
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
79

810
import java.sql.ResultSet;
911
import java.sql.SQLException;
10-
import java.util.ArrayList;
11-
import java.util.HashMap;
12-
import java.util.List;
12+
import java.util.*;
1313

1414
public class RoadToNowhereDetectorImpl implements AntiPatternDetector {
1515

@@ -28,6 +28,13 @@ public class RoadToNowhereDetectorImpl implements AntiPatternDetector {
2828
put("minNumberOfActivitiesWithProjectPlan", new Configuration<Integer>("minNumberOfActivitiesWithProjectPlan",
2929
"Minimum number of activities with project plan",
3030
"Number of activities", 1));
31+
put("searchSubstringsWithProjectPlan", new Configuration<String>("searchSubstringsWithProjectPlan",
32+
"Search substrings with project plan",
33+
"Substring that will be search in wikipages and activities",
34+
"%plán projektu%" + Constants.SUBSTRING_DELIMITER +
35+
"%project plan%" + Constants.SUBSTRING_DELIMITER +
36+
"%plan project%" + Constants.SUBSTRING_DELIMITER +
37+
"%projektový plán%"));
3138
}},
3239
"Road_To_Nowhere.md");
3340

@@ -43,6 +50,10 @@ private int getMinNumberOfActivitiesWithProjectPlan() {
4350
return (int) antiPattern.getConfigurations().get("minNumberOfActivitiesWithProjectPlan").getValue();
4451
}
4552

53+
private List<String> getSearchSubstringsWithProjectPlan() {
54+
return Arrays.asList(((String) antiPattern.getConfigurations().get("searchSubstringsWithProjectPlan").getValue()).split("\\|\\|"));
55+
}
56+
4657
@Override
4758
public AntiPattern getAntiPatternModel() {
4859
return this.antiPattern;
@@ -60,9 +71,9 @@ public void setSqlQueries(List<String> queries) {
6071

6172
/**
6273
* Postup detekce:
63-
* 1) u každého projektu zkusit nalézt jestli obsahuje nějaké wiki stránky s projektovým plánem
64-
* 2) dále zkusit najít aktivity, které by naznačovali, že vznikl nějaký projektový plán
65-
* 3) pokud nebude nalezena žádná aktivita nebo wiki stránka, tak je antivzor detekován
74+
* 1) u každého projektu zkusit nalézt jestli obsahuje nějaké wiki stránky s projektovým plánem
75+
* 2) dále zkusit najít aktivity, které by naznačovali, že vznikl nějaký projektový plán
76+
* 3) pokud nebude nalezena žádná aktivita nebo wiki stránka, tak je antivzor detekován
6677
*
6778
* @param project analyzovaný project
6879
* @param databaseConnection databázové připojení
@@ -77,7 +88,8 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
7788
int numberOfWikiPagesForProjectPlan = 0;
7889

7990
try {
80-
ResultSet rs = databaseConnection.executeQueries(project, this.sqlQueries);
91+
ResultSet rs = databaseConnection.executeQueries(project,
92+
Utils.fillQueryWithSearchSubstrings(this.sqlQueries, getSearchSubstringsWithProjectPlan()));
8193
if (rs != null) {
8294
while (rs.next()) {
8395
numberOfIssuesForProjectPlan = rs.getInt("numberOfIssuesForProjectPlan");
@@ -94,7 +106,7 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
94106
resultDetails.add(new ResultDetail("Number of issues for creating project plan", String.valueOf(numberOfIssuesForProjectPlan)));
95107
resultDetails.add(new ResultDetail("Number of wiki pages for creating project plan", String.valueOf(numberOfWikiPagesForProjectPlan)));
96108

97-
if( numberOfIssuesForProjectPlan >= getMinNumberOfActivitiesWithProjectPlan() || numberOfWikiPagesForProjectPlan >= getMinNumberOfWikiPagesWithProjectPlan()) {
109+
if (numberOfIssuesForProjectPlan >= getMinNumberOfActivitiesWithProjectPlan() || numberOfWikiPagesForProjectPlan >= getMinNumberOfWikiPagesWithProjectPlan()) {
98110
resultDetails.add(new ResultDetail("Conclusion", "Found some activities or wiki pages for project plan in first two iterations"));
99111
return new QueryResultItem(this.antiPattern, false, resultDetails);
100112
} else {

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/detectors/SpecifyNothingDetectorImpl.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors;
22

3+
import cz.zcu.fav.kiv.antipatterndetectionapp.Constants;
34
import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.DatabaseConnection;
45
import cz.zcu.fav.kiv.antipatterndetectionapp.model.*;
6+
import cz.zcu.fav.kiv.antipatterndetectionapp.utils.Utils;
57
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
79

810
import java.sql.ResultSet;
911
import java.sql.SQLException;
10-
import java.util.ArrayList;
11-
import java.util.HashMap;
12-
import java.util.List;
12+
import java.util.*;
1313

1414
public class SpecifyNothingDetectorImpl implements AntiPatternDetector {
1515

@@ -30,6 +30,14 @@ public class SpecifyNothingDetectorImpl implements AntiPatternDetector {
3030
put("minAvgLengthOfActivityDescription", new Configuration<Integer>("minAvgLengthOfActivityDescription",
3131
"Minimum average length of activity description",
3232
"Minimum average number of character of activity description", 150));
33+
put("searchSubstringsWithProjectSpecification", new Configuration<String>("searchSubstringsWithProjectSpecification",
34+
"Search substrings with project specification",
35+
"Substring that will be search in wikipages and activities",
36+
"%dsp%" + Constants.SUBSTRING_DELIMITER +
37+
"%specifikace%" + Constants.SUBSTRING_DELIMITER +
38+
"%specification%" + Constants.SUBSTRING_DELIMITER +
39+
"%vize%proj%" + Constants.SUBSTRING_DELIMITER +
40+
"%vize%produ%"));
3341
}},
3442
"Specify_Nothing.md");
3543

@@ -49,6 +57,10 @@ private int getMinAvgLengthOfActivityDescription() {
4957
return (int) antiPattern.getConfigurations().get("minAvgLengthOfActivityDescription").getValue();
5058
}
5159

60+
private List<String> getSearchSubstringsWithProjectSpecification() {
61+
return Arrays.asList(((String) antiPattern.getConfigurations().get("searchSubstringsWithProjectSpecification").getValue()).split("\\|\\|"));
62+
}
63+
5264
@Override
5365
public AntiPattern getAntiPatternModel() {
5466
return this.antiPattern;
@@ -86,7 +98,8 @@ public QueryResultItem analyze(Project project, DatabaseConnection databaseConne
8698
double averageLengthOfIssueDescription = 0;
8799

88100
try {
89-
ResultSet rs = databaseConnection.executeQueries(project, this.sqlQueries);
101+
ResultSet rs = databaseConnection.executeQueries(project,
102+
Utils.fillQueryWithSearchSubstrings(this.sqlQueries, getSearchSubstringsWithProjectSpecification()));
90103
if (rs != null) {
91104
while (rs.next()) {
92105
numberOfWikiPages = rs.getInt("numberOfWikiPages");

src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternServiceImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ public boolean saveNewConfiguration(String[] configNames, String[] configValues)
9090
} catch (NumberFormatException e) {
9191
return false;
9292
}
93+
} else if (antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).getValue().getClass() == String.class) {
94+
antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).setValue((configValues[i]));
95+
setConfigurationChanged(true);
9396
}
9497
}
9598
}

0 commit comments

Comments
 (0)