Skip to content

Commit c5d00c0

Browse files
mustaphazorgatiholgerhagen
authored andcommitted
TSK-843: moved report structure ajustment from client to rest service.
1 parent d8b1829 commit c5d00c0

File tree

25 files changed

+383
-574
lines changed

25 files changed

+383
-574
lines changed

lib/taskana-core/src/main/java/pro/taskana/impl/report/structure/Report.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,12 @@ public abstract class Report<I extends QueryItem, H extends ColumnHeader<? super
2424
protected List<H> columnHeaders;
2525
private Map<String, Row<I>> reportRows = new LinkedHashMap<>();
2626
private Row<I> sumRow;
27-
private String rowDesc;
28-
private String[] expandableHeaders;
27+
private String[] rowDesc;
2928

30-
protected Report(List<H> columnHeaders, String rowDesc, String[] expandableHeaders) {
29+
protected Report(List<H> columnHeaders, String[] rowDesc) {
3130
this.rowDesc = rowDesc;
3231
sumRow = createRow(columnHeaders.size());
3332
this.columnHeaders = new ArrayList<>(columnHeaders);
34-
this.expandableHeaders = expandableHeaders;
35-
}
36-
37-
protected Report(List<H> columnHeaders, String rowDesc) {
38-
this(columnHeaders, rowDesc, new String[0]);
3933
}
4034

4135
public final Map<String, Row<I>> getRows() {
@@ -50,14 +44,10 @@ public final List<H> getColumnHeaders() {
5044
return columnHeaders;
5145
}
5246

53-
public final String getRowDesc() {
47+
public final String[] getRowDesc() {
5448
return rowDesc;
5549
}
5650

57-
public final String[] getExpandableHeaders() {
58-
return expandableHeaders;
59-
}
60-
6151
public Row<I> getRow(String key) {
6252
return reportRows.get(key);
6353
}

lib/taskana-core/src/main/java/pro/taskana/report/CategoryReport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
public class CategoryReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
2020

2121
public CategoryReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
22-
super(timeIntervalColumnHeaders, "CLASSIFICATION CATEGORIES");
22+
super(timeIntervalColumnHeaders, new String[] {"CLASSIFICATION CATEGORIES"});
2323
}
2424

2525
/**

lib/taskana-core/src/main/java/pro/taskana/report/ClassificationReport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
public class ClassificationReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
1818

1919
public ClassificationReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
20-
super(timeIntervalColumnHeaders, "CLASSIFICATION KEYS");
20+
super(timeIntervalColumnHeaders, new String[] {"CLASSIFICATION KEYS"});
2121
}
2222

2323
/**
@@ -52,7 +52,7 @@ public static class DetailedClassificationReport
5252
extends Report<DetailedMonitorQueryItem, TimeIntervalColumnHeader> {
5353

5454
public DetailedClassificationReport(List<TimeIntervalColumnHeader> workbasketLevelReportColumnHeaders) {
55-
super(workbasketLevelReportColumnHeaders, "TASK CLASSIFICATION KEYS");
55+
super(workbasketLevelReportColumnHeaders, new String[] {"TASK CLASSIFICATION KEYS", "ATTACHMENT"});
5656
}
5757

5858
@Override

lib/taskana-core/src/main/java/pro/taskana/report/CustomFieldValueReport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
public class CustomFieldValueReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
2020

2121
public CustomFieldValueReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
22-
super(timeIntervalColumnHeaders, "CUSTOM FIELDS");
22+
super(timeIntervalColumnHeaders, new String[] {"CUSTOM FIELDS"});
2323
}
2424

2525
/**

lib/taskana-core/src/main/java/pro/taskana/report/TaskStatusReport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class TaskStatusReport extends Report<TaskQueryItem, TaskStatusColumnHead
2121
public TaskStatusReport(List<TaskState> filter) {
2222
super((filter != null ? filter.stream() : Stream.of(TaskState.values()))
2323
.map(TaskStatusColumnHeader::new)
24-
.collect(Collectors.toList()), "DOMAINS");
24+
.collect(Collectors.toList()), new String[] {"DOMAINS"});
2525
}
2626

2727
/**

lib/taskana-core/src/main/java/pro/taskana/report/TimestampReport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
public class TimestampReport extends Report<TimestampQueryItem, TimeIntervalColumnHeader> {
1616

1717
public TimestampReport(List<TimeIntervalColumnHeader> dates) {
18-
super(dates, "STATES", new String[] {"ORG LEVEL 1", "ORG LEVEL 2", "ORG LEVEL 3", "ORG LEVEL 4"});
18+
super(dates, new String[] {"STATES", "ORG LEVEL 1", "ORG LEVEL 2", "ORG LEVEL 3", "ORG LEVEL 4"});
1919
}
2020

2121
@Override

lib/taskana-core/src/main/java/pro/taskana/report/WorkbasketReport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
public class WorkbasketReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
2323

2424
public WorkbasketReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
25-
super(timeIntervalColumnHeaders, "WORKBASKET KEYS");
25+
super(timeIntervalColumnHeaders, new String[] {"WORKBASKET KEYS"});
2626
}
2727

2828
/**

lib/taskana-core/src/test/java/pro/taskana/impl/report/structure/ReportTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class ReportTest {
2929

3030
@Before
3131
public void before() {
32-
this.report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(HEADERS, "rowDesc") {
32+
this.report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(HEADERS, new String[] {"rowDesc"}) {
3333

3434
};
3535

@@ -116,7 +116,8 @@ public void testInsertSameItemMultipleTimesWithPreProcessor() {
116116
@Test
117117
public void testInsertItemWithNoColumnHeaders() {
118118
//given
119-
report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(Collections.emptyList(), "rowDesc") {
119+
report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(Collections.emptyList(),
120+
new String[] {"rowDesc"}) {
120121

121122
};
122123

@@ -148,7 +149,7 @@ public void testInsertItemWhichIsInMultipleHeaderScopes() {
148149
//given
149150
List<TimeIntervalColumnHeader> headers = new ArrayList<>(HEADERS);
150151
headers.add(new TimeIntervalColumnHeader(0, 3));
151-
report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(headers, "rowDesc") {
152+
report = new Report<MonitorQueryItem, TimeIntervalColumnHeader>(headers, new String[] {"rowDesc"}) {
152153

153154
};
154155
item.setAgeInDays(2);

rest/taskana-rest-spring-test/src/main/asciidoc/rest-api.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,22 @@ include::../../../{snippets}/GetTaskClassificationReportDocTest/http-response.ad
658658

659659
Same as task status report
660660

661+
=== Get a timestamp report
662+
663+
A `GET` request is used to get the number of tasks sorted by a task timestamp.
664+
665+
==== Example Request
666+
667+
include::../../../{snippets}/GetTimestampReportDocTest/http-request.adoc[]
668+
669+
==== Example Response
670+
671+
include::../../../{snippets}/GetTimestampReportDocTest/http-response.adoc[]
672+
673+
==== Response Structure
674+
675+
Same as task status report
676+
661677
== Other Resources (using the TaskanaEngineController)
662678

663679
These resources are directly connected to the Taskana Engine endpoint.

rest/taskana-rest-spring-test/src/test/java/pro/taskana/doc/api/MonitorControllerRestDocumentation.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,15 @@ public void setUp() {
6868
fieldWithPath("meta.name").description("Name of the report"),
6969
fieldWithPath("meta.date").description("Date of the report creation"),
7070
fieldWithPath("meta.header").description("Column-headers of the report"),
71-
fieldWithPath("meta.expHeader").description(
72-
"Expandable Column-headers which match the depth of the foldable rows within the report."),
7371
fieldWithPath("meta.rowDesc").description("Descriptions for the rows the report"),
74-
fieldWithPath("meta.totalDesc").description("Description for the report itself"),
75-
subsectionWithPath("rows").description("Object holding the rows of the report.\n"
76-
+ "For the exact structure please check the example response above"),
77-
fieldWithPath("sumRow").description("Object holding the sums in the columns over all rows"),
78-
subsectionWithPath("sumRow.cells")
79-
.description("Contains the accumulated numbers over all columns defined in meta.header.\n"
80-
+ "For the exact structure please check the example response above"),
81-
fieldWithPath("sumRow.total").description("Total number of tasks"),
72+
fieldWithPath("meta.totalDesc").description("Description for the sum column"),
73+
fieldWithPath("rows").description("Array holding the rows of the report."),
74+
fieldWithPath("rows[].cells").description("Array holding all the cell values of the given row"),
75+
fieldWithPath("rows[].total").description("Sum of all values of the given row"),
76+
fieldWithPath("rows[].depth").description("Depth of the row. If the depth is > 0, then this row is a sub-row of a prior row"),
77+
fieldWithPath("rows[].desc").description("Array containing description of the row."),
78+
fieldWithPath("rows[].display").description("Boolean identifying if the given row should be initially displayed or not."),
79+
subsectionWithPath("sumRow").description("Array holding the sums in the columns over all rows. Structure same as 'rows'"),
8280
fieldWithPath("_links.self.href").ignored()
8381
};
8482
}
@@ -115,4 +113,15 @@ public void tasksClassificationReport() throws Exception {
115113
.andDo(MockMvcRestDocumentation.document("GetTaskClassificationReportDocTest",
116114
responseFields(taskReportFieldDescriptors)));
117115
}
116+
117+
@Test
118+
public void getTimestampReport() throws Exception {
119+
this.mockMvc.perform(RestDocumentationRequestBuilders
120+
.get("http://127.0.0.1:" + port + "/v1/monitor/timestamp-report")
121+
.accept("application/hal+json")
122+
.header("Authorization", "Basic YWRtaW46YWRtaW4="))
123+
.andExpect(MockMvcResultMatchers.status().isOk())
124+
.andDo(MockMvcRestDocumentation.document("GetTimestampReportDocTest",
125+
responseFields(taskReportFieldDescriptors)));
126+
}
118127
}

rest/taskana-rest-spring/src/main/java/pro/taskana/rest/resource/ReportAssembler.java

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
55

66
import java.time.Instant;
7-
import java.util.HashMap;
7+
import java.util.Collection;
8+
import java.util.Collections;
9+
import java.util.Comparator;
10+
import java.util.LinkedList;
811
import java.util.List;
9-
import java.util.Map;
1012
import java.util.stream.Collectors;
1113

1214
import org.springframework.stereotype.Component;
@@ -80,65 +82,52 @@ <I extends QueryItem, H extends ColumnHeader<? super I>> ReportResource toReport
8082
report.getClass().getSimpleName(),
8183
time.toString(),
8284
header,
83-
report.getExpandableHeaders(), report.getRowDesc());
85+
report.getRowDesc());
8486

8587
// iterate over each Row and transform it to a RowResource while keeping the domain key.
86-
Map<String, ReportResource.RowResource> rows = report.getRows()
88+
List<ReportResource.RowResource> rows = report.getRows()
8789
.entrySet()
8890
.stream()
89-
.collect(Collectors.toMap(Map.Entry::getKey, i -> transformRow(i.getValue(), header)));
91+
.sorted(Comparator.comparing(e -> e.getKey().toLowerCase()))
92+
.map(i -> transformRow(i.getValue(), i.getKey(), new String[report.getRowDesc().length], 0))
93+
.flatMap(Collection::stream)
94+
.collect(Collectors.toList());
9095

91-
ReportResource.RowResource sumRow = transformRow(report.getSumRow(), header);
96+
List<ReportResource.RowResource> sumRow = transformRow(report.getSumRow(), meta.getTotalDesc(),
97+
new String[report.getRowDesc().length], 0);
9298

9399
return new ReportResource(meta, rows, sumRow);
94100
}
95101

96-
private <I extends QueryItem> ReportResource.RowResource transformRow(Row<I> row, String[] header) {
102+
private <I extends QueryItem> List<ReportResource.RowResource> transformRow(Row<I> row, String currentDesc,
103+
String[] desc, int depth) {
97104
// This is a very dirty solution.. Personally I'd prefer to use a visitor-like pattern here.
98105
// The issue with that: Addition of the visitor code within taskana-core - and having clean code is not
99106
// a reason to append code somewhere where it doesn't belong.
100107
if (row.getClass() == SingleRow.class) {
101-
return transformSingleRow((SingleRow<I>) row, header);
108+
return Collections.singletonList(transformSingleRow((SingleRow<I>) row, currentDesc, desc, depth));
102109
}
103-
return transformFoldableRow((FoldableRow<I>) row, header);
110+
return transformFoldableRow((FoldableRow<I>) row, currentDesc, desc, depth);
104111
}
105112

106-
private <I extends QueryItem> ReportResource.SingleRowResource transformSingleRow(SingleRow<I> row,
107-
String[] header) {
108-
Map<String, Integer> result = new HashMap<>();
109-
int[] cells = row.getCells();
110-
for (int i = 0; i < cells.length; i++) {
111-
result.put(header[i], cells[i]);
112-
}
113-
return new ReportResource.SingleRowResource(result, row.getTotalValue());
113+
private <I extends QueryItem> ReportResource.RowResource transformSingleRow(SingleRow<I> row, String currentDesc,
114+
String[] previousRowDesc, int depth) {
115+
String[] rowDesc = new String[previousRowDesc.length];
116+
System.arraycopy(previousRowDesc, 0, rowDesc, 0, depth);
117+
rowDesc[depth] = currentDesc;
118+
return new ReportResource.RowResource(row.getCells(), row.getTotalValue(), depth, rowDesc, depth == 0);
114119
}
115120

116-
private <I extends QueryItem> ReportResource.FoldableRowResource transformFoldableRow(FoldableRow<I> row,
117-
String[] header) {
118-
ReportResource.FoldableRowResource base = new ReportResource.FoldableRowResource(
119-
transformSingleRow(row, header));
121+
private <I extends QueryItem> List<ReportResource.RowResource> transformFoldableRow(FoldableRow<I> row,
122+
String currentDesc, String[] previousRowDesc, int depth) {
123+
ReportResource.RowResource baseRow = transformSingleRow(row, currentDesc, previousRowDesc, depth);
124+
List<ReportResource.RowResource> rowList = new LinkedList<>();
125+
rowList.add(baseRow);
120126
row.getFoldableRowKeySet().stream()
121-
.map(k -> new Pair<>(k, row.getFoldableRow(k)))
122-
.map(p -> new Pair<>(p.key, transformRow(p.value, header)))
123-
.forEachOrdered(p -> base.addRow(p.key, p.value));
124-
return base;
125-
}
126-
127-
/**
128-
* Simple Pair (tuple).
129-
* @param <K> key
130-
* @param <V> value
131-
*/
132-
private class Pair<K, V> {
133-
134-
private final K key;
135-
private final V value;
136-
137-
Pair(K key, V value) {
138-
this.key = key;
139-
this.value = value;
140-
}
141-
127+
.sorted(String.CASE_INSENSITIVE_ORDER)
128+
.map(s -> transformRow(row.getFoldableRow(s), s, baseRow.getDesc(), depth + 1))
129+
.flatMap(Collection::stream)
130+
.forEachOrdered(rowList::add);
131+
return rowList;
142132
}
143-
144133
}

0 commit comments

Comments
 (0)