TSK-395 created REST interface for TaskStatusReport

This commit is contained in:
Mustapha Zorgati 2018-03-22 10:40:17 +01:00
parent bb4d5adf35
commit 02fc6b3cd3
15 changed files with 217 additions and 47 deletions

View File

@ -20,12 +20,42 @@ public abstract class Report<Item extends QueryItem, ColumnHeader extends Report
protected List<ColumnHeader> columnHeaders = new ArrayList<>();
private Map<String, ReportRow<Item>> reportRows = new LinkedHashMap<>();
private ReportRow<Item> sumRow;
private String rowDesc;
public Report(List<ColumnHeader> columnHeaders) {
public Report(List<ColumnHeader> columnHeaders, String rowDesc) {
this.rowDesc = rowDesc;
sumRow = new ReportRow<>(columnHeaders.size());
this.columnHeaders.addAll(columnHeaders);
}
public final Map<String, ReportRow<Item>> getReportRows() {
return reportRows;
}
public final ReportRow<Item> getSumRow() {
return sumRow;
}
public final List<ColumnHeader> getColumnHeaders() {
return columnHeaders;
}
public final String getRowDesc() {
return rowDesc;
}
public ReportRow<Item> getRow(String key) {
return reportRows.get(key);
}
public final Set<String> rowTitles() {
return reportRows.keySet();
}
public final int rowSize() {
return reportRows.size();
}
public final void addItem(Item item) {
ReportRow<Item> row = reportRows.computeIfAbsent(item.getKey(), (s) -> createReportRow(columnHeaders.size()));
if (columnHeaders.isEmpty()) {
@ -51,27 +81,7 @@ public abstract class Report<Item extends QueryItem, ColumnHeader extends Report
items.forEach(this::addItem);
}
public ReportRow<Item> getRow(String key) {
return reportRows.get(key);
}
public final ReportRow<Item> getSumRow() {
return sumRow;
}
public Set<String> rowTitles() {
return reportRows.keySet();
}
public final int rowSize() {
return reportRows.size();
}
protected ReportRow<Item> createReportRow(int columnSize) {
return new ReportRow<>(columnSize);
}
public List<ColumnHeader> getColumnHeaders() {
return columnHeaders;
}
}

View File

@ -8,7 +8,7 @@ package pro.taskana.impl.report;
*/
public interface ReportColumnHeader<Item extends QueryItem> {
String displayName();
String getDisplayName();
boolean fits(Item item);

View File

@ -10,7 +10,7 @@ import pro.taskana.impl.report.Report;
public class CategoryReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
public CategoryReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
super(timeIntervalColumnHeaders);
super(timeIntervalColumnHeaders, "CLASSIFICATION CATEGORIES");
}
}

View File

@ -11,7 +11,7 @@ import pro.taskana.impl.report.Report;
public class ClassificationReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
public ClassificationReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
super(timeIntervalColumnHeaders);
super(timeIntervalColumnHeaders, "CLASSIFICATION KEYS");
}
}

View File

@ -10,6 +10,6 @@ import pro.taskana.impl.report.Report;
public class CustomFieldValueReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
public CustomFieldValueReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
super(timeIntervalColumnHeaders);
super(timeIntervalColumnHeaders, "CUSTOM FIELDS");
}
}

View File

@ -12,7 +12,7 @@ import pro.taskana.impl.report.Report;
public class DetailedClassificationReport extends Report<DetailedMonitorQueryItem, TimeIntervalColumnHeader> {
public DetailedClassificationReport(List<TimeIntervalColumnHeader> workbasketLevelReportColumnHeaders) {
super(workbasketLevelReportColumnHeaders);
super(workbasketLevelReportColumnHeaders, "TASK CLASSIFICATION KEYS");
}
@Override

View File

@ -4,7 +4,7 @@ import pro.taskana.TaskState;
import pro.taskana.impl.report.ReportColumnHeader;
/**
* TODO.
* The TaskStatusColumnHeader represents a column for each {@link TaskState}.
*/
public class TaskStatusColumnHeader implements ReportColumnHeader<TaskQueryItem> {
@ -15,7 +15,7 @@ public class TaskStatusColumnHeader implements ReportColumnHeader<TaskQueryItem>
}
@Override
public String displayName() {
public String getDisplayName() {
return state.name();
}
@ -26,6 +26,6 @@ public class TaskStatusColumnHeader implements ReportColumnHeader<TaskQueryItem>
@Override
public String toString() {
return displayName();
return getDisplayName();
}
}

View File

@ -8,7 +8,7 @@ import pro.taskana.TaskState;
import pro.taskana.impl.report.Report;
/**
* TODO.
* The TaskStatusReport displays the amount of tasks, differentiated by their state and grouped by domain.
*/
public class TaskStatusReport extends Report<TaskQueryItem, TaskStatusColumnHeader> {
@ -19,7 +19,7 @@ public class TaskStatusReport extends Report<TaskQueryItem, TaskStatusColumnHead
public TaskStatusReport(List<TaskState> filter) {
super((filter != null ? filter.stream() : Arrays.stream(TaskState.values()))
.map(TaskStatusColumnHeader::new)
.collect(Collectors.toList()));
.collect(Collectors.toList()), "DOMAINS");
}
}

View File

@ -35,11 +35,11 @@ public class TimeIntervalColumnHeader implements ReportColumnHeader<MonitorQuery
@Override
public String toString() {
return displayName();
return getDisplayName();
}
@Override
public String displayName() {
public String getDisplayName() {
return "(" + this.lowerAgeLimit + "," + this.upperAgeLimit + ")";
}

View File

@ -10,7 +10,7 @@ import pro.taskana.impl.report.Report;
public class WorkbasketLevelReport extends Report<MonitorQueryItem, TimeIntervalColumnHeader> {
public WorkbasketLevelReport(List<TimeIntervalColumnHeader> timeIntervalColumnHeaders) {
super(timeIntervalColumnHeaders);
super(timeIntervalColumnHeaders, "WORKBASKET KEYS");
}
}

View File

@ -160,7 +160,7 @@ public class ProvideTaskStatusReportAccTest {
builder.append("\n");
builder.append(String.format(formatFirstColumnFirstLine, "Domain", "Total"));
for (TaskStatusColumnHeader def : columnHeaders) {
builder.append(String.format(formatColumnWidth, def.displayName()));
builder.append(String.format(formatColumnWidth, def.getDisplayName()));
}
builder.append("|\n");

View File

@ -4,7 +4,6 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
@ -14,17 +13,22 @@ import org.springframework.web.bind.annotation.RestController;
import pro.taskana.TaskMonitorService;
import pro.taskana.TaskState;
import pro.taskana.rest.resource.ReportResource;
import pro.taskana.rest.resource.mapper.ReportMapper;
/**
* Controller for all monitoring endpoints.
*/
@RestController
@RequestMapping(path = "/v1/monitor", produces = {MediaType.APPLICATION_JSON_VALUE})
@RequestMapping(path = "/v1/monitor", produces = "application/hal+json")
public class MonitorController {
@Autowired
private TaskMonitorService taskMonitorService;
@Autowired
private ReportMapper reportMapper;
@GetMapping(path = "/countByState")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<?> getTaskcountForState(
@ -65,8 +69,9 @@ public class MonitorController {
@GetMapping(path = "/taskStatusReport")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<?> getTaskStatusReport(@RequestParam(required = false) List<String> domains,
public ResponseEntity<ReportResource> getTaskStatusReport(@RequestParam(required = false) List<String> domains,
@RequestParam(required = false) List<TaskState> states) {
return ResponseEntity.status(HttpStatus.OK).body(taskMonitorService.getTaskStatusReport(domains, states));
return ResponseEntity.status(HttpStatus.OK)
.body(reportMapper.toResource(taskMonitorService.getTaskStatusReport(domains, states), domains, states));
}
}

View File

@ -19,9 +19,6 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import pro.taskana.ClassificationService;
@ -94,11 +91,6 @@ public class RestConfiguration {
return b;
}
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder jacksonBuilder) {
return jacksonBuilder.build().setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}
//Needed for injection into jackson deserilizer.
@Bean
public HandlerInstantiator handlerInstantiator(ApplicationContext context) {

View File

@ -0,0 +1,97 @@
package pro.taskana.rest.resource;
import java.util.Map;
import org.springframework.hateoas.ResourceSupport;
/**
* Resource class for {@link pro.taskana.impl.report.Report}.
*/
public class ReportResource extends ResourceSupport {
private MetaInformation meta;
private Map<String, RowResource> rows;
private RowResource sumRow;
public ReportResource(MetaInformation meta, Map<String, RowResource> rows, RowResource sumRow) {
this.meta = meta;
this.rows = rows;
this.sumRow = sumRow;
}
public MetaInformation getMeta() {
return meta;
}
public Map<String, RowResource> getRows() {
return rows;
}
public RowResource getSumRow() {
return sumRow;
}
/**
* Meta Information about this ReportResource.
*/
public static class MetaInformation {
private static final String TOTAL_DESC = "Total";
private String name;
private String date;
private String[] header;
private String rowDesc;
public MetaInformation(String name, String date, String[] header, String rowDesc) {
this.name = name;
this.date = date;
this.header = header;
this.rowDesc = rowDesc;
}
public String getTotalDesc() {
return TOTAL_DESC;
}
public String getName() {
return name;
}
public String getDate() {
return date;
}
public String[] getHeader() {
return header;
}
public String getRowDesc() {
return rowDesc;
}
}
/**
* Resource class for {@link pro.taskana.impl.report.ReportRow}.
*/
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;
}
}
}

View File

@ -0,0 +1,66 @@
package pro.taskana.rest.resource.mapper;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import pro.taskana.TaskState;
import pro.taskana.impl.report.QueryItem;
import pro.taskana.impl.report.Report;
import pro.taskana.impl.report.ReportColumnHeader;
import pro.taskana.impl.report.ReportRow;
import pro.taskana.impl.report.impl.TaskStatusReport;
import pro.taskana.rest.MonitorController;
import pro.taskana.rest.resource.ReportResource;
/**
* Transforms any {@link Report} into its {@link ReportResource}.
*/
@Component
public class ReportMapper {
public ReportResource toResource(TaskStatusReport report, List<String> domains, List<TaskState> states) {
ReportResource resource = toResource(report);
resource.add(
linkTo(methodOn(MonitorController.class).getTaskStatusReport(domains, states))
.withSelfRel().expand());
return resource;
}
private <I extends QueryItem, H extends ReportColumnHeader<? super I>> ReportResource toResource(
Report<I, H> report) {
String[] header = report.getColumnHeaders().stream()
.map(ReportColumnHeader::getDisplayName)
.toArray(String[]::new);
ReportResource.MetaInformation meta = new ReportResource.MetaInformation(
report.getClass().getSimpleName(),
Instant.now().toString(),
header,
report.getRowDesc());
// iterate over each ReportRow and transform it to a RowResource while keeping the domain key.
Map<String, ReportResource.RowResource> rows = report.getReportRows().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, i -> transformRow(i.getValue(), header)));
ReportResource.RowResource sumRow = transformRow(report.getSumRow(), header);
return new ReportResource(meta, rows, sumRow);
}
private <I extends QueryItem> ReportResource.RowResource transformRow(ReportRow<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());
}
}