Merge branch 'master' into tracapi

This commit is contained in:
Axel Uhl committed 2014-06-05 00:42:27 +02:00
commit 7111ff7921
20 files changed
+523 -64

No files matched your search

@@ -0,0 +1,11 @@
package com.sap.sailing.domain.base;
import com.sap.sse.common.Named;
public interface LeaderboardBase extends Named {
/**
* If a display name for the leaderboard has been defined,
* this method returns it; otherwise, <code>null</code> is returned.
*/
String getDisplayName();
}
@@ -0,0 +1,38 @@
package com.sap.sailing.domain.base;
import com.sap.sse.common.search.Hit;
/**
* A generalization of <code>LeaderboardSearchResult</code> which has references to full-blown leaderboards, a regatta,
* full leaderboard groups and the entire event; this form requires only the respective <code>...Base</code> flavors of
* events, leaderboards and leaderboard groups which allows for the creation of a copy in a server that has been
* receiving a search result from some other (remote) server, e.g., through JSON deserialization.
*
* @author Axel Uhl (D043530)
*
*/
public interface LeaderboardSearchResultBase extends Hit {
/**
* The leaderboard that matches the search query.
*/
LeaderboardBase getLeaderboard();
String getRegattaName();
String getBoatClassName();
/**
* If the leaderboard is part of one or more leaderboard groups, the leaderboard groups; an empty but
* valid (non-<code>null</code>) collection otherwise.
*/
Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups();
/**
* If there is a connection between an {@link EventBase} and the {@link #getLeaderboard() leaderboard}, e.g.,
* because the {@link EventBase} has a {@link EventBase#getLeaderboardGroups() leaderboard group} that is part of
* {@link #getLeaderboardGroups()} or the event has a course area attached to its {@link EventBase#getVenue() venue}
* that is referenced by the leaderboard as its {@link Leaderboard#getDefaultCourseArea() default course area}, the
* event is returned; <code>null</code> otherwise.
*/
EventBase getEvent();
}
@@ -0,0 +1,42 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
/**
* This is what you get when you search a <code>RacingEventService</code> with its <code>search(...)</code> method. It
* delivers the "real things," meaning that the leaderboards and events etc. are those objects currently living in the
* server instance. This is richer than the de-serialized {@link LeaderboardSearchResultBase} objects you get when
* fetching search results from remote instances, such as those described by a {@link RemoteSailingServerReference}.
* However, for putting them into a DTO to transfer them to a web client, both are fine.
*
* @author Axel Uhl (D043530)
*
*/
public interface LeaderboardSearchResult extends LeaderboardSearchResultBase {
/**
* The leaderboard that matches the search query.
*/
Leaderboard getLeaderboard();
/**
* Returns the {@link RegattaLeaderboard#getRegatta() regatta leaderboard's regatta} if the
* {@link #getLeaderboard() leaderboard} is a regatta leaderboard, or <code>null</code> otherwise.
*/
Regatta getRegatta();
/**
* If the leaderboard is part of one or more leaderboard groups, the leaderboard groups; an empty but
* valid (non-<code>null</code>) collection otherwise.
*/
Iterable<LeaderboardGroup> getLeaderboardGroups();
/**
* If there is a connection between an {@link Event} and the {@link #getLeaderboard() leaderboard}, e.g., because
* the {@link Event} has a {@link Event#getLeaderboardGroups() leaderboard group} that is part of {@link #getLeaderboardGroups()} or
* the event has a course area attached to its {@link Event#getVenue() venue} that is referenced by the leaderboard as
* its {@link Leaderboard#getDefaultCourseArea() default course area}, the event is returned; <code>null</code> otherwise.
*/
Event getEvent();
}
@@ -0,0 +1,26 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.LeaderboardBase;
public class LeaderboardBaseImpl implements LeaderboardBase {
private static final long serialVersionUID = -5332972141344617372L;
private final String name;
private final String displayName;
public LeaderboardBaseImpl(String name, String displayName) {
super();
this.name = name;
this.displayName = displayName;
}
@Override
public String getName() {
return name;
}
@Override
public String getDisplayName() {
return displayName;
}
}
@@ -0,0 +1,60 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.LeaderboardBase;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
import com.sap.sailing.domain.leaderboard.Leaderboard;
/**
* The simplified version of a {@link LeaderboardSearchResult}, after JSON deserialization on a remote server. In particular,
* the {@link Leaderboard} object is most certainly not available on the receiving end. {@link EventBase} and {@link LeaderboardGroupBase}
* objects are
*
* @author Axel Uhl (D043530)
*
*/
public class LeaderboardSearchResultBaseImpl implements LeaderboardSearchResultBase {
private final LeaderboardBase leaderboard;
private final String regattaName;
private final Iterable<? extends LeaderboardGroupBase> leaderboardGroups;
private final EventBase event;
private final String boatClassName;
public LeaderboardSearchResultBaseImpl(LeaderboardBase leaderboard, String regattaName,
String boatClassName, Iterable<? extends LeaderboardGroupBase> leaderboardGroups, EventBase event) {
super();
this.leaderboard = leaderboard;
this.regattaName = regattaName;
this.boatClassName = boatClassName;
this.leaderboardGroups = leaderboardGroups;
this.event = event;
}
@Override
public LeaderboardBase getLeaderboard() {
return leaderboard;
}
@Override
public String getRegattaName() {
return regattaName;
}
@Override
public String getBoatClassName() {
return boatClassName;
}
@Override
public Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups() {
return leaderboardGroups;
}
@Override
public EventBase getEvent() {
return event;
}
}
@@ -0,0 +1,83 @@
package com.sap.sailing.domain.base.impl;
import java.util.Collections;
import java.util.Set;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.tracking.TrackedRace;
public class LeaderboardSearchResultImpl implements LeaderboardSearchResult {
private final Leaderboard leaderboard;
private final Event event;
private final Set<LeaderboardGroup> leaderboardGroups;
public LeaderboardSearchResultImpl(Leaderboard leaderboard, Event event, Set<LeaderboardGroup> leaderboardGroups) {
this.leaderboard = leaderboard;
if (leaderboardGroups == null) {
this.leaderboardGroups = Collections.emptySet();
} else {
this.leaderboardGroups = leaderboardGroups;
}
this.event = event;
}
@Override
public Regatta getRegatta() {
final Regatta regatta;
if (leaderboard instanceof RegattaLeaderboard) {
regatta = ((RegattaLeaderboard) leaderboard).getRegatta();
} else {
regatta = null;
}
return regatta;
}
@Override
public String getRegattaName() {
return getRegatta() != null ? getRegatta().getName() : null;
}
@Override
public Leaderboard getLeaderboard() {
return leaderboard;
}
@Override
public Event getEvent() {
return event;
}
@Override
public Iterable<LeaderboardGroup> getLeaderboardGroups() {
return leaderboardGroups;
}
@Override
public String getBoatClassName() {
BoatClass boatClass = getBoatClass();
return boatClass == null ? null : boatClass.getName();
}
public BoatClass getBoatClass() {
final BoatClass boatClass;
if (getRegatta() != null) {
boatClass = getRegatta().getBoatClass();
} else {
boatClass = getBoatClassFromTrackedRaces();
}
return boatClass;
}
private BoatClass getBoatClassFromTrackedRaces() {
for (TrackedRace trackedRace : getLeaderboard().getTrackedRaces()) {
return trackedRace.getRace().getBoatClass();
}
return null;
}
}
@@ -9,6 +9,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.LeaderboardBase;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Series;
@@ -25,7 +26,6 @@ import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sse.common.Named;
import com.sap.sse.common.Util;
/**
@@ -43,7 +43,7 @@ import com.sap.sse.common.Util;
* @author Axel Uhl (d043530)
*
*/
public interface Leaderboard extends Named {
public interface Leaderboard extends LeaderboardBase {
/**
* If the leaderboard is a "matrix" with the cells being defined by a competitor / race "coordinate,"
* then this interface defines the structure of the "cells."
@@ -300,12 +300,6 @@ public interface Leaderboard extends Named {
void setDisplayName(Competitor competitor, String displayName);
/**
* If a display name for the leaderboard has been defined,
* this method returns it; otherwise, <code>null</code> is returned.
*/
String getDisplayName();
void setDisplayName(String displayName);
/**
@@ -0,0 +1,47 @@
package com.sap.sailing.server.gateway.deserialization.impl;
import java.util.ArrayList;
import java.util.List;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
import com.sap.sailing.domain.base.impl.LeaderboardBaseImpl;
import com.sap.sailing.domain.base.impl.LeaderboardSearchResultBaseImpl;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardSearchResultJsonSerializer;
public class LeaderboardSearchResultBaseJsonDeserializer implements JsonDeserializer<LeaderboardSearchResultBase> {
private final EventBaseJsonDeserializer eventDeserializer;
private final LeaderboardGroupBaseJsonDeserializer leaderboardGroupDeserializer;
public LeaderboardSearchResultBaseJsonDeserializer(EventBaseJsonDeserializer eventDeserializer,
LeaderboardGroupBaseJsonDeserializer leaderboardGroupDeserializer) {
super();
this.eventDeserializer = eventDeserializer;
this.leaderboardGroupDeserializer = leaderboardGroupDeserializer;
}
@Override
public LeaderboardSearchResultBase deserialize(JSONObject object) throws JsonDeserializationException {
EventBase event = eventDeserializer.deserialize(Helpers.getNestedObjectSafe(object, LeaderboardSearchResultJsonSerializer.FIELD_EVENT));
JSONObject leaderboardJson = Helpers.getNestedObjectSafe(object, LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD);
String leaderboardName = (String) leaderboardJson.get(LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD_NAME);
String leaderboardDisplayName = (String) leaderboardJson.get(LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD_DISPLAY_NAME);
String boatClassName = (String) leaderboardJson.get(LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD_BOAT_CLASS_NAME);
String regattaName = (String) leaderboardJson.get(LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD_REGATTA_NAME);
JSONArray leaderboardGroupsJson = Helpers.getNestedArraySafe(leaderboardJson, LeaderboardSearchResultJsonSerializer.FIELD_LEADERBOARD_IN_LEADERBOARD_GROUPS);
List<LeaderboardGroupBase> leaderboardGroups = new ArrayList<LeaderboardGroupBase>();
for (Object leaderboardGroupJson : leaderboardGroupsJson) {
leaderboardGroups.add(leaderboardGroupDeserializer.deserialize((JSONObject) leaderboardGroupJson));
}
return new LeaderboardSearchResultBaseImpl(new LeaderboardBaseImpl(leaderboardName, leaderboardDisplayName),
regattaName, boatClassName, leaderboardGroups, event);
}
}
@@ -21,10 +21,10 @@ public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
public static final String FIELDS_LEADERBOARD_GROUPS = "leaderboardGroups";
private final JsonSerializer<Venue> venueSerializer;
private final JsonSerializer<? super LeaderboardGroupBase> leaderboardGroupSerializer;
private final JsonSerializer<? super LeaderboardGroupBase> leaderboardGroupBaseSerializer;
public EventBaseJsonSerializer(JsonSerializer<Venue> venueSerializer, JsonSerializer<? super LeaderboardGroupBase> leaderboardGroupSerializer) {
this.leaderboardGroupSerializer = leaderboardGroupSerializer;
public EventBaseJsonSerializer(JsonSerializer<Venue> venueSerializer, JsonSerializer<? super LeaderboardGroupBase> leaderboardGroupBaseSerializer) {
this.leaderboardGroupBaseSerializer = leaderboardGroupBaseSerializer;
this.venueSerializer = venueSerializer;
}
@@ -40,7 +40,7 @@ public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
JSONArray leaderboardGroups = new JSONArray();
result.put(FIELDS_LEADERBOARD_GROUPS, leaderboardGroups);
for (LeaderboardGroupBase lg : event.getLeaderboardGroups()) {
leaderboardGroups.add(leaderboardGroupSerializer.serialize(lg));
leaderboardGroups.add(leaderboardGroupBaseSerializer.serialize(lg));
}
return result;
}
@@ -0,0 +1,63 @@
package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
public class LeaderboardSearchResultJsonSerializer implements JsonSerializer<LeaderboardSearchResult> {
public static final String FIELD_SERVER_BASE_URL = "serverBaseURL";
public static final String FIELD_EVENT = "event";
public static final String FIELD_LEADERBOARD = "leaderboard";
public static final String FIELD_LEADERBOARD_NAME = "name";
public static final String FIELD_LEADERBOARD_DISPLAY_NAME = "displayName";
public static final String FIELD_LEADERBOARD_BOAT_CLASS_NAME = "boatClassName";
public static final String FIELD_LEADERBOARD_REGATTA_NAME = "regattaName";
public static final String FIELD_LEADERBOARD_IN_LEADERBOARD_GROUPS = "inLeaderboardGroups";
private final JsonSerializer<EventBase> eventBaseJsonSerializer;
private final JsonSerializer<LeaderboardGroupBase> leaderboardGroupBaseJsonSerializer;
public LeaderboardSearchResultJsonSerializer(JsonSerializer<EventBase> eventBaseJsonSerializer, JsonSerializer<LeaderboardGroupBase> leaderboardGroupBaseJsonSerializer) {
this.eventBaseJsonSerializer = eventBaseJsonSerializer;
this.leaderboardGroupBaseJsonSerializer = leaderboardGroupBaseJsonSerializer;
}
@Override
public JSONObject serialize(LeaderboardSearchResult leaderboardSearchResult) {
JSONObject result = new JSONObject();
result.put(
FIELD_EVENT,
leaderboardSearchResult.getEvent() == null ? null : eventBaseJsonSerializer
.serialize(leaderboardSearchResult.getEvent()));
JSONObject leaderboardJson = new JSONObject();
result.put(FIELD_LEADERBOARD, leaderboardJson);
Leaderboard leaderboard = leaderboardSearchResult.getLeaderboard();
leaderboardJson.put(FIELD_LEADERBOARD_NAME, leaderboard.getName());
leaderboardJson.put(FIELD_LEADERBOARD_DISPLAY_NAME, leaderboard.getDisplayName());
final String boatClassName;
final Regatta regatta;
if (leaderboard instanceof RegattaLeaderboard) {
regatta = ((RegattaLeaderboard) leaderboard).getRegatta();
boatClassName = regatta.getBoatClass().getName();
} else {
regatta = null;
boatClassName = leaderboardSearchResult.getBoatClassName();
}
leaderboardJson.put(FIELD_LEADERBOARD_BOAT_CLASS_NAME, boatClassName);
leaderboardJson.put(FIELD_LEADERBOARD_REGATTA_NAME, regatta == null ? null : regatta.getName());
JSONArray leaderboardGroupsJson = new JSONArray();
leaderboardJson.put(FIELD_LEADERBOARD_IN_LEADERBOARD_GROUPS, leaderboardGroupsJson);
for (LeaderboardGroup lg : leaderboardSearchResult.getLeaderboardGroups()) {
leaderboardGroupsJson.add(leaderboardGroupBaseJsonSerializer.serialize(lg));
}
return result;
}
}
@@ -13,8 +13,7 @@ public class RestApiApplication extends Application {
classes.add(EventsResource.class);
classes.add(RegattasResource.class);
classes.add(LeaderboardsResource.class);
// classes.add(WindResource.class);
classes.add(SearchResource.class);
return classes;
}
}
@@ -0,0 +1,48 @@
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.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONArray;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.CourseAreaJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardSearchResultJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
@Path("/v1/search")
public class SearchResource extends AbstractSailingServerResource {
private final JsonSerializer<LeaderboardSearchResult> serializer;
public SearchResource() {
final LeaderboardGroupBaseJsonSerializer leaderboardGroupSerializer = new LeaderboardGroupBaseJsonSerializer();
serializer = new LeaderboardSearchResultJsonSerializer(new EventBaseJsonSerializer(new VenueJsonSerializer(
new CourseAreaJsonSerializer()), leaderboardGroupSerializer), leaderboardGroupSerializer);
}
private Result<LeaderboardSearchResult> search(KeywordQuery query) {
return getService().search(query);
}
@GET
@Produces("application/json;charset=UTF-8")
public Response search(@QueryParam("q") String keywords) {
KeywordQuery query = new KeywordQuery(keywords.split(" "));
Iterable<LeaderboardSearchResult> searchResults = search(query).getHits();
JSONArray jsonSearchResults = new JSONArray();
for (LeaderboardSearchResult searchResult : searchResults) {
jsonSearchResults.add(serializer.serialize(searchResult));
}
return Response.ok(jsonSearchResults.toJSONString(), MediaType.APPLICATION_JSON).build();
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.server.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.net.URL;
import java.util.ArrayList;
@@ -21,7 +22,11 @@ import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Venue;
import com.sap.sailing.domain.base.Waypoint;
@@ -36,14 +41,25 @@ import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO;
import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.server.LeaderboardSearchResult;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardSearchResultBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.CourseAreaJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardSearchResultJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.operationaltransformation.AddColumnToSeries;
import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
@@ -241,10 +257,14 @@ public class SearchServiceTest {
Result<LeaderboardSearchResult> searchResults = server.search(new KeywordQuery(Arrays.asList(new String[] { "Kiel" })));
assertEquals(2, Util.size(searchResults.getHits()));
final Iterator<LeaderboardSearchResult> iterator = searchResults.getHits().iterator();
Regatta firstFoundRegatta = iterator.next().getRegatta();
final LeaderboardSearchResult firstMatch = iterator.next();
Regatta firstFoundRegatta = firstMatch.getRegatta();
assertSame(pfingstbusch29er, firstFoundRegatta);
Regatta secondFoundRegatta = iterator.next().getRegatta();
assertSame(pfingstbusch, firstMatch.getEvent());
final LeaderboardSearchResult secondMatch = iterator.next();
Regatta secondFoundRegatta = secondMatch.getRegatta();
assertSame(pfingstbusch470, secondFoundRegatta);
assertSame(pfingstbusch, secondMatch.getEvent());
}
@Test
@@ -252,9 +272,44 @@ public class SearchServiceTest {
Result<LeaderboardSearchResult> searchResults = server.search(new KeywordQuery(Arrays.asList(new String[] { "Buhl" })));
assertEquals(2, Util.size(searchResults.getHits()));
final Iterator<LeaderboardSearchResult> iter = searchResults.getHits().iterator();
Regatta earlierStartRegatta = iter.next().getRegatta();
final LeaderboardSearchResult firstMatch = iter.next();
Regatta earlierStartRegatta = firstMatch.getRegatta();
assertSame(pfingstbusch470, earlierStartRegatta);
Regatta laterStartRegatta = iter.next().getRegatta();
assertSame(pfingstbusch, firstMatch.getEvent());
final LeaderboardSearchResult secondMatch = iter.next();
Regatta laterStartRegatta = secondMatch.getRegatta();
assertSame(aalRegatta, laterStartRegatta);
assertSame(aalEvent, secondMatch.getEvent());
}
@Test
public void testSerializeAndDeserializeSearchResult() throws JsonDeserializationException {
Result<LeaderboardSearchResult> searchResults = server.search(new KeywordQuery(Arrays.asList(new String[] { "Buhl" })));
LeaderboardGroupBaseJsonSerializer leaderboardGroupBaseJsonSerializer = new LeaderboardGroupBaseJsonSerializer();
LeaderboardSearchResultJsonSerializer serializer = new LeaderboardSearchResultJsonSerializer(new EventBaseJsonSerializer(new VenueJsonSerializer(new CourseAreaJsonSerializer()),
leaderboardGroupBaseJsonSerializer),
leaderboardGroupBaseJsonSerializer);
LeaderboardGroupBaseJsonDeserializer leaderboardGroupBaseJsonDeserializer = new LeaderboardGroupBaseJsonDeserializer();
LeaderboardSearchResultBaseJsonDeserializer deserializer = new LeaderboardSearchResultBaseJsonDeserializer(
new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)),
leaderboardGroupBaseJsonDeserializer), leaderboardGroupBaseJsonDeserializer);
final LeaderboardSearchResult expected = searchResults.getHits().iterator().next();
LeaderboardSearchResultBase deserialized = deserializer.deserialize(serializer.serialize(expected));
assertEquals("Pfingstbusch (470)", deserialized.getRegattaName());
assertEquals(expected.getEvent().getName(), deserialized.getEvent().getName());
assertEquals(expected.getEvent().getId(), deserialized.getEvent().getId());
assertEquals(expected.getEvent().getStartDate(), deserialized.getEvent().getStartDate());
assertEquals(expected.getEvent().getEndDate(), deserialized.getEvent().getEndDate());
assertEquals(expected.getEvent().getVenue().getName(), deserialized.getEvent().getVenue().getName());
Iterator<LeaderboardGroup> expectedLGs = expected.getLeaderboardGroups().iterator();
Iterator<? extends LeaderboardGroupBase> deserializedLGs = deserialized.getLeaderboardGroups().iterator();
while (expectedLGs.hasNext()) {
assertTrue(deserializedLGs.hasNext());
LeaderboardGroup expectedLG = expectedLGs.next();
LeaderboardGroupBase deserializedLG = deserializedLGs.next();
assertEquals(expectedLG.getId(), deserializedLG.getId());
assertEquals(expectedLG.getName(), deserializedLG.getName());
assertEquals(expectedLG.getDescription(), deserializedLG.getDescription());
}
}
}
@@ -1,10 +0,0 @@
package com.sap.sailing.server;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sse.common.search.Hit;
public interface LeaderboardSearchResult extends Hit {
Regatta getRegatta();
Leaderboard getLeaderboard();
}
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
@@ -1,29 +0,0 @@
package com.sap.sailing.server.impl;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.server.LeaderboardSearchResult;
public class LeaderboardSearchResultImpl implements LeaderboardSearchResult {
private final Leaderboard leaderboard;
public LeaderboardSearchResultImpl(Leaderboard leaderboard) {
this.leaderboard = leaderboard;
}
public Regatta getRegatta() {
final Regatta regatta;
if (leaderboard instanceof RegattaLeaderboard) {
regatta = ((RegattaLeaderboard) leaderboard).getRegatta();
} else {
regatta = null;
}
return regatta;
}
@Override
public Leaderboard getLeaderboard() {
return leaderboard;
}
}
@@ -39,6 +39,7 @@ import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnInSeries;
@@ -133,7 +134,6 @@ import com.sap.sailing.operationaltransformation.Operation;
import com.sap.sailing.server.OperationExecutionListener;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
import com.sap.sailing.server.LeaderboardSearchResult;
import com.sap.sailing.server.Replicator;
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
import com.sap.sailing.server.operationaltransformation.AddCourseArea;
@@ -1,15 +1,19 @@
package com.sap.sailing.server.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.impl.LeaderboardSearchResultImpl;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.server.LeaderboardSearchResult;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Util;
import com.sap.sse.common.filter.AbstractListFilter;
@@ -30,9 +34,12 @@ import com.sap.sse.common.search.ResultImpl;
public class RegattaByKeywordSearchService {
Result<LeaderboardSearchResult> search(final RacingEventService racingEventService, KeywordQuery query) {
ResultImpl<LeaderboardSearchResult> result = new ResultImpl<>(query, new RegattaSearchResultRanker(racingEventService));
final Map<Leaderboard, Event> eventForLeaderboard = new HashMap<>();
final Map<Leaderboard, Set<LeaderboardGroup>> leaderboardGroupsForLeaderboard = new HashMap<>();
AbstractListFilter<Leaderboard> leaderboardFilter = new AbstractListFilter<Leaderboard>() {
@Override
public Iterable<String> getStrings(Leaderboard leaderboard) {
// TODO allow recording which part of the leaderboard was matched by the keywords by returning "annotated strings" that the matcher can understand
List<String> leaderboardStrings = new ArrayList<>();
leaderboardStrings.add(leaderboard.getName());
leaderboardStrings.add(leaderboard.getDisplayName());
@@ -49,16 +56,23 @@ public class RegattaByKeywordSearchService {
for (LeaderboardGroup leaderboardGroup : leaderboardGroupsHostingLeaderboard) {
leaderboardStrings.add(leaderboardGroup.getName());
leaderboardStrings.add(leaderboardGroup.getDescription());
Set<LeaderboardGroup> leaderboardGroups = leaderboardGroupsForLeaderboard.get(leaderboard);
if (leaderboardGroups == null) {
leaderboardGroups = new HashSet<>();
leaderboardGroupsForLeaderboard.put(leaderboard, leaderboardGroups);
}
leaderboardGroups.add(leaderboardGroup);
}
for (Event event : getEventsHostingLeaderboard(leaderboard, racingEventService, leaderboardGroupsHostingLeaderboard)) {
leaderboardStrings.add(event.getName());
leaderboardStrings.add(event.getVenue().getName());
eventForLeaderboard.put(leaderboard, event);
}
return leaderboardStrings;
}
};
for (Leaderboard matchingLeaderboard : leaderboardFilter.applyFilter(query.getKeywords(), racingEventService.getLeaderboards().values())) {
result.addHit(new LeaderboardSearchResultImpl(matchingLeaderboard));
result.addHit(new LeaderboardSearchResultImpl(matchingLeaderboard, eventForLeaderboard.get(matchingLeaderboard), leaderboardGroupsForLeaderboard.get(matchingLeaderboard)));
}
return result;
}
@@ -5,13 +5,13 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.LeaderboardSearchResult;
import com.sap.sse.common.Util;
public class RegattaSearchResultRanker implements Comparator<LeaderboardSearchResult> {
@@ -1,20 +1,37 @@
package com.sap.sse.common.search;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.sap.sse.common.Util;
public class KeywordQuery implements Query {
private final Iterable<String> keywords;
public KeywordQuery(String... keywords) {
this.keywords = Arrays.asList(keywords);
this.keywords = trim(Arrays.asList(keywords));
}
private Iterable<String> trim(Iterable<String> keywords) {
final List<String> result = new ArrayList<String>(Util.size(keywords));
for (String keyword : keywords) {
result.add(keyword.trim());
}
return result;
}
public KeywordQuery(Iterable<String> keywords) {
super();
this.keywords = keywords;
this.keywords = trim(keywords);
}
public Iterable<String> getKeywords() {
return keywords;
}
@Override
public String toString() {
return ""+keywords;
}
}