mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-22 03:53:56 +00:00
Merge remote-tracking branch 'origin/master' into foiling
Conflicts: java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
This commit is contained in:
commit
e1f8dc06d5
166 files changed
+6263
-4576
No files matched your search
+18
-8
@@ -62,11 +62,11 @@ public class RaceGroupFactory {
|
||||
return new RaceGroupImpl(name, leaderboard.getDisplayName(), boatClass, courseArea, series, configuration);
|
||||
}
|
||||
|
||||
public Iterable<SeriesWithRows> getSeries(Leaderboard leaderboard) {
|
||||
private Iterable<SeriesWithRows> getSeries(Leaderboard leaderboard) {
|
||||
Map<Series, List<RaceColumn>> seriesToRaceColumns = getSeriesToRaceColumns(leaderboard);
|
||||
Collection<SeriesWithRows> seriesWithRows = new ArrayList<>();
|
||||
for (Series series : getSeriesIterable(leaderboard, seriesToRaceColumns)) {
|
||||
seriesWithRows.add(new SeriesWithRowsImpl(series.getName(), series.isMedal(), getRows(series,
|
||||
seriesWithRows.add(new SeriesWithRowsImpl(series.getName(), series.isMedal(), series.isFleetsCanRunInParallel(), getRows(series,
|
||||
seriesToRaceColumns.get(series))));
|
||||
}
|
||||
return seriesWithRows;
|
||||
@@ -80,6 +80,9 @@ public class RaceGroupFactory {
|
||||
return seriesToRaceColumns.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param raceColumns must be provided in the same order in which they appear in the series / leaderboard
|
||||
*/
|
||||
private Collection<RaceRow> getRows(Series series, List<RaceColumn> raceColumns) {
|
||||
Collection<RaceRow> rows = new ArrayList<>();
|
||||
for (Fleet fleet : series.getFleets()) {
|
||||
@@ -94,16 +97,21 @@ public class RaceGroupFactory {
|
||||
return series.isFirstColumnIsNonDiscardableCarryForward();
|
||||
}
|
||||
|
||||
private Collection<RaceCell> getCells(String fleetName, List<RaceColumn> raceColumns, boolean isFirstRaceColumnVirtual) {
|
||||
/**
|
||||
* Delivers the race cell in the order of the {@link RaceColumn}s provided in {@code raceColumns}.
|
||||
*/
|
||||
private List<RaceCell> getCells(String fleetName, List<RaceColumn> raceColumns, boolean isFirstRaceColumnVirtual) {
|
||||
boolean skippedFirst = false;
|
||||
Collection<RaceCell> cells = new ArrayList<>();
|
||||
List<RaceCell> cells = new ArrayList<>();
|
||||
if (raceColumns != null) {
|
||||
for (RaceColumn raceColumn : raceColumns) {
|
||||
int zeroBasedIndexOfRaceInFleet = 0;
|
||||
for (final RaceColumn raceColumn : raceColumns) {
|
||||
if (isFirstRaceColumnVirtual && !skippedFirst) {
|
||||
skippedFirst = true;
|
||||
} else {
|
||||
Fleet fleet = raceColumn.getFleetByName(fleetName);
|
||||
cells.add(new RaceCellImpl(raceColumn.getName(), raceColumn.getRaceLog(fleet), raceColumn.getFactor(), raceColumn.getExplicitFactor()));
|
||||
cells.add(new RaceCellImpl(raceColumn.getName(), raceColumn.getRaceLog(fleet),
|
||||
raceColumn.getFactor(), raceColumn.getExplicitFactor(), zeroBasedIndexOfRaceInFleet++));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +120,9 @@ public class RaceGroupFactory {
|
||||
|
||||
/**
|
||||
* Returns a series to race column mapping. If there are no series all race columns will
|
||||
* be mapped from a default series.
|
||||
* be mapped from a default series. The race column lists that appear as values in the result
|
||||
* maintain the order in which the race column objects appear in the original {@link Series}
|
||||
* or leaderboard.
|
||||
*/
|
||||
private Map<Series, List<RaceColumn>> getSeriesToRaceColumns(Leaderboard leaderboard) {
|
||||
Map<Series, List<RaceColumn>> seriesToRaceColumns = new HashMap<>();
|
||||
@@ -135,7 +145,7 @@ public class RaceGroupFactory {
|
||||
|
||||
private Series createDefaultSeries(Iterable<? extends Fleet> fleets) {
|
||||
Series defaultSeries;
|
||||
defaultSeries = new SeriesImpl(LeaderboardNameConstants.DEFAULT_SERIES_NAME, false,
|
||||
defaultSeries = new SeriesImpl(LeaderboardNameConstants.DEFAULT_SERIES_NAME, false, true,
|
||||
fleets, Collections.<String> emptyList(), null);
|
||||
return defaultSeries;
|
||||
}
|
||||
|
||||
+2
-2
@@ -80,7 +80,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
} else {
|
||||
String jsonString = getCompetitorJSON(competitor).toJSONString();
|
||||
response = Response.ok(jsonString, MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
|
||||
JSONObject teamJson = teamJsonSerializer.serialize(team);
|
||||
String json = teamJson.toJSONString();
|
||||
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+356
-325
@@ -1,325 +1,356 @@
|
||||
package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.RestServletContainer;
|
||||
import com.sap.sailing.server.gateway.serialization.NotJsonSerializableException;
|
||||
import com.sap.sse.datamining.DataMiningServer;
|
||||
import com.sap.sse.datamining.Query;
|
||||
import com.sap.sse.datamining.StatisticQueryDefinition;
|
||||
import com.sap.sse.datamining.data.QueryResult;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.CompoundGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.datamining.shared.impl.UUIDDataMiningSession;
|
||||
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
|
||||
|
||||
/**
|
||||
* REST-API to run predefined queries and get the result as JSON.
|
||||
* @author Lennart Hensler (D054527)
|
||||
*/
|
||||
@Path("/v1/datamining")
|
||||
public class DataMiningResource extends AbstractSailingServerResource {
|
||||
|
||||
private static final String AVG_SPEED_PER_COMPETITOR_LEG_TYPE = "AvgSpeed_Per_Competitor-LegType";
|
||||
private static final String SUM_DISTANCE_PER_COMPETITOR_LEG_TYPE = "SumDistance_Per_Competitor-LegType";
|
||||
private static final String SUM_MANEUVERS_PER_COMPETITOR = "SumManeuvers_Per_Competitor";
|
||||
|
||||
private static final Function<Distance, Number> distanceMetersExtractor = (distance) -> distance.getMeters();
|
||||
|
||||
public DataMiningServer getDataMiningServer() {
|
||||
@SuppressWarnings("unchecked")
|
||||
ServiceTracker<DataMiningServer, DataMiningServer> dataMiningServerTracker = (ServiceTracker<DataMiningServer, DataMiningServer>) getServletContext().getAttribute(RestServletContainer.DATA_MINING_SERVER_TRACKER_NAME);
|
||||
return dataMiningServerTracker.getService();
|
||||
}
|
||||
|
||||
private Response getBadIdentifierErrorResponse(String identifier) {
|
||||
return Response.status(Status.NOT_FOUND).entity("Couldn't find a predefined query with the identifier '" + identifier + "'.")
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getBadQueryDefinitionErrorResponse(ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO) {
|
||||
return Response.status(Status.BAD_REQUEST).entity("Couldn't create a query for definition '" + StringEscapeUtils.escapeHtml(queryDefinitionDTO.toString()) + "'.")
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getNoDataFoundErrorResponse() {
|
||||
return Response.status(Status.NOT_FOUND).entity("No data found.").type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getNotSerializableErrorResponse(Class<?> type) {
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Can't serialize values of type '" + type.getName() + "'.").
|
||||
type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
// @GET
|
||||
// @Produces("application/json;charset=UTF-8")
|
||||
// public Response getPredefinedQueries() {
|
||||
// return predefinedQueryIdentifiersToJSON(getDataMiningServer().getPredefinedQueryIdentifiers());
|
||||
// }
|
||||
|
||||
public Response predefinedQueryIdentifiersToJSON(Iterable<PredefinedQueryIdentifier> identifiers) {
|
||||
JSONArray predefinedQueryNames = new JSONArray();
|
||||
for (PredefinedQueryIdentifier identifier : identifiers) {
|
||||
JSONObject jsonId = new JSONObject();
|
||||
jsonId.put("Identifier", identifier.getIdentifier());
|
||||
jsonId.put("Description", identifier.getDescription());
|
||||
predefinedQueryNames.add(jsonId);
|
||||
}
|
||||
|
||||
String json = predefinedQueryNames.toJSONString();
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
|
||||
// @GET
|
||||
// @Produces("application/json;charset=UTF-8")
|
||||
// @Path("{identifier}")
|
||||
// public Response runPredefinedQuery(@PathParam("identifier") String identifier) {
|
||||
// Response response;
|
||||
// ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(identifier);
|
||||
// if (queryDefinitionDTO == null) {
|
||||
// response = getBadIdentifierErrorResponse(identifier);
|
||||
// } else {
|
||||
// response = runQuery(queryDefinitionDTO);
|
||||
// }
|
||||
// return response;
|
||||
// }
|
||||
|
||||
public Response avgSpeedPerCompetitorAndLegType(String regattaName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(AVG_SPEED_PER_COMPETITOR_LEG_TYPE);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(AVG_SPEED_PER_COMPETITOR_LEG_TYPE);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, null, null, "kn", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response avgSpeedPerCompetitorAndLegType(String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(AVG_SPEED_PER_COMPETITOR_LEG_TYPE);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(AVG_SPEED_PER_COMPETITOR_LEG_TYPE);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, null, "kn", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumDistancePerCompetitorAndLegType(String regattaName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(SUM_DISTANCE_PER_COMPETITOR_LEG_TYPE);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(SUM_DISTANCE_PER_COMPETITOR_LEG_TYPE);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, null, distanceMetersExtractor, "m", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumDistancePerCompetitorAndLegType(String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(SUM_DISTANCE_PER_COMPETITOR_LEG_TYPE);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(SUM_DISTANCE_PER_COMPETITOR_LEG_TYPE);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, distanceMetersExtractor, "m", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumManeuversPerCompetitor(String regattaName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(SUM_MANEUVERS_PER_COMPETITOR);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(SUM_MANEUVERS_PER_COMPETITOR);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, null, null, null, 0);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumManeuversPerCompetitor(String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(SUM_MANEUVERS_PER_COMPETITOR);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(SUM_MANEUVERS_PER_COMPETITOR);
|
||||
} else {
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, null, null, 0);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private ModifiableStatisticQueryDefinitionDTO getPredefinedQuery(String identifier) {
|
||||
DataMiningServer dataMiningServer = getDataMiningServer();
|
||||
PredefinedQueryIdentifier queryIdentifier = new PredefinedQueryIdentifier(identifier, "");
|
||||
return dataMiningServer.getPredefinedQueryDefinitionDTO(queryIdentifier);
|
||||
}
|
||||
|
||||
private <ResultType> Response runQuery(ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO, String regattaName, String raceName,
|
||||
Function<ResultType, Number> numberExtractor, String resultUnit, int resultPlaces) {
|
||||
Response response;
|
||||
DataMiningServer dataMiningServer = getDataMiningServer();
|
||||
|
||||
StatisticQueryDefinition<?, ?, ?, ?> queryDefinition = dataMiningServer.getQueryDefinitionForDTO(queryDefinitionDTO);
|
||||
Query<?> query = queryDefinition == null ? null : dataMiningServer.createQuery(queryDefinition);
|
||||
if (query == null) {
|
||||
response = getBadQueryDefinitionErrorResponse(queryDefinitionDTO);
|
||||
} else {
|
||||
DataMiningSession session = new UUIDDataMiningSession(UUID.randomUUID());
|
||||
long requestTimepoint = System.currentTimeMillis();
|
||||
@SuppressWarnings("unchecked")
|
||||
QueryResult<ResultType> result = (QueryResult<ResultType>) dataMiningServer.runNewQueryAndAbortPreviousQueries(session, query);
|
||||
|
||||
if (result == null || result.isEmpty()) {
|
||||
response = getNoDataFoundErrorResponse();
|
||||
} else {
|
||||
try {
|
||||
JSONObject jsonResult = new JSONObject();
|
||||
jsonResult.put("state", result.getState());
|
||||
jsonResult.put("requestTimepoint", requestTimepoint);
|
||||
jsonResult.put("calculationDuration-s", roundDouble(result.getCalculationTimeInSeconds(), 2));
|
||||
jsonResult.put("description", result.getResultSignifier());
|
||||
if (regattaName != null && !regattaName.isEmpty()) {
|
||||
jsonResult.put("regatta", regattaName);
|
||||
}
|
||||
if (raceName != null && !raceName.isEmpty()) {
|
||||
jsonResult.put("race", raceName);
|
||||
}
|
||||
jsonResult.put("resultUnit", resultUnit != null && !resultUnit.isEmpty() ? resultUnit : "None");
|
||||
jsonResult.put("results", resultValuesToJSON(result, numberExtractor, resultPlaces));
|
||||
response = Response.ok(jsonResult.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
} catch (NotJsonSerializableException e) {
|
||||
response = getNotSerializableErrorResponse(e.getNotSerializableClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private <ResultType> JSONArray resultValuesToJSON(QueryResult<ResultType> result, Function<ResultType, Number> numberExtractor,
|
||||
int places) throws NotJsonSerializableException {
|
||||
if (!Number.class.isAssignableFrom(result.getResultType()) && numberExtractor == null) {
|
||||
throw new NotJsonSerializableException(result.getResultType());
|
||||
}
|
||||
|
||||
// TODO see Bug 3334
|
||||
Map<GroupKey, ResultType> values = result.getResults();
|
||||
JSONArray jsonResultValues = new JSONArray();
|
||||
for (GroupKey groupKey : values.keySet()) {
|
||||
JSONObject jsonResultEntry = new JSONObject();
|
||||
jsonResultEntry.put("groupKey", groupKeyToJSON(groupKey));
|
||||
Number value = numberExtractor != null ? numberExtractor.apply(values.get(groupKey)) : (Number) values.get(groupKey);
|
||||
jsonResultEntry.put("value", roundDouble(value.doubleValue(), places));
|
||||
jsonResultValues.add(jsonResultEntry);
|
||||
}
|
||||
return jsonResultValues;
|
||||
}
|
||||
|
||||
private JSONArray groupKeyToJSON(GroupKey groupKey) throws NotJsonSerializableException {
|
||||
// TODO Convert the concrete key values and not just the string represantation
|
||||
JSONArray jsonResultEntryGroupKeys = new JSONArray();
|
||||
if (groupKey instanceof GenericGroupKey<?>) {
|
||||
jsonResultEntryGroupKeys.add(simpleGroupKeyToJSON(groupKey));
|
||||
} else if (groupKey instanceof CompoundGroupKey) {
|
||||
for (GroupKey key : groupKey.getKeys()) {
|
||||
jsonResultEntryGroupKeys.add(groupKeyToJSON(key));
|
||||
}
|
||||
} else {
|
||||
throw new NotJsonSerializableException(groupKey.getClass());
|
||||
}
|
||||
return jsonResultEntryGroupKeys;
|
||||
}
|
||||
|
||||
private Object simpleGroupKeyToJSON(GroupKey groupKey) {
|
||||
return groupKey.asString();
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sailing.datamining.SailingPredefinedQueries;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.RestServletContainer;
|
||||
import com.sap.sailing.server.gateway.serialization.NotJsonSerializableException;
|
||||
import com.sap.sse.datamining.DataMiningServer;
|
||||
import com.sap.sse.datamining.Query;
|
||||
import com.sap.sse.datamining.StatisticQueryDefinition;
|
||||
import com.sap.sse.datamining.data.QueryResult;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.CompoundGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.datamining.shared.impl.UUIDDataMiningSession;
|
||||
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
|
||||
|
||||
/**
|
||||
* REST-API to run predefined queries and get the result as JSON.
|
||||
* @author Lennart Hensler (D054527)
|
||||
*/
|
||||
@Path("/v1/datamining")
|
||||
public class DataMiningResource extends AbstractSailingServerResource {
|
||||
|
||||
private SailingPredefinedQueries predefinedDataMiningQueries;
|
||||
|
||||
private static final Function<Distance, Number> distanceMetersExtractor = (distance) -> distance.getMeters();
|
||||
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_REGATTA_RACE = "AvgSpeed_Per_Regatta-Race";
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE = "AvgSpeed_Per_Competitor-LegType";
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_COMPETITOR = "AvgSpeed_Per_Competitor";
|
||||
public final static String QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE = "DistanceTraveled_Per_Competitor-LegType";
|
||||
public final static String QUERY_DISTANCE_TRAVELED_PER_COMPETITOR = "DistanceTraveled_Per_Competitor";
|
||||
public final static String QUERY_MANEUVERS_PER_COMPETITOR = "Maneuvers_Per_Competitor";
|
||||
|
||||
public List<PredefinedQueryIdentifier> getPredefinedRegattaDataMiningQueries() {
|
||||
return getPredefinedQueriesByNames(
|
||||
QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE,
|
||||
QUERY_AVERAGE_SPEED_PER_COMPETITOR,
|
||||
QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE,
|
||||
QUERY_DISTANCE_TRAVELED_PER_COMPETITOR,
|
||||
QUERY_MANEUVERS_PER_COMPETITOR);
|
||||
}
|
||||
|
||||
public List<PredefinedQueryIdentifier> getPredefinedRaceDataMiningQueries() {
|
||||
return getPredefinedQueriesByNames(
|
||||
QUERY_AVERAGE_SPEED_PER_REGATTA_RACE,
|
||||
QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE,
|
||||
QUERY_AVERAGE_SPEED_PER_COMPETITOR,
|
||||
QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE,
|
||||
QUERY_DISTANCE_TRAVELED_PER_COMPETITOR,
|
||||
QUERY_MANEUVERS_PER_COMPETITOR);
|
||||
}
|
||||
|
||||
public List<PredefinedQueryIdentifier> getPredefinedQueriesByNames(String... names) {
|
||||
List<PredefinedQueryIdentifier> result = new ArrayList<>();
|
||||
SailingPredefinedQueries predefinedMiningQueries = getPredefinedMiningQueries();
|
||||
for(PredefinedQueryIdentifier id: predefinedMiningQueries.getQueries().keySet()) {
|
||||
for(String name: names) {
|
||||
if(id.getIdentifier().equals(name)) {
|
||||
result.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public DataMiningServer getDataMiningServer() {
|
||||
@SuppressWarnings("unchecked")
|
||||
ServiceTracker<DataMiningServer, DataMiningServer> dataMiningServerTracker = (ServiceTracker<DataMiningServer, DataMiningServer>) getServletContext().getAttribute(RestServletContainer.DATA_MINING_SERVER_TRACKER_NAME);
|
||||
return dataMiningServerTracker.getService();
|
||||
}
|
||||
|
||||
private Response getBadIdentifierErrorResponse(String identifier) {
|
||||
return Response.status(Status.NOT_FOUND).entity("Couldn't find a predefined query with the identifier '" + identifier + "'.")
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getBadQueryDefinitionErrorResponse(ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO) {
|
||||
return Response.status(Status.BAD_REQUEST).entity("Couldn't create a query for definition '" + StringEscapeUtils.escapeHtml(queryDefinitionDTO.toString()) + "'.")
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getNoDataFoundErrorResponse() {
|
||||
return Response.status(Status.NOT_FOUND).entity("No data found.").type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private Response getNotSerializableErrorResponse(Class<?> type) {
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Can't serialize values of type '" + type.getName() + "'.").
|
||||
type(MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
private SailingPredefinedQueries getPredefinedMiningQueries() {
|
||||
if (predefinedDataMiningQueries == null) {
|
||||
predefinedDataMiningQueries = new SailingPredefinedQueries();
|
||||
}
|
||||
return predefinedDataMiningQueries;
|
||||
}
|
||||
|
||||
public Response predefinedQueryIdentifiersToJSON(Iterable<PredefinedQueryIdentifier> identifiers) {
|
||||
JSONArray predefinedQueryNames = new JSONArray();
|
||||
for (PredefinedQueryIdentifier identifier : identifiers) {
|
||||
JSONObject jsonId = new JSONObject();
|
||||
jsonId.put("Identifier", identifier.getIdentifier());
|
||||
jsonId.put("Description", identifier.getDescription());
|
||||
predefinedQueryNames.add(jsonId);
|
||||
}
|
||||
|
||||
String json = predefinedQueryNames.toJSONString();
|
||||
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
public Response avgSpeedPerCompetitorAndLegType(String regattaName) {
|
||||
return avgSpeedPerCompetitorQuery(SailingPredefinedQueries.QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE, regattaName);
|
||||
}
|
||||
|
||||
public Response avgSpeedPerCompetitor(String regattaName) {
|
||||
return avgSpeedPerCompetitorQuery(SailingPredefinedQueries.QUERY_AVERAGE_SPEED_PER_COMPETITOR, regattaName);
|
||||
}
|
||||
|
||||
public Response avgSpeedPerCompetitorAndLegType(String regattaName, String raceName) {
|
||||
return avgSpeedPerCompetitorQuery(SailingPredefinedQueries.QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE, regattaName, raceName);
|
||||
}
|
||||
|
||||
public Response avgSpeedPerCompetitor(String regattaName, String raceName) {
|
||||
return avgSpeedPerCompetitorQuery(SailingPredefinedQueries.QUERY_AVERAGE_SPEED_PER_COMPETITOR, regattaName, raceName);
|
||||
}
|
||||
|
||||
private Response avgSpeedPerCompetitorQuery(String predefinedQueriesName, String regattaName) {
|
||||
return avgSpeedPerCompetitorQuery(predefinedQueriesName, regattaName, null);
|
||||
}
|
||||
|
||||
private Response avgSpeedPerCompetitorQuery(String predefinedQueriesName, String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(predefinedQueriesName);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(predefinedQueriesName);
|
||||
} else {
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
|
||||
if(raceName != null) {
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
}
|
||||
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, null, "kn", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumDistanceTraveledPerCompetitor(String regattaName) {
|
||||
return sumDistanceTraveledPerCompetitorQuery(SailingPredefinedQueries.QUERY_DISTANCE_TRAVELED_PER_COMPETITOR, regattaName);
|
||||
}
|
||||
|
||||
public Response sumDistanceTraveledPerCompetitorAndLegType(String regattaName) {
|
||||
return sumDistanceTraveledPerCompetitorQuery(SailingPredefinedQueries.QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE, regattaName);
|
||||
}
|
||||
|
||||
public Response sumDistanceTraveledPerCompetitor(String regattaName, String raceName) {
|
||||
return sumDistanceTraveledPerCompetitorQuery(SailingPredefinedQueries.QUERY_DISTANCE_TRAVELED_PER_COMPETITOR, regattaName, raceName);
|
||||
}
|
||||
|
||||
public Response sumDistanceTraveledPerCompetitorAndLegType(String regattaName, String raceName) {
|
||||
return sumDistanceTraveledPerCompetitorQuery(SailingPredefinedQueries.QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE, regattaName, raceName);
|
||||
}
|
||||
|
||||
private Response sumDistanceTraveledPerCompetitorQuery(String predefinedQueriesName, String regattaName) {
|
||||
return sumDistanceTraveledPerCompetitorQuery(predefinedQueriesName, regattaName, null);
|
||||
}
|
||||
|
||||
private Response sumDistanceTraveledPerCompetitorQuery(String predefinedQueriesName, String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(predefinedQueriesName);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(predefinedQueriesName);
|
||||
} else {
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
|
||||
if(raceName != null) {
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
}
|
||||
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, distanceMetersExtractor, "m", 2);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Response sumManeuversPerCompetitor(String regattaName) {
|
||||
return sumManeuversPerCompetitorQuery(SailingPredefinedQueries.QUERY_MANEUVERS_PER_COMPETITOR, regattaName);
|
||||
}
|
||||
|
||||
public Response sumManeuversPerCompetitor(String regattaName, String raceName) {
|
||||
return sumManeuversPerCompetitorQuery(SailingPredefinedQueries.QUERY_MANEUVERS_PER_COMPETITOR, regattaName, raceName);
|
||||
}
|
||||
|
||||
private Response sumManeuversPerCompetitorQuery(String predefinedQueriesName, String regattaName) {
|
||||
return sumManeuversPerCompetitorQuery(predefinedQueriesName, regattaName, null);
|
||||
}
|
||||
|
||||
private Response sumManeuversPerCompetitorQuery(String predefinedQueriesName, String regattaName, String raceName) {
|
||||
Response response;
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO = getPredefinedQuery(predefinedQueriesName);
|
||||
|
||||
if (queryDefinitionDTO == null) {
|
||||
response = getBadIdentifierErrorResponse(predefinedQueriesName);
|
||||
} else {
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> race_FilterSelection = new HashMap<>();
|
||||
|
||||
FunctionDTO getRegattaName = new FunctionDTO(true, "getRegatta().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRegattaName_FilterSelection = new HashSet<>();
|
||||
getRegattaName_FilterSelection.add(regattaName);
|
||||
race_FilterSelection.put(getRegattaName, getRegattaName_FilterSelection);
|
||||
|
||||
if (raceName != null) {
|
||||
FunctionDTO getRaceName = new FunctionDTO(true, "getRace().getName()", HasTrackedRaceContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> getRaceName_FilterSelection = new HashSet<>();
|
||||
getRaceName_FilterSelection.add(raceName);
|
||||
race_FilterSelection.put(getRaceName, getRaceName_FilterSelection);
|
||||
}
|
||||
|
||||
queryDefinitionDTO.setFilterSelectionFor(queryDefinitionDTO.getDataRetrieverChainDefinition().getRetrieverLevel(2), race_FilterSelection);
|
||||
response = runQuery(queryDefinitionDTO, regattaName, raceName, null, null, 0);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private ModifiableStatisticQueryDefinitionDTO getPredefinedQuery(String identifier) {
|
||||
DataMiningServer dataMiningServer = getDataMiningServer();
|
||||
PredefinedQueryIdentifier queryIdentifier = new PredefinedQueryIdentifier(identifier, "");
|
||||
return dataMiningServer.getPredefinedQueryDefinitionDTO(queryIdentifier);
|
||||
}
|
||||
|
||||
private <ResultType> Response runQuery(ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO, String regattaName, String raceName,
|
||||
Function<ResultType, Number> numberExtractor, String resultUnit, int resultPlaces) {
|
||||
Response response;
|
||||
DataMiningServer dataMiningServer = getDataMiningServer();
|
||||
|
||||
StatisticQueryDefinition<?, ?, ?, ?> queryDefinition = dataMiningServer.getQueryDefinitionForDTO(queryDefinitionDTO);
|
||||
Query<?> query = queryDefinition == null ? null : dataMiningServer.createQuery(queryDefinition);
|
||||
if (query == null) {
|
||||
response = getBadQueryDefinitionErrorResponse(queryDefinitionDTO);
|
||||
} else {
|
||||
DataMiningSession session = new UUIDDataMiningSession(UUID.randomUUID());
|
||||
long requestTimepoint = System.currentTimeMillis();
|
||||
@SuppressWarnings("unchecked")
|
||||
QueryResult<ResultType> result = (QueryResult<ResultType>) dataMiningServer.runNewQueryAndAbortPreviousQueries(session, query);
|
||||
|
||||
if (result == null || result.isEmpty()) {
|
||||
response = getNoDataFoundErrorResponse();
|
||||
} else {
|
||||
try {
|
||||
JSONObject jsonResult = new JSONObject();
|
||||
jsonResult.put("state", result.getState());
|
||||
jsonResult.put("requestTimepoint", requestTimepoint);
|
||||
jsonResult.put("calculationDuration-s", roundDouble(result.getCalculationTimeInSeconds(), 2));
|
||||
jsonResult.put("description", result.getResultSignifier());
|
||||
if (regattaName != null && !regattaName.isEmpty()) {
|
||||
jsonResult.put("regatta", regattaName);
|
||||
}
|
||||
if (raceName != null && !raceName.isEmpty()) {
|
||||
jsonResult.put("race", raceName);
|
||||
}
|
||||
jsonResult.put("resultUnit", resultUnit != null && !resultUnit.isEmpty() ? resultUnit : "None");
|
||||
jsonResult.put("results", resultValuesToJSON(result, numberExtractor, resultPlaces));
|
||||
response = Response.ok(jsonResult.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
} catch (NotJsonSerializableException e) {
|
||||
response = getNotSerializableErrorResponse(e.getNotSerializableClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private <ResultType> JSONArray resultValuesToJSON(QueryResult<ResultType> result, Function<ResultType, Number> numberExtractor,
|
||||
int places) throws NotJsonSerializableException {
|
||||
if (!Number.class.isAssignableFrom(result.getResultType()) && numberExtractor == null) {
|
||||
throw new NotJsonSerializableException(result.getResultType());
|
||||
}
|
||||
|
||||
// TODO see Bug 3334
|
||||
Map<GroupKey, ResultType> values = result.getResults();
|
||||
JSONArray jsonResultValues = new JSONArray();
|
||||
for (GroupKey groupKey : values.keySet()) {
|
||||
JSONObject jsonResultEntry = new JSONObject();
|
||||
jsonResultEntry.put("groupKey", groupKeyToJSON(groupKey));
|
||||
Number value = numberExtractor != null ? numberExtractor.apply(values.get(groupKey)) : (Number) values.get(groupKey);
|
||||
jsonResultEntry.put("value", roundDouble(value.doubleValue(), places));
|
||||
jsonResultValues.add(jsonResultEntry);
|
||||
}
|
||||
return jsonResultValues;
|
||||
}
|
||||
|
||||
private JSONArray groupKeyToJSON(GroupKey groupKey) throws NotJsonSerializableException {
|
||||
// TODO Convert the concrete key values and not just the string representation
|
||||
JSONArray jsonResultEntryGroupKeys = new JSONArray();
|
||||
if (groupKey instanceof GenericGroupKey<?>) {
|
||||
jsonResultEntryGroupKeys.add(simpleGroupKeyToJSON(groupKey));
|
||||
} else if (groupKey instanceof CompoundGroupKey) {
|
||||
for (GroupKey key : groupKey.getKeys()) {
|
||||
jsonResultEntryGroupKeys.add(groupKeyToJSON(key));
|
||||
}
|
||||
} else {
|
||||
throw new NotJsonSerializableException(groupKey.getClass());
|
||||
}
|
||||
return jsonResultEntryGroupKeys;
|
||||
}
|
||||
|
||||
private Object simpleGroupKeyToJSON(GroupKey groupKey) {
|
||||
return groupKey.asString();
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -46,7 +46,7 @@ public class EventsResource extends AbstractSailingServerResource {
|
||||
}
|
||||
}
|
||||
String json = result.toJSONString();
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -71,7 +71,7 @@ public class EventsResource extends AbstractSailingServerResource {
|
||||
JSONObject eventJson = eventSerializer.serialize(event);
|
||||
|
||||
String json = eventJson.toJSONString();
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class EventsResource extends AbstractSailingServerResource {
|
||||
filterByLeaderboard, filterByDayOffset, getService());
|
||||
JSONObject raceStatesJson = eventRaceStatesSerializer.serialize(new Pair<Event, Iterable<Leaderboard>>(event, getService().getLeaderboards().values()));
|
||||
String json = raceStatesJson.toJSONString();
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
@@ -65,7 +66,7 @@ public class FileStorageResource extends AbstractSailingServerResource {
|
||||
getService().getFileStorageManagementService().getActiveFileStorageService()
|
||||
.removeFile(new URI(uri));
|
||||
result.put("status", Status.OK.name());
|
||||
response = Response.ok().entity(result.toJSONString()).build();
|
||||
response = Response.ok().entity(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
} catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException
|
||||
| URISyntaxException | IOException e) {
|
||||
final String errorMessage = "Could not delete file with URI "+uri+": "+e.getMessage();
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource {
|
||||
|
||||
// header option is set to allow communication between two sapsailing servers, especially for
|
||||
// the master data import functionality
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", "*").build();
|
||||
return Response.ok(json).header("Access-Control-Allow-Origin", "*").header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -154,7 +154,7 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource {
|
||||
}
|
||||
}
|
||||
String json = jsonLeaderboardGroup.toJSONString();
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
+6
-6
@@ -104,7 +104,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
jsonLeaderboards.add(leaderboardName);
|
||||
}
|
||||
String json = jsonLeaderboards.toJSONString();
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -138,7 +138,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
jsonLeaderboard.writeJSONString(sw);
|
||||
|
||||
String json = sw.getBuffer().toString();
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
} catch (NoWindException | InterruptedException | ExecutionException | IOException e) {
|
||||
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage())
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
@@ -509,7 +509,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
} else {
|
||||
JSONObject json = CompetitorsResource.getCompetitorJSON(competitor);
|
||||
json.put("displayName", leaderboard.getDisplayName(competitor));
|
||||
response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -580,7 +580,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
}
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("marks", array);
|
||||
return Response.ok(result.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
|
||||
private final MarkJsonSerializer markSerializer = new MarkJsonSerializer();
|
||||
@@ -671,7 +671,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
.type(MediaType.TEXT_PLAIN).build();
|
||||
} else {
|
||||
final JSONObject json = getJsonForColumnFactors(leaderboard, raceColumns);
|
||||
response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
@@ -725,7 +725,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
} else {
|
||||
raceColumn.setFactor(explicitFactor);
|
||||
final JSONObject json = getJsonForColumnFactors(leaderboard, Collections.singleton(raceColumn));
|
||||
response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
|
||||
@@ -12,6 +13,6 @@ public class PingResource extends AbstractSailingServerResource {
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response ping() {
|
||||
return Response.ok().build();
|
||||
return Response.ok().header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -170,7 +170,7 @@ public class PolarResource extends AbstractSailingServerResource {
|
||||
} finally {
|
||||
maneuverBasedWindEstimationTrackImpl.unlockAfterRead();
|
||||
}
|
||||
response = Response.ok(resultAsJson.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
response = Response.ok(resultAsJson.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
||||
+1235
-1169
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -43,6 +43,6 @@ public class SearchResource extends AbstractSailingServerResource {
|
||||
for (LeaderboardSearchResult searchResult : searchResults) {
|
||||
jsonSearchResults.add(serializer.serialize(searchResult));
|
||||
}
|
||||
return Response.ok(jsonSearchResults.toJSONString(), MediaType.APPLICATION_JSON).build();
|
||||
return Response.ok(jsonSearchResults.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user