TSK-685: added DailyEntryExitReport to taskana-rest-spring

This commit is contained in:
Mustapha Zorgati 2019-01-02 13:40:49 +01:00
parent 37f48a5667
commit 4dd2415a3a
4 changed files with 134 additions and 41 deletions

View File

@ -124,7 +124,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
}
public static boolean isPostgreSQL(String databaseProductName) {
return databaseProductName.equals("PostgreSQL");
return "PostgreSQL".equals(databaseProductName);
}
@Override

View File

@ -3,6 +3,7 @@ package pro.taskana.rest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.slf4j.Logger;
@ -21,7 +22,6 @@ import pro.taskana.TaskState;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.impl.report.header.TimeIntervalColumnHeader;
import pro.taskana.rest.resource.ReportResource;
import pro.taskana.rest.resource.ReportAssembler;
import pro.taskana.rest.resource.ReportResource;
@ -91,6 +91,20 @@ public class MonitorController {
return response;
}
@GetMapping(path = "/daily-entry-exit-report")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<ReportResource> getDailyEntryExitReport()
throws NotAuthorizedException, InvalidArgumentException {
List<TimeIntervalColumnHeader.Date> columnHeaders = IntStream.range(-14, 0)
.mapToObj(TimeIntervalColumnHeader.Date::new)
.collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK)
.body(reportAssembler.toResource(
taskMonitorService.createDailyEntryExitReportBuilder()
.withColumnHeaders(columnHeaders)
.buildReport()));
}
private List<TimeIntervalColumnHeader> getTaskClassificationTimeInterval() {
return Stream.concat(Stream.concat(
Stream.of(new TimeIntervalColumnHeader.Range(Integer.MIN_VALUE, -10),

View File

@ -14,14 +14,16 @@ import org.springframework.stereotype.Component;
import pro.taskana.TaskState;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.impl.report.row.FoldableRow;
import pro.taskana.impl.report.row.SingleRow;
import pro.taskana.report.ClassificationReport;
import pro.taskana.report.structure.ColumnHeader;
import pro.taskana.report.DailyEntryExitReport;
import pro.taskana.report.TaskStatusReport;
import pro.taskana.report.WorkbasketReport;
import pro.taskana.report.structure.ColumnHeader;
import pro.taskana.report.structure.QueryItem;
import pro.taskana.report.structure.Report;
import pro.taskana.report.structure.Row;
import pro.taskana.report.TaskStatusReport;
import pro.taskana.report.WorkbasketReport;
import pro.taskana.rest.MonitorController;
/**
@ -57,6 +59,13 @@ public class ReportAssembler {
return resource;
}
public ReportResource toResource(DailyEntryExitReport report)
throws NotAuthorizedException, InvalidArgumentException {
ReportResource resource = toReportResource(report);
resource.add(linkTo(methodOn(MonitorController.class).getDailyEntryExitReport()).withSelfRel().expand());
return resource;
}
private <I extends QueryItem, H extends ColumnHeader<? super I>> ReportResource toReportResource(
Report<I, H> report) {
String[] header = report.getColumnHeaders()
@ -80,14 +89,52 @@ public class ReportAssembler {
return new ReportResource(meta, rows, sumRow);
}
private <I extends QueryItem> ReportResource.RowResource transformRow(Row<I> row,
private <I extends QueryItem> ReportResource.RowResource transformRow(Row<I> row, String[] header) {
// This is a very dirty solution.. Personally I'd prefer to use a visitor-like pattern here.
// The issue with that: Addition of the visitor code within taskana-core - and having clean code is not
// a reason to append code somewhere where it doesn't belong.
if (row.getClass() == SingleRow.class) {
return transformSingleRow((SingleRow<I>) row, header);
}
return transformFoldableRow((FoldableRow<I>) row, header);
}
private <I extends QueryItem> ReportResource.SingleRowResource transformSingleRow(SingleRow<I> row,
String[] header) {
Map<String, Integer> result = new HashMap<>();
int[] cells = row.getCells();
for (int i = 0; i < cells.length; i++) {
result.put(header[i], cells[i]);
}
return new ReportResource.RowResource(result, row.getTotalValue());
return new ReportResource.SingleRowResource(result, row.getTotalValue());
}
private <I extends QueryItem> ReportResource.FoldableRowResource transformFoldableRow(FoldableRow<I> row,
String[] header) {
ReportResource.FoldableRowResource base = new ReportResource.FoldableRowResource(
transformSingleRow(row, header));
row.getFoldableRowKeySet().stream()
.map(k -> new Pair<>(k, row.getFoldableRow(k)))
.map(p -> new Pair<>(p.key, transformRow(p.value, header)))
.forEachOrdered(p -> base.addRow(p.key, p.value));
return base;
}
/**
* Simple Pair (tuple).
* @param <K> key
* @param <V> value
*/
private class Pair<K, V> {
private final K key;
private final V value;
Pair(K key, V value) {
this.key = key;
this.value = value;
}
}
}

View File

@ -1,15 +1,15 @@
package pro.taskana.rest.resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.springframework.hateoas.ResourceSupport;
import pro.taskana.impl.util.LoggerUtils;
import pro.taskana.report.structure.Report;
import pro.taskana.report.structure.Row;
/**
* Resource class for {@link Report}.
* Resource class for {@link pro.taskana.report.structure.Report}.
*/
public class ReportResource extends ResourceSupport {
@ -37,6 +37,68 @@ public class ReportResource extends ResourceSupport {
return sumRow;
}
/**
* Resource Interface for {@link pro.taskana.report.structure.Row}.
*/
public interface RowResource {
Map<String, Integer> getCells();
int getTotal();
}
/**
* Resource class for {@link pro.taskana.impl.report.row.SingleRow}.
*/
public static class SingleRowResource implements RowResource {
private Map<String, Integer> cells;
private int total;
public SingleRowResource(Map<String, Integer> cells, int total) {
this.cells = cells;
this.total = total;
}
@Override
public Map<String, Integer> getCells() {
return cells;
}
@Override
public int getTotal() {
return total;
}
@Override
public String toString() {
return "SingleRowResource ["
+ "rowDesc= " + LoggerUtils.mapToString(this.cells)
+ "taskId= " + this.total
+ "]";
}
}
/**
* Resource class for {@link pro.taskana.impl.report.row.FoldableRow}.
*/
public static class FoldableRowResource extends SingleRowResource {
private Map<String, RowResource> foldableRows = new HashMap<>();
public FoldableRowResource(SingleRowResource row) {
super(row.getCells(), row.getTotal());
}
public void addRow(String desc, RowResource row) {
foldableRows.put(desc, row);
}
public Map<String, RowResource> getFoldableRows() {
return foldableRows;
}
}
/**
* Meta Information about this ReportResource.
*/
@ -81,39 +143,9 @@ public class ReportResource extends ResourceSupport {
return "MetaInformation ["
+ "name= " + this.name
+ "date= " + this.date
+ "header= " + this.header
+ "header= " + Arrays.toString(this.header)
+ "rowDesc= " + this.rowDesc
+ "]";
}
}
/**
* Resource class for {@link Row}.
*/
public static class RowResource {
private Map<String, Integer> cells;
private int total;
public RowResource(Map<String, Integer> cells, int total) {
this.cells = cells;
this.total = total;
}
public Map<String, Integer> getCells() {
return cells;
}
public int getTotal() {
return total;
}
@Override
public String toString() {
return "RowResource ["
+ "rowDesc= " + LoggerUtils.mapToString(this.cells)
+ "taskId= " + this.total
+ "]";
}
}
}