Skip to content

Commit cd0f48a

Browse files
committed
Merge remote-tracking branch 'remotes/origin/execution_and_trend_statistics'
2 parents 20c11fa + fe86641 commit cd0f48a

12 files changed

+658
-2
lines changed

Diff for: pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@
296296

297297
<audit.trail.enabled>false</audit.trail.enabled>
298298
<audit.trail.log.file>/tmp/atlas/audit/audit.log</audit.trail.log.file>
299+
<audit.trail.log.file.pattern>/tmp/atlas/audit/audit-%d{yyyy-MM-dd}-%i.log</audit.trail.log.file.pattern>
299300
<audit.trail.log.extraFile>/tmp/atlas/audit/audit-extra.log</audit.trail.log.extraFile>
300301
</properties>
301302
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
package org.ohdsi.webapi.statistic.controller;
2+
3+
import com.opencsv.CSVWriter;
4+
5+
import org.ohdsi.webapi.statistic.dto.AccessTrendDto;
6+
import org.ohdsi.webapi.statistic.dto.AccessTrendsDto;
7+
import org.ohdsi.webapi.statistic.dto.EndpointDto;
8+
import org.ohdsi.webapi.statistic.dto.SourceExecutionDto;
9+
import org.ohdsi.webapi.statistic.dto.SourceExecutionsDto;
10+
import org.ohdsi.webapi.statistic.service.StatisticService;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
12+
import org.springframework.stereotype.Controller;
13+
14+
import javax.ws.rs.Consumes;
15+
import javax.ws.rs.POST;
16+
import javax.ws.rs.Path;
17+
import javax.ws.rs.Produces;
18+
import javax.ws.rs.core.MediaType;
19+
import javax.ws.rs.core.Response;
20+
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.StringWriter;
23+
import java.time.LocalDate;
24+
import java.time.format.DateTimeFormatter;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.stream.Collectors;
28+
29+
@Controller
30+
@Path("/statistic/")
31+
@ConditionalOnProperty(value = "audit.trail.enabled", havingValue = "true")
32+
public class StatisticController {
33+
private StatisticService service;
34+
35+
public enum ResponseFormat {
36+
CSV, JSON
37+
}
38+
39+
private static final List<String[]> EXECUTION_STATISTICS_CSV_RESULT_HEADER = new ArrayList<String[]>() {{
40+
add(new String[]{"Date", "Source", "Execution Type"});
41+
}};
42+
43+
private static final List<String[]> ACCESS_TRENDS_CSV_RESULT_HEADER = new ArrayList<String[]>() {{
44+
add(new String[]{"Date", "Endpoint", "UserID"});
45+
}};
46+
47+
public StatisticController(StatisticService service) {
48+
this.service = service;
49+
}
50+
51+
/**
52+
* Returns execution statistics
53+
* @param executionStatisticsRequest - filter settings for statistics
54+
*/
55+
@POST
56+
@Path("/executions")
57+
@Produces(MediaType.APPLICATION_JSON)
58+
@Consumes(MediaType.APPLICATION_JSON)
59+
public Response executionStatistics(ExecutionStatisticsRequest executionStatisticsRequest) {
60+
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
61+
boolean showUserInformation = executionStatisticsRequest.isShowUserInformation();
62+
63+
SourceExecutionsDto sourceExecutions = service.getSourceExecutions(LocalDate.parse(executionStatisticsRequest.getStartDate(), formatter),
64+
LocalDate.parse(executionStatisticsRequest.getEndDate(), formatter), executionStatisticsRequest.getSourceKey(), showUserInformation);
65+
66+
if (ResponseFormat.CSV.equals(executionStatisticsRequest.getResponseFormat())) {
67+
return prepareExecutionResultResponse(sourceExecutions.getExecutions(), "execution_statistics.zip", showUserInformation);
68+
} else {
69+
return Response.ok(sourceExecutions).build();
70+
}
71+
}
72+
73+
/**
74+
* Returns access trends statistics
75+
* @param accessTrendsStatisticsRequest - filter settings for statistics
76+
*/
77+
@POST
78+
@Path("/accesstrends")
79+
@Produces(MediaType.APPLICATION_JSON)
80+
@Consumes(MediaType.APPLICATION_JSON)
81+
public Response accessStatistics(AccessTrendsStatisticsRequest accessTrendsStatisticsRequest) {
82+
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
83+
boolean showUserInformation = accessTrendsStatisticsRequest.isShowUserInformation();
84+
85+
AccessTrendsDto trends = service.getAccessTrends(LocalDate.parse(accessTrendsStatisticsRequest.getStartDate(), formatter),
86+
LocalDate.parse(accessTrendsStatisticsRequest.getEndDate(), formatter), accessTrendsStatisticsRequest.getEndpoints(), showUserInformation);
87+
88+
if (ResponseFormat.CSV.equals(accessTrendsStatisticsRequest.getResponseFormat())) {
89+
return prepareAccessTrendsResponse(trends.getTrends(), "execution_trends.zip", showUserInformation);
90+
} else {
91+
return Response.ok(trends).build();
92+
}
93+
}
94+
95+
private Response prepareExecutionResultResponse(List<SourceExecutionDto> executions, String filename, boolean showUserInformation) {
96+
updateExecutionStatisticsHeader(showUserInformation);
97+
List<String[]> data = executions.stream()
98+
.map(execution -> showUserInformation
99+
? new String[]{execution.getExecutionDate(), execution.getSourceName(), execution.getExecutionName(), execution.getUserID()}
100+
: new String[]{execution.getExecutionDate(), execution.getSourceName(), execution.getExecutionName()}
101+
)
102+
.collect(Collectors.toList());
103+
return prepareResponse(data, filename, EXECUTION_STATISTICS_CSV_RESULT_HEADER);
104+
}
105+
106+
private Response prepareAccessTrendsResponse(List<AccessTrendDto> trends, String filename, boolean showUserInformation) {
107+
updateAccessTrendsHeader(showUserInformation);
108+
List<String[]> data = trends.stream()
109+
.map(trend -> showUserInformation
110+
? new String[]{trend.getExecutionDate().toString(), trend.getEndpointName(), trend.getUserID()}
111+
: new String[]{trend.getExecutionDate().toString(), trend.getEndpointName()}
112+
)
113+
.collect(Collectors.toList());
114+
return prepareResponse(data, filename, ACCESS_TRENDS_CSV_RESULT_HEADER);
115+
}
116+
117+
private Response prepareResponse(List<String[]> data, String filename, List<String[]> header) {
118+
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
119+
StringWriter sw = new StringWriter();
120+
CSVWriter csvWriter = new CSVWriter(sw, ',', CSVWriter.DEFAULT_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER);
121+
csvWriter.writeAll(header);
122+
csvWriter.writeAll(data);
123+
csvWriter.flush();
124+
baos.write(sw.getBuffer().toString().getBytes());
125+
126+
return Response
127+
.ok(baos)
128+
.type(MediaType.APPLICATION_OCTET_STREAM)
129+
.header("Content-Disposition", String.format("attachment; filename=\"%s\"", filename))
130+
.build();
131+
} catch (Exception ex) {
132+
throw new RuntimeException(ex);
133+
}
134+
}
135+
136+
private void updateExecutionStatisticsHeader(boolean showUserInformation) {
137+
EXECUTION_STATISTICS_CSV_RESULT_HEADER.clear();
138+
if (showUserInformation) {
139+
EXECUTION_STATISTICS_CSV_RESULT_HEADER.add(new String[]{"Date", "Source", "Execution Type", "User ID"});
140+
} else {
141+
EXECUTION_STATISTICS_CSV_RESULT_HEADER.add(new String[]{"Date", "Source", "Execution Type"});
142+
}
143+
}
144+
145+
private void updateAccessTrendsHeader(boolean showUserInformation) {
146+
ACCESS_TRENDS_CSV_RESULT_HEADER.clear();
147+
if (showUserInformation) {
148+
ACCESS_TRENDS_CSV_RESULT_HEADER.add(new String[]{"Date", "Endpoint", "UserID"});
149+
} else {
150+
ACCESS_TRENDS_CSV_RESULT_HEADER.add(new String[]{"Date", "Endpoint"});
151+
}
152+
}
153+
154+
public static final class ExecutionStatisticsRequest {
155+
// Format - yyyy-MM-dd
156+
String startDate;
157+
// Format - yyyy-MM-dd
158+
String endDate;
159+
String sourceKey;
160+
ResponseFormat responseFormat;
161+
boolean showUserInformation;
162+
163+
public String getStartDate() {
164+
return startDate;
165+
}
166+
167+
public void setStartDate(String startDate) {
168+
this.startDate = startDate;
169+
}
170+
171+
public String getEndDate() {
172+
return endDate;
173+
}
174+
175+
public void setEndDate(String endDate) {
176+
this.endDate = endDate;
177+
}
178+
179+
public String getSourceKey() {
180+
return sourceKey;
181+
}
182+
183+
public void setSourceKey(String sourceKey) {
184+
this.sourceKey = sourceKey;
185+
}
186+
187+
public ResponseFormat getResponseFormat() {
188+
return responseFormat;
189+
}
190+
191+
public void setResponseFormat(ResponseFormat responseFormat) {
192+
this.responseFormat = responseFormat;
193+
}
194+
195+
public boolean isShowUserInformation() {
196+
return showUserInformation;
197+
}
198+
199+
public void setShowUserInformation(boolean showUserInformation) {
200+
this.showUserInformation = showUserInformation;
201+
}
202+
}
203+
204+
public static final class AccessTrendsStatisticsRequest {
205+
// Format - yyyy-MM-dd
206+
String startDate;
207+
// Format - yyyy-MM-dd
208+
String endDate;
209+
// Key - method (POST, GET)
210+
// Value - endpoint ("{}" can be used as a placeholder, will be converted to ".*" in regular expression)
211+
List<EndpointDto> endpoints;
212+
ResponseFormat responseFormat;
213+
boolean showUserInformation;
214+
215+
public String getStartDate() {
216+
return startDate;
217+
}
218+
219+
public void setStartDate(String startDate) {
220+
this.startDate = startDate;
221+
}
222+
223+
public String getEndDate() {
224+
return endDate;
225+
}
226+
227+
public void setEndDate(String endDate) {
228+
this.endDate = endDate;
229+
}
230+
231+
public List<EndpointDto> getEndpoints() {
232+
return endpoints;
233+
}
234+
235+
public void setEndpoints(List<EndpointDto> endpoints) {
236+
this.endpoints = endpoints;
237+
}
238+
239+
public ResponseFormat getResponseFormat() {
240+
return responseFormat;
241+
}
242+
243+
public void setResponseFormat(ResponseFormat responseFormat) {
244+
this.responseFormat = responseFormat;
245+
}
246+
247+
public boolean isShowUserInformation() {
248+
return showUserInformation;
249+
}
250+
251+
public void setShowUserInformation(boolean showUserInformation) {
252+
this.showUserInformation = showUserInformation;
253+
}
254+
}
255+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.ohdsi.webapi.statistic.dto;
2+
3+
public class AccessTrendDto {
4+
private String endpointName;
5+
private String executionDate;
6+
private String userID;
7+
8+
public AccessTrendDto(String endpointName, String executionDate, String userID) {
9+
this.endpointName = endpointName;
10+
this.executionDate = executionDate;
11+
this.userID = userID;
12+
}
13+
14+
public String getEndpointName() {
15+
return endpointName;
16+
}
17+
18+
public void setEndpointName(String endpointName) {
19+
this.endpointName = endpointName;
20+
}
21+
22+
public String getExecutionDate() {
23+
return executionDate;
24+
}
25+
26+
public void setExecutionDate(String executionDate) {
27+
this.executionDate = executionDate;
28+
}
29+
30+
public String getUserID() {
31+
return userID;
32+
}
33+
34+
public void setUserID(String userID) {
35+
this.userID = userID;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.ohdsi.webapi.statistic.dto;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class AccessTrendsDto {
7+
private List<AccessTrendDto> trends = new ArrayList<>();
8+
9+
public AccessTrendsDto(List<AccessTrendDto> trends) {
10+
this.trends = trends;
11+
}
12+
13+
public List<AccessTrendDto> getTrends() {
14+
return trends;
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.ohdsi.webapi.statistic.dto;
2+
3+
public class EndpointDto {
4+
String method;
5+
String urlPattern;
6+
String userId;
7+
8+
public String getMethod() {
9+
return method;
10+
}
11+
12+
public void setMethod(String method) {
13+
this.method = method;
14+
}
15+
16+
public String getUrlPattern() {
17+
return urlPattern;
18+
}
19+
20+
public void setUrlPattern(String urlPattern) {
21+
this.urlPattern = urlPattern;
22+
}
23+
24+
public String getUserId() {
25+
return userId;
26+
}
27+
28+
public void setUserId(String userId) {
29+
this.userId = userId;
30+
}
31+
}
32+

0 commit comments

Comments
 (0)