mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 21:30:57 +00:00
Merge remote-tracking branch 'server/master'
This commit is contained in:
commit
22f66dadea
64 files changed
+1831
-669
No files matched your search
@@ -9,6 +9,7 @@ Bundle-ActivationPolicy: lazy
|
||||
Export-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.filter,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.media,
|
||||
com.sap.sailing.domain.common.quadtree,
|
||||
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test",
|
||||
com.sap.sailing.domain.common.racelog,
|
||||
|
||||
+52
-14
@@ -1,15 +1,16 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.media;
|
||||
package com.sap.sailing.domain.common.media;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
|
||||
/**
|
||||
* See http://my.opera.com/core/blog/2010/03/03/everything-you-need-to-know-about-html5-video-and-audio-2
|
||||
* @author D047974
|
||||
*
|
||||
*/
|
||||
public class MediaTrack implements IsSerializable {
|
||||
public class MediaTrack implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public enum MimeType {
|
||||
|
||||
@@ -56,13 +57,6 @@ public class MediaTrack implements IsSerializable {
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaSection implements IsSerializable {
|
||||
public String title;
|
||||
public long offsetInMillis;
|
||||
public Date startTime;
|
||||
public Date endTime;
|
||||
}
|
||||
|
||||
public String dbId;
|
||||
public String title;
|
||||
public String url;
|
||||
@@ -72,11 +66,17 @@ public class MediaTrack implements IsSerializable {
|
||||
public Status status = Status.UNDEFINED;
|
||||
|
||||
public MediaTrack() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public MediaTrack(String title, String url, Date startTime, int durationInMillis, MimeType mimeType) {
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
this.startTime = startTime;
|
||||
this.durationInMillis = durationInMillis;
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public MediaTrack(String dbId, String title, String url, Date startTime, int durationInMillis, MimeType mimeType) {
|
||||
super();
|
||||
this.dbId = dbId;
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
@@ -88,6 +88,14 @@ public class MediaTrack implements IsSerializable {
|
||||
public String toString() {
|
||||
return title + " - " + url + " [" + typeToString() + ']' + startTime + " [" + durationInMillis + status + ']';
|
||||
}
|
||||
|
||||
public Date deriveEndTime() {
|
||||
if (startTime != null) {
|
||||
return new Date(startTime.getTime() + durationInMillis);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String typeToString() {
|
||||
return mimeType == null ? "undefined" : mimeType.toString();
|
||||
@@ -96,5 +104,35 @@ public class MediaTrack implements IsSerializable {
|
||||
public boolean isYoutube() {
|
||||
return (mimeType != null) && MediaSubType.youtube.equals(mimeType.mediaSubType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for overlap of this start time and duration with the given startTime and endTime, excluding boundaries!
|
||||
* Behaviour for given endTime being earlier than given startTime is not specified.
|
||||
* endTime being null represents "open end". Open beginning is not allow, though!
|
||||
* @param startTime Must not be null.
|
||||
* @param endTime May be null representing "open end".
|
||||
*/
|
||||
public boolean overlapsWith(Date startTime, Date endTime) {
|
||||
if (this.startTime == null) {
|
||||
return false;
|
||||
} else {
|
||||
return this.deriveEndTime().getTime() > startTime.getTime() && (endTime == null || this.startTime.getTime() < endTime.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof MediaTrack) {
|
||||
MediaTrack mediaTrack = (MediaTrack) obj;
|
||||
return this.dbId == null? mediaTrack.dbId == null : this.dbId.equals(mediaTrack.dbId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.dbId == null ? 0 : this.dbId.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.domain.common.media;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class MediaUtil {
|
||||
|
||||
public static int compareDatesAllowingNull(Date date1, Date date2) {
|
||||
if (date1 == null) {
|
||||
return date2 == null ? 0 : -1;
|
||||
} else if (date2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return date1.compareTo(date2);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean equalsDatesAllowingNull(Date date1, Date date2) {
|
||||
if (date1 == null) {
|
||||
return date2 == null;
|
||||
} else if (date2 == null) {
|
||||
return false;
|
||||
} else {
|
||||
return date1.equals(date2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+31
-5
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.domain.persistence.media;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,11 +14,9 @@ public interface MediaDB {
|
||||
|
||||
String insertMediaTrack(String title, String url, Date startTime, int durationInMillis, String mimeType);
|
||||
|
||||
DBMediaTrack loadMediaTrack(String dbId);
|
||||
|
||||
List<DBMediaTrack> loadAllMediaTracks();
|
||||
|
||||
void deleteMediaTrack(String title);
|
||||
void deleteMediaTrack(String dbId);
|
||||
|
||||
void updateTitle(String dbId, String title);
|
||||
|
||||
@@ -28,6 +26,34 @@ public interface MediaDB {
|
||||
|
||||
void updateDuration(String dbId, int durationInMillis);
|
||||
|
||||
Collection<DBMediaTrack> queryOverlappingMediaTracks(Date rangeStart, Date rangeEnd);
|
||||
MediaDB TEST_STUB = new MediaDB() {
|
||||
|
||||
@Override
|
||||
public String insertMediaTrack(String title, String url, Date startTime, int durationInMillis, String mimeType) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DBMediaTrack> loadAllMediaTracks() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMediaTrack(String dbId) {}
|
||||
|
||||
@Override
|
||||
public void updateTitle(String dbId, String title) {}
|
||||
|
||||
@Override
|
||||
public void updateUrl(String dbId, String url) {}
|
||||
|
||||
@Override
|
||||
public void updateStartTime(String dbId, Date startTime) {}
|
||||
|
||||
@Override
|
||||
public void updateDuration(String dbId, int durationInMillis) {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
-2
@@ -6,8 +6,6 @@ import com.sap.sailing.mongodb.MongoDBService;
|
||||
public interface MediaDBFactory {
|
||||
MediaDBFactory INSTANCE = new MediaDBFactoryImpl();
|
||||
|
||||
MediaObjectFactory getDefaultDomainObjectFactory();
|
||||
MediaObjectFactory getDomainObjectFactory(MongoDBService mongoDBService);
|
||||
MediaDB getDefaultMediaDB();
|
||||
MediaDB getMediaDB(MongoDBService mongoDBService);
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package com.sap.sailing.domain.persistence.media;
|
||||
|
||||
|
||||
/**
|
||||
* Offers methods to load media objects from a Mongo DB
|
||||
*
|
||||
* @author Jens Rommel (d047974)
|
||||
*
|
||||
*/
|
||||
public interface MediaObjectFactory {
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
package com.sap.sailing.domain.persistence.media.impl;
|
||||
|
||||
/**
|
||||
* Defines literals providing the names for MongoDB collections. The literal documentation described the semantics
|
||||
* of the collection identified by that literal.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public enum CollectionNames {
|
||||
/**
|
||||
* Stores the wind fixes recorded from persistent wind sources.
|
||||
*/
|
||||
WIND_TRACKS,
|
||||
|
||||
/**
|
||||
* Stores the leaderboards with their names, score corrections, competitor display name overrides, race
|
||||
* columns and their fleets as well as the per-fleet tracked race assignments.
|
||||
*/
|
||||
LEADERBOARDS,
|
||||
|
||||
/**
|
||||
* Stores the leaderboard group configurations with references to the {@link #LEADERBOARDS} collection
|
||||
*/
|
||||
LEADERBOARD_GROUPS,
|
||||
|
||||
/**
|
||||
* Top-level event information about events such as Kiel Week 2011, or IDM Travem�nde 2011, including name and
|
||||
* course areas.
|
||||
*/
|
||||
EVENTS,
|
||||
|
||||
/**
|
||||
* Stores regatta definitions including their series layout and fleets and race columns. Regattas can reference
|
||||
* the event from the {@link #EVENTS} collection to which they belong.
|
||||
*/
|
||||
REGATTAS,
|
||||
|
||||
/**
|
||||
* Stores boat class-specific master data such as the class's hull length, logo, name, number of sailors, etc.
|
||||
* To be implemented in future versions.
|
||||
*/
|
||||
BOAT_CLASSES,
|
||||
|
||||
/**
|
||||
* Stores the mapping of {@link RaceDefinition#getId race IDs} to regatta names for automatic re-association
|
||||
* when tracking races again without explicitly specifying a regatta.
|
||||
*/
|
||||
REGATTA_FOR_RACE_ID;
|
||||
}
|
||||
-13
@@ -2,29 +2,16 @@ package com.sap.sailing.domain.persistence.media.impl;
|
||||
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.domain.persistence.media.MediaObjectFactory;
|
||||
import com.sap.sailing.mongodb.MongoDBService;
|
||||
|
||||
public class MediaDBFactoryImpl implements MediaDBFactory {
|
||||
private final MediaObjectFactory defaultMediaObjectFactory;
|
||||
private final MediaDB defaultMediaDB;
|
||||
|
||||
public MediaDBFactoryImpl() {
|
||||
super();
|
||||
this.defaultMediaObjectFactory = new MediaObjectFactoryImpl(MongoDBService.INSTANCE.getDB());
|
||||
this.defaultMediaDB = new MediaDBImpl(MongoDBService.INSTANCE.getDB());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaObjectFactory getDefaultDomainObjectFactory() {
|
||||
return defaultMediaObjectFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaObjectFactory getDomainObjectFactory(MongoDBService mongoDBService) {
|
||||
return new MediaObjectFactoryImpl(mongoDBService.getDB());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaDB getDefaultMediaDB() {
|
||||
return defaultMediaDB;
|
||||
|
||||
-50
@@ -1,8 +1,6 @@
|
||||
package com.sap.sailing.domain.persistence.media.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@@ -13,7 +11,6 @@ import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import com.sap.sailing.domain.persistence.media.DBMediaTrack;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
|
||||
@@ -63,23 +60,6 @@ public class MediaDBImpl implements MediaDB {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBMediaTrack loadMediaTrack(String dbId) {
|
||||
ObjectId objectId = new ObjectId(dbId);
|
||||
DBCursor cursor = getVideoCollection().find(new BasicDBObject(DbNames.Fields._id.name(), objectId));
|
||||
switch (cursor.count()) {
|
||||
case 0:
|
||||
throw new RuntimeException("Video not found with id: " + dbId);
|
||||
case 1:
|
||||
DBObject dbObject = cursor.next();
|
||||
DBMediaTrack dbMediaTrack = createMediaObjectFromDB(dbObject);
|
||||
return dbMediaTrack;
|
||||
default:
|
||||
throw new RuntimeException("Ambiguous videos not found with id: " + dbId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private DBMediaTrack createMediaObjectFromDB(DBObject dbObject) {
|
||||
String dbId = ((ObjectId) dbObject.get(DbNames.Fields._id.name())).toString();
|
||||
String title = (String) dbObject.get(DbNames.Fields.MEDIA_TITLE.name());
|
||||
@@ -152,34 +132,4 @@ public class MediaDBImpl implements MediaDB {
|
||||
getVideoCollection().update(updateQuery, update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DBMediaTrack> queryOverlappingMediaTracks(Date rangeStart, Date rangeEnd) {
|
||||
if ((rangeStart != null) && (rangeEnd != null)) {
|
||||
BasicDBObject startTimeCondition = new BasicDBObject();
|
||||
startTimeCondition.put(DbNames.Fields.STARTTIME.name(), new BasicDBObject("$gt", rangeStart));
|
||||
startTimeCondition.put(DbNames.Fields.STARTTIME.name(), new BasicDBObject("$lt", rangeEnd));
|
||||
BasicDBObject endTimeCondition = new BasicDBObject();
|
||||
|
||||
// Should actually be "AND greater than rangeStart - duration".
|
||||
// However, using values calculated on server side turns out to be a nightmare with mongodb.
|
||||
// Instead do the remaining filtering on client side...
|
||||
endTimeCondition.put(DbNames.Fields.STARTTIME.name(), new BasicDBObject("$lt", rangeStart));
|
||||
|
||||
DBObject query = QueryBuilder.start().or(startTimeCondition, endTimeCondition).get();
|
||||
|
||||
DBCursor cursor = getVideoCollection().find(query).sort(sortByStartTimeAndTitle);
|
||||
|
||||
List<DBMediaTrack> result = new ArrayList<>(cursor.count());
|
||||
while (cursor.hasNext()) {
|
||||
DBMediaTrack resultCandidate = createMediaObjectFromDB(cursor.next());
|
||||
if (resultCandidate.durationInMillis > rangeStart.getTime() - resultCandidate.startTime.getTime()) {
|
||||
result.add(resultCandidate);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package com.sap.sailing.domain.persistence.media.impl;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaObjectFactory;
|
||||
|
||||
public class MediaObjectFactoryImpl implements MediaObjectFactory {
|
||||
|
||||
// private static final Logger logger = Logger.getLogger(MediaObjectFactoryImpl.class.getName());
|
||||
|
||||
// private final DB database;
|
||||
|
||||
public MediaObjectFactoryImpl(DB db) {
|
||||
super();
|
||||
// this.database = db;
|
||||
}
|
||||
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package com.sap.sailing.domain.persistence.media.impl;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
public class MongoUtils {
|
||||
/**
|
||||
* Key names in MongoDB must not start with a $ sign and must not contain a "." character. This method escapes
|
||||
* those. {@link #unescapeDollarAndDot} is the inverse function.
|
||||
*
|
||||
* @param key
|
||||
* a non-<code>null</code> string which may have length 0
|
||||
* @return a string that can be used as a key in a MongoDB key-value pair and that can be decoded again using
|
||||
* {@link #unescapeDollarAndDot(String)}.
|
||||
*/
|
||||
public static String escapeDollarAndDot(String key) {
|
||||
String result = key.replace("%", "%25").replace("+", "%2B");
|
||||
if (result.length() > 0 && result.charAt(0) == '$') {
|
||||
result = "%24"+result.substring(1);
|
||||
}
|
||||
return result.replace(".", "%2E");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #escapeDollarAndDot(String)
|
||||
* @param key
|
||||
* a non-<code>null</code> string which may have length 0 and that was returned by
|
||||
* {@link #escapeDollarAndDot(String)}.
|
||||
* @return the string originally passed to {@link #escapeDollarAndDot(String)}
|
||||
*/
|
||||
public static String unescapeDollarAndDot(String escapedKey) {
|
||||
try {
|
||||
return URLDecoder.decode(escapedKey, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("How come this VM doesn't know UTF-8?");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence;bundle-version="1.0.0"
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence;bundle-version="1.0.0",
|
||||
org.hamcrest.core;bundle-version="1.1.0"
|
||||
Bundle-ClassPath: resources/,
|
||||
.
|
||||
Import-Package: com.sap.sailing.server,
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType.OlympicRaceCode;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
|
||||
public class DomainFactoryTest {
|
||||
|
||||
private com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl swissTimingDomainFactory;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
com.sap.sailing.domain.base.DomainFactory baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
|
||||
swissTimingDomainFactory = new com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl(
|
||||
baseDomainFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFinnBoatClass() throws Exception {
|
||||
String raceID = "SAM002";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode.FINN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFinnBoatClass_LowerCase() throws Exception {
|
||||
String raceID = "sam002";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode.FINN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet470WomenBoatClass() throws Exception {
|
||||
String raceID = "SAW005";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet470WomenBoatClass2() throws Exception {
|
||||
String raceID = "SAW005_xxx";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontGetWrongBoatClass() throws Exception {
|
||||
String raceID = "ABC";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode.UNKNOWN));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testCompetitorLookup() throws Exception {
|
||||
before();
|
||||
|
||||
// swissTimingDomainFactory.getOrCreateCompetitor(boatID, threeLetterIOCCode, name, boatClass);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+7
-6
@@ -1,10 +1,5 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -35,6 +30,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.MessageType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
@@ -59,6 +55,11 @@ import com.sap.sailing.mongodb.MongoDBService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class EndToEndListeningStoreAndFowardTest {
|
||||
private static final Logger logger = Logger.getLogger(EndToEndListeningStoreAndFowardTest.class.getName());
|
||||
|
||||
@@ -117,7 +118,7 @@ public class EndToEndListeningStoreAndFowardTest {
|
||||
final com.sap.sailing.domain.base.impl.DomainFactoryImpl baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
|
||||
racingEventService = new RacingEventServiceImpl(mongoDBService, SwissTimingFactory.INSTANCE,
|
||||
new DomainFactoryImpl(baseDomainFactory),
|
||||
new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(baseDomainFactory));
|
||||
new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(baseDomainFactory), MediaDB.TEST_STUB);
|
||||
raceHandles = new ArrayList<RacesHandle>();
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -2,8 +2,6 @@ package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
@@ -31,18 +29,20 @@ public interface DomainFactory {
|
||||
|
||||
Nationality getOrCreateNationality(String threeLetterIOCCode);
|
||||
|
||||
Competitor getOrCreateCompetitor(com.sap.sailing.domain.swisstimingadapter.Competitor competitor, BoatClass boatClass);
|
||||
Competitor getOrCreateCompetitor(com.sap.sailing.domain.swisstimingadapter.Competitor competitor, RaceType raceType);
|
||||
|
||||
Competitor getOrCreateCompetitor(String boatID, String threeLetterIOCCode, String name, BoatClass boatClass);
|
||||
Competitor getOrCreateCompetitor(String boatID, String threeLetterIOCCode, String name, RaceType raceType);
|
||||
|
||||
Competitor getCompetitorByBoatIDAndRaceType(String boatID, RaceType raceType);
|
||||
|
||||
Competitor getCompetitorByBoatIDAndRaceID(String boatID, String raceID);
|
||||
|
||||
RaceDefinition createRaceDefinition(Regatta regatta, Race race, StartList startList, com.sap.sailing.domain.swisstimingadapter.Course course);
|
||||
|
||||
com.sap.sailing.domain.base.Mark getOrCreateMark(String trackerID);
|
||||
|
||||
GPSFixMoving createGPSFix(TimePoint timePointOfTransmission, Fix fix);
|
||||
|
||||
Competitor getCompetitorByBoatIDAndBoatClass(String boatID, BoatClass boatClass);
|
||||
|
||||
void updateCourseWaypoints(Course courseToUpdate, Iterable<Mark> marks) throws PatchFailedException;
|
||||
|
||||
MarkPassing createMarkPassing(TimePoint timePoint, Waypoint waypoint, Competitor competitor);
|
||||
@@ -54,10 +54,11 @@ public interface DomainFactory {
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore, WindStore windStore,
|
||||
RaceSpecificMessageLoader messageLoader);
|
||||
|
||||
BoatClass getOrCreateBoatClassFromRaceID(String raceID);
|
||||
RaceType getRaceTypeFromRaceID(String raceID);
|
||||
|
||||
ControlPoint getOrCreateControlPoint(Iterable<String> devices);
|
||||
|
||||
RaceDefinition createRaceDefinition(Regatta regatta, String raceID, Iterable<Competitor> competitors,
|
||||
List<ControlPoint> courseDefinition);
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
|
||||
|
||||
public interface RaceType {
|
||||
|
||||
public enum OlympicRaceCode {
|
||||
|
||||
// SAM102000 Men's Windsurfer = Windsufer M�nner RS:X
|
||||
// SAW102000 Women's Windsurfer = Windsurfer Damen RS:X
|
||||
// SAM004000 Men's One Person Dinghy = Laser M�nner
|
||||
// SAW103000 Women's One Person Dinghy = Laser Damen Laser Radial
|
||||
// SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy M�nner
|
||||
// SAM005000 Men's Two Person Dinghy = 470er M�nner
|
||||
// SAW005000 Women's Two Person Dinghy = 470er Damen
|
||||
// SAM009000 Men's Skiff = 49er M�nner
|
||||
// SAM007000 Men's Keelboat = Starboot M�nner
|
||||
// SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified)
|
||||
|
||||
|
||||
UNKNOWN("Unspecified", "Unspecified", Gender.unspecified),
|
||||
FINN("SAM002", "Finn", Gender.male),
|
||||
LASER("SAM004", "Laser", Gender.male),
|
||||
_470_WOMEN("SAW005", "470", Gender.female),
|
||||
_470_MEN("SAM005", "470", Gender.male),
|
||||
STAR("SAM007", "Star", Gender.male),
|
||||
_49ER("SAM009", "49er", Gender.male),
|
||||
ELLIOTT6M("SAW007", "Elliott 6M", Gender.female),
|
||||
RSX_WOMEN("SAW102", "RS:X", Gender.female),
|
||||
RSX_MEN("SAM102", "RS:X", Gender.male),
|
||||
LASER_RADIAL("SAW103", "Laser Radial", Gender.female),
|
||||
_49ERFX_TODO("xxxxx_TODO_xxxxx", "49er FX", Gender.female),
|
||||
NACRA17_TOTO("xxxxx_TODO_xxxxx", "Nacra 17", Gender.mixed);
|
||||
|
||||
enum Gender {
|
||||
male, female, mixed, unspecified;
|
||||
}
|
||||
|
||||
public final String swissTimingCode;
|
||||
|
||||
public final String boatClassName;
|
||||
|
||||
public final Gender gender;
|
||||
|
||||
public final boolean typicallyStartsUpwind;
|
||||
|
||||
private OlympicRaceCode(String swissTimingCode, String boatClassName, Gender gender) {
|
||||
this.swissTimingCode = swissTimingCode;
|
||||
this.boatClassName = boatClassName;
|
||||
this.gender = gender;
|
||||
this.typicallyStartsUpwind = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OlympicRaceCode getRaceCode();
|
||||
|
||||
BoatClass getBoatClass();
|
||||
|
||||
}
|
||||
+4
@@ -34,4 +34,8 @@ public class CompetitorImpl implements Competitor {
|
||||
return name+"/"+boatID;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+52
-64
@@ -42,6 +42,8 @@ import com.sap.sailing.domain.swisstimingadapter.MessageType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceSpecificMessageLoader;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType.OlympicRaceCode;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
@@ -64,36 +66,23 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
private final static Logger logger = Logger.getLogger(DomainFactoryImpl.class.getName());
|
||||
private final Map<String, Regatta> raceIDToRegattaCache;
|
||||
private final Map<Iterable<String>, ControlPoint> controlPointCache;
|
||||
private final Map<String, BoatClass> olympicClassesByID;
|
||||
private final BoatClass unknownBoatClass;
|
||||
private final Map<String, RaceType> raceTypeByID;
|
||||
private final RaceType unknownRaceType;
|
||||
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
||||
|
||||
public DomainFactoryImpl(com.sap.sailing.domain.base.DomainFactory baseDomainFactory) {
|
||||
this.baseDomainFactory = baseDomainFactory;
|
||||
raceIDToRegattaCache = new HashMap<String, Regatta>();
|
||||
controlPointCache = new HashMap<Iterable<String>, ControlPoint>();
|
||||
olympicClassesByID = new HashMap<String, BoatClass>();
|
||||
/*
|
||||
SAM102000 Men's Windsurfer = Windsufer M�nner RS:X
|
||||
SAW102000 Women's Windsurfer = Windsurfer Damen RS:X
|
||||
SAM004000 Men's One Person Dinghy = Laser M�nner
|
||||
SAW103000 Women's One Person Dinghy = Laser Damen Laser Radial
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy M�nner
|
||||
SAM005000 Men's Two Person Dinghy = 470er M�nner
|
||||
SAW005000 Women's Two Person Dinghy = 470er Damen
|
||||
SAM009000 Men's Skiff = 49er M�nner
|
||||
SAM007000 Men's Keelboat = Starboot M�nner
|
||||
SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified)
|
||||
*/
|
||||
olympicClassesByID.put("102", baseDomainFactory.getOrCreateBoatClass("RS:X", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("004", baseDomainFactory.getOrCreateBoatClass("Laser", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("103", baseDomainFactory.getOrCreateBoatClass("Laser Radial", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("002", baseDomainFactory.getOrCreateBoatClass("Finn", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("005", baseDomainFactory.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("009", baseDomainFactory.getOrCreateBoatClass("49er", /* alwaysStartsUpwind */ true));
|
||||
olympicClassesByID.put("007", baseDomainFactory.getOrCreateBoatClass("Star", /* typicallyStartsUpwind */ true));
|
||||
olympicClassesByID.put("010", baseDomainFactory.getOrCreateBoatClass("Elliott 6M", /* typicallyStartsUpwind */ true));
|
||||
unknownBoatClass = baseDomainFactory.getOrCreateBoatClass("Unknown", /* typicallyStartsUpwind */ true);
|
||||
raceTypeByID = new HashMap<String, RaceType>();
|
||||
|
||||
for (OlympicRaceCode olympicRaceCode : OlympicRaceCode.values()) {
|
||||
raceTypeByID.put(
|
||||
olympicRaceCode.swissTimingCode,
|
||||
new RaceTypeImpl(olympicRaceCode, baseDomainFactory.getOrCreateBoatClass(
|
||||
olympicRaceCode.boatClassName, olympicRaceCode.typicallyStartsUpwind)));
|
||||
}
|
||||
unknownRaceType = new RaceTypeImpl(OlympicRaceCode.UNKNOWN, baseDomainFactory.getOrCreateBoatClass("Unknown", OlympicRaceCode.UNKNOWN.typicallyStartsUpwind));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +97,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
result = raceIDToRegattaCache.get(raceID);
|
||||
}
|
||||
if (result == null) {
|
||||
result = new RegattaImpl(raceLogStore, raceID, getOrCreateBoatClassFromRaceID(raceID), trackedRegattaRegistry,
|
||||
result = new RegattaImpl(raceLogStore, raceID, getRaceTypeFromRaceID(raceID).getBoatClass(), trackedRegattaRegistry,
|
||||
getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), raceID, null);
|
||||
logger.info("Created regatta "+result.getName()+" ("+result.hashCode()+")");
|
||||
raceIDToRegattaCache.put(raceID, result);
|
||||
@@ -117,26 +106,36 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Competitor getCompetitorByBoatIDAndBoatClass(String boatID, BoatClass boatClass) {
|
||||
return baseDomainFactory.getExistingCompetitorById(getCompetitorID(boatID, boatClass));
|
||||
public Competitor getCompetitorByBoatIDAndRaceType(String boatID, RaceType raceType) {
|
||||
return baseDomainFactory.getExistingCompetitorById(getCompetitorID(boatID, raceType));
|
||||
}
|
||||
|
||||
private String getCompetitorID(String boatID, BoatClass boatClass) {
|
||||
return boatID + "/" + boatClass.getName();
|
||||
@Override
|
||||
public Competitor getCompetitorByBoatIDAndRaceID(String boatID, String raceID) {
|
||||
RaceType raceType = getRaceTypeFromRaceID(raceID);
|
||||
if (raceType != null) {
|
||||
return getCompetitorByBoatIDAndRaceType(boatID, raceType);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getCompetitorID(String boatID, RaceType raceType) {
|
||||
return boatID + "/" + raceType.getRaceCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Competitor getOrCreateCompetitor(com.sap.sailing.domain.swisstimingadapter.Competitor competitor, BoatClass boatClass) {
|
||||
Competitor result = getCompetitorByBoatIDAndBoatClass(competitor.getBoatID(), boatClass);
|
||||
public Competitor getOrCreateCompetitor(com.sap.sailing.domain.swisstimingadapter.Competitor competitor, RaceType raceType) {
|
||||
Competitor result = getCompetitorByBoatIDAndRaceType(competitor.getBoatID(), raceType);
|
||||
if (result == null) {
|
||||
Boat boat = new BoatImpl(competitor.getName(), boatClass, competitor.getBoatID());
|
||||
Boat boat = new BoatImpl(competitor.getName(), raceType.getBoatClass(), competitor.getBoatID());
|
||||
List<Person> teamMembers = new ArrayList<Person>();
|
||||
for (String teamMemberName : competitor.getName().split("[-+&]")) {
|
||||
teamMembers.add(new PersonImpl(teamMemberName.trim(), getOrCreateNationality(competitor.getThreeLetterIOCCode()),
|
||||
/* dateOfBirth */ null, teamMemberName.trim()));
|
||||
}
|
||||
Team team = new TeamImpl(competitor.getName(), teamMembers, /* coach */ null);
|
||||
result = baseDomainFactory.getOrCreateCompetitor(getCompetitorID(competitor.getBoatID(), boatClass),
|
||||
result = baseDomainFactory.getOrCreateCompetitor(getCompetitorID(competitor.getBoatID(), raceType),
|
||||
competitor.getName(), team, boat);
|
||||
}
|
||||
return result;
|
||||
@@ -144,8 +143,8 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
|
||||
@Override
|
||||
public Competitor getOrCreateCompetitor(String boatID, String threeLetterIOCCode, String name,
|
||||
BoatClass boatClass) {
|
||||
return getOrCreateCompetitor(new CompetitorImpl(boatID, threeLetterIOCCode, name), boatClass);
|
||||
RaceType raceType) {
|
||||
return getOrCreateCompetitor(new CompetitorImpl(boatID, threeLetterIOCCode, name), raceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,7 +156,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
com.sap.sailing.domain.base.Course domainCourse = new CourseImpl("Course", waypoints);
|
||||
BoatClass boatClass = getOrCreateBoatClassFromRaceID(raceID);
|
||||
BoatClass boatClass = getRaceTypeFromRaceID(raceID).getBoatClass();
|
||||
logger.info("Creating RaceDefinitionImpl for race "+raceID);
|
||||
RaceDefinition result = new RaceDefinitionImpl(regatta.getId().toString()+"/"+raceID, domainCourse, boatClass, competitors);
|
||||
regatta.addRace(result);
|
||||
@@ -167,47 +166,36 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public RaceDefinition createRaceDefinition(Regatta regatta, Race race, StartList startList, Course course) {
|
||||
com.sap.sailing.domain.base.Course domainCourse = createCourse(race.getDescription(), course);
|
||||
BoatClass boatClass = getOrCreateBoatClassFromRaceID(race.getRaceID());
|
||||
Iterable<Competitor> competitors = createCompetitorList(startList, boatClass);
|
||||
RaceType raceType = getRaceTypeFromRaceID(race.getRaceID());
|
||||
Iterable<Competitor> competitors = createCompetitorList(startList, raceType);
|
||||
logger.info("Creating RaceDefinitionImpl for race "+race.getRaceID());
|
||||
RaceDefinition result = new RaceDefinitionImpl(race.getRaceID(), domainCourse,
|
||||
boatClass, competitors);
|
||||
raceType.getBoatClass(), competitors);
|
||||
regatta.addRace(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SwissTiming olympic race type or race type "UNKNOWN" when no corresponding olympic race type can be found.
|
||||
* Will never return null neither throw a content-related exception.
|
||||
*/
|
||||
@Override
|
||||
public BoatClass getOrCreateBoatClassFromRaceID(String raceID) {
|
||||
BoatClass result;
|
||||
/*
|
||||
SAM102000 Men's Windsurfer = Windsurfer Maenner RS:X
|
||||
SAW102000 Women's Windsurfer = Windsurfer Damen RS:X
|
||||
SAM004000 Men's One Person Dinghy = Laser Maenner
|
||||
SAW103000 Women's One Person Dinghy = Laser Damen Laser Radial
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy Maenner
|
||||
SAM005000 Men's Two Person Dinghy = 470er Maenner
|
||||
SAW005000 Women's Two Person Dinghy = 470er Damen
|
||||
SAM009000 Men's Skiff = 49er Maenner
|
||||
SAM007000 Men's Keelboat = Starboot Maenner
|
||||
SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified)
|
||||
*/
|
||||
if (raceID.toUpperCase().startsWith("SA") && raceID.length() == 9) {
|
||||
String classID = raceID.substring(3, 6);
|
||||
result = olympicClassesByID.get(classID);
|
||||
if (result == null) {
|
||||
// unknown code
|
||||
result = unknownBoatClass;
|
||||
public RaceType getRaceTypeFromRaceID(String raceID) {
|
||||
if (raceID != null && raceID.length() >= 6) {
|
||||
String swissTimingRaceCode = raceID.substring(0, 6).toUpperCase();
|
||||
RaceType result = raceTypeByID.get(swissTimingRaceCode);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
result = unknownBoatClass;
|
||||
}
|
||||
return result;
|
||||
//else
|
||||
return unknownRaceType;
|
||||
}
|
||||
|
||||
private Iterable<Competitor> createCompetitorList(StartList startList, BoatClass boatClass) {
|
||||
private Iterable<Competitor> createCompetitorList(StartList startList, RaceType raceType) {
|
||||
List<Competitor> result = new ArrayList<Competitor>();
|
||||
for (com.sap.sailing.domain.swisstimingadapter.Competitor swissTimingCompetitor : startList.getCompetitors()) {
|
||||
Competitor domainCompetitor = getOrCreateCompetitor(swissTimingCompetitor, boatClass);
|
||||
Competitor domainCompetitor = getOrCreateCompetitor(swissTimingCompetitor, raceType);
|
||||
result.add(domainCompetitor);
|
||||
}
|
||||
return result;
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
|
||||
public class RaceTypeImpl implements RaceType {
|
||||
|
||||
private final OlympicRaceCode raceCode;
|
||||
private final BoatClass boatClass;
|
||||
|
||||
public RaceTypeImpl(OlympicRaceCode raceCode, BoatClass boatClass) {
|
||||
this.raceCode = raceCode;
|
||||
this.boatClass = boatClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final OlympicRaceCode getRaceCode() {
|
||||
return raceCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClass getBoatClass() {
|
||||
return boatClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-7
@@ -13,7 +13,6 @@ import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
@@ -232,8 +231,8 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
trackedRace.recordFix(mark, gpsFix);
|
||||
break;
|
||||
case COMPETITOR:
|
||||
Competitor competitor = domainFactory.getCompetitorByBoatIDAndBoatClass(
|
||||
fix.getBoatID(), domainFactory.getOrCreateBoatClassFromRaceID(raceID));
|
||||
Competitor competitor = domainFactory.getCompetitorByBoatIDAndRaceID(
|
||||
fix.getBoatID(), raceID);
|
||||
DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(competitor);
|
||||
competitorTrack.addGPSFix(gpsFix);
|
||||
break;
|
||||
@@ -258,9 +257,8 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
List<Triple<Integer, Integer, Long>> markIndicesRanksAndTimesSinceStartInMilliseconds) {
|
||||
assert this.raceID.equals(raceID);
|
||||
if (isTrackedRaceStillReachable()) {
|
||||
final BoatClass boatClass = domainFactory.getOrCreateBoatClassFromRaceID(raceID);
|
||||
Competitor competitor = domainFactory.getCompetitorByBoatIDAndBoatClass(boatID,
|
||||
boatClass);
|
||||
Competitor competitor = domainFactory.getCompetitorByBoatIDAndRaceID(boatID,
|
||||
raceID);
|
||||
// the list of mark indices and time stamps is partial and usually only shows the last mark passing;
|
||||
// we need to use this to *update* the competitor's mark passings list, not *replace* it
|
||||
TreeMap<Integer, MarkPassing> markPassingsByMarkIndex = new TreeMap<Integer, MarkPassing>();
|
||||
@@ -288,7 +286,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
MillisecondsTimePoint timePoint = new MillisecondsTimePoint(
|
||||
startTime.asMillis() + markIndexRankAndTimeSinceStartInMilliseconds.getC());
|
||||
MarkPassing markPassing = domainFactory.createMarkPassing(timePoint, waypoint,
|
||||
domainFactory.getCompetitorByBoatIDAndBoatClass(boatID, boatClass));
|
||||
domainFactory.getCompetitorByBoatIDAndRaceID(boatID, raceID));
|
||||
markPassingsByMarkIndex.put(markIndexRankAndTimeSinceStartInMilliseconds.getA(), markPassing);
|
||||
} else {
|
||||
//
|
||||
|
||||
+2
-2
@@ -101,8 +101,8 @@ public class TMDMessageQueue {
|
||||
// otherwise, this could lead to the "guessed time" to
|
||||
while (i.hasNext()) {
|
||||
TMDMessageContents messageContents = i.next();
|
||||
Competitor competitor = raceTracker.getDomainFactory().getCompetitorByBoatIDAndBoatClass(messageContents.getBoatID(),
|
||||
trackedRace.getRace().getBoatClass());
|
||||
Competitor competitor = raceTracker.getDomainFactory().getCompetitorByBoatIDAndRaceID(messageContents.getBoatID(),
|
||||
messageContents.getRaceID());
|
||||
NavigableSet<MarkPassing> oldMarkPassings = trackedRace.getMarkPassings(competitor);
|
||||
TreeMap<Integer, MarkPassing> cleansedMarkPassingsForCompetitor = cleansedMarkPassings.get(competitor);
|
||||
if (cleansedMarkPassingsForCompetitor == null) {
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+22
-4
@@ -211,7 +211,8 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
@Test
|
||||
@Ignore
|
||||
public void printRaceData_SAM009903_20120731_sapsailing_replay() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM009903.20120731_sapsailing.replay"),
|
||||
new SwissTimingReplayParserImpl().readData(
|
||||
getClass().getResourceAsStream("/SAM009903.20120731_sapsailing.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
@@ -225,19 +226,36 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
@Test
|
||||
@Ignore
|
||||
public void printReadRaceData_SAW010955_20120802() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW010955.20120802.replay"), new SwissTimingReplayPrintListener());
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW010955.20120802.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void printReadRaceData_SAM002901() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM002901.replay"), new SwissTimingReplayPrintListener());
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM002901.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void printReadRaceData_SAM009904_20120731() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM009904.20120731.replay"), new SwissTimingReplayPrintListener());
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM009904.20120731.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void printRaceData_SAW102101_20120807() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW102101.20120807.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void printRaceData_SAM102101_20120807() throws Exception {
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAM102101.20120807.replay"),
|
||||
new SwissTimingReplayPrintListener());
|
||||
}
|
||||
|
||||
}
|
||||
+5
-6
@@ -15,7 +15,6 @@ import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
@@ -39,6 +38,7 @@ import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.CompetitorStatus;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayParser;
|
||||
@@ -83,6 +83,8 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
|
||||
*/
|
||||
private String currentRaceID;
|
||||
|
||||
private RaceType currentRaceType;
|
||||
|
||||
/**
|
||||
* Reference time point for time specifications
|
||||
*/
|
||||
@@ -158,10 +160,6 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
|
||||
return trackedRacePerRaceID.values();
|
||||
}
|
||||
|
||||
private BoatClass getCurrentBoatClass() {
|
||||
return domainFactory.getOrCreateBoatClassFromRaceID(currentRaceID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void referenceTimestamp(long referenceTimestampMillis) {
|
||||
referenceTimePoint = new MillisecondsTimePoint(referenceTimestampMillis);
|
||||
@@ -175,6 +173,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
|
||||
@Override
|
||||
public void raceID(String raceID) {
|
||||
currentRaceID = raceID;
|
||||
currentRaceType = domainFactory.getRaceTypeFromRaceID(currentRaceID);
|
||||
}
|
||||
|
||||
private boolean isValid(int threeByteValue) {
|
||||
@@ -236,7 +235,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
|
||||
short ctPoints_x10_Winner) {
|
||||
if (boatType == BoatType.Competitor) {
|
||||
Competitor competitor = domainFactory.getOrCreateCompetitor(sailNumberOrTrackerID, threeLetterIOCCode.trim(), name.trim(),
|
||||
getCurrentBoatClass());
|
||||
currentRaceType);
|
||||
Set<Competitor> competitorsOfCurrentRace = competitorsPerRaceID.get(currentRaceID);
|
||||
if (competitorsOfCurrentRace == null) {
|
||||
competitorsOfCurrentRace = new HashSet<>();
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class MediaTrackTest {
|
||||
|
||||
@Test
|
||||
public void testExactOverlap() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime());
|
||||
Date endTime = new Date(mediaTrack.deriveEndTime().getTime());
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoOverlapLeft() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() + 2);
|
||||
Date endTime = new Date(startTime.getTime() + 1);
|
||||
assertFalse(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoOverlapRight() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() - 2);
|
||||
Date endTime = new Date(startTime.getTime() + 1);
|
||||
assertFalse(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialOverlapLeft() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 2;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() - 1);
|
||||
Date endTime = new Date(startTime.getTime() + 2);
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialOverlapRight() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 2;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() + 1);
|
||||
Date endTime = new Date(startTime.getTime() + 2);
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediaFullyIncluded() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() - 1);
|
||||
Date endTime = new Date(startTime.getTime() + 3);
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediaFullyIncluding() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 3;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() + 1);
|
||||
Date endTime = new Date(startTime.getTime() + 1);
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlapOpenEndStartingEarlier() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() - 1);
|
||||
Date endTime = null; //--> open end
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlapOpenEndStartingLater() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 2;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() + 1);
|
||||
Date endTime = null; //--> open end
|
||||
assertTrue(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenEndNoOverlap() throws Exception {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 1;
|
||||
|
||||
Date startTime = new Date(mediaTrack.startTime.getTime() + 2);
|
||||
Date endTime = null; //--> open end
|
||||
assertFalse(mediaTrack.overlapsWith(startTime, endTime));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaUtil;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class MediaUtilTest {
|
||||
|
||||
@Test
|
||||
public void testCompareDatesAllNull() throws Exception {
|
||||
Date date1 = null;
|
||||
Date date2 = null;
|
||||
assertTrue(MediaUtil.compareDatesAllowingNull(date1, date2) == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareDatesFirstNull() throws Exception {
|
||||
Date date1 = null;
|
||||
Date date2 = new Date();
|
||||
assertTrue(MediaUtil.compareDatesAllowingNull(date1, date2) < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareDatesSecondNull() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = null;
|
||||
assertTrue(MediaUtil.compareDatesAllowingNull(date1, date2) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareDatesFirstGreaterSecond() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime() - 1);
|
||||
assertTrue(MediaUtil.compareDatesAllowingNull(date1, date2) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareDatesSecondGreaterFirst() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime() + 1);
|
||||
assertTrue(MediaUtil.compareDatesAllowingNull(date1, date2) < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsDatesAllNull() throws Exception {
|
||||
Date date1 = null;
|
||||
Date date2 = null;
|
||||
assertTrue(MediaUtil.equalsDatesAllowingNull(date1, date2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsDatesFirstNull() throws Exception {
|
||||
Date date1 = null;
|
||||
Date date2 = new Date();
|
||||
assertFalse(MediaUtil.equalsDatesAllowingNull(date1, date2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsDatesSecondNull() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = null;
|
||||
assertFalse(MediaUtil.equalsDatesAllowingNull(date1, date2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsDatesBothEqual() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime());
|
||||
assertTrue(MediaUtil.equalsDatesAllowingNull(date1, date2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsDatesNotEqual() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime() + 1);
|
||||
assertFalse(MediaUtil.equalsDatesAllowingNull(date1, date2));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDIwMjRtIC1EZ3d0LnVzZWFyY2hpdmVzPWZhbHNlXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVHZWaWV3PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlZpZGVvUG9wdXA8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuWW91dHViZVBvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlBvbGFyU2hlZXRzPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJlZ2F0dGFPdmVydmlldzwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TaW11bGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48L2d3dC1jb21waWxlLXNldHRpbmdzPg\=\=
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDIwMjRtIC1EZ3d0LnVzZWFyY2hpdmVzPWZhbHNlXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVHZWaWV3PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlZpZGVvUG9wdXA8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuWW91dHViZVBvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlBvbGFyU2hlZXRzPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJlZ2F0dGFPdmVydmlldzwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TaW11bGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48L2d3dC1jb21waWxlLXNldHRpbmdzPg\=\=
|
||||
@@ -1,43 +1,42 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing App GWT UI
|
||||
Bundle-SymbolicName: com.sap.sailing.gwt.ui
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence,
|
||||
com.sap.sailing.domain.tractracadapter.persistence,
|
||||
com.google.gwt.osgi;bundle-version="2.4.0",
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.resultimport,
|
||||
org.moxieapps.gwt.highcharts;bundle-version="1.5.0",
|
||||
com.sap.sailing.geocoding,
|
||||
com.sap.sailing.server.replication,
|
||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.freg.resultimport,
|
||||
com.sap.sailing.domain.swisstimingreplayadapter,
|
||||
com.sap.sailing.simulator;bundle-version="1.0.0"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: com.sap.sailing.gwt.ui.client.shared.media
|
||||
Import-Package: javax.jms;version="1.1.0",
|
||||
javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0",
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework,
|
||||
org.osgi.util.tracker
|
||||
Web-ContextPath: /gwt
|
||||
Bundle-ClassPath: WEB-INF/classes/,
|
||||
WEB-INF/lib/gwt-maps.jar,
|
||||
WEB-INF/lib/gwt-servlet.jar
|
||||
TrackLifecycle: true
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing App GWT UI
|
||||
Bundle-SymbolicName: com.sap.sailing.gwt.ui
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence,
|
||||
com.sap.sailing.domain.tractracadapter.persistence,
|
||||
com.google.gwt.osgi;bundle-version="2.4.0",
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.resultimport,
|
||||
org.moxieapps.gwt.highcharts;bundle-version="1.5.0",
|
||||
com.sap.sailing.geocoding,
|
||||
com.sap.sailing.server.replication,
|
||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.freg.resultimport,
|
||||
com.sap.sailing.domain.swisstimingreplayadapter,
|
||||
com.sap.sailing.simulator;bundle-version="1.0.0"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: javax.jms;version="1.1.0",
|
||||
javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0",
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework,
|
||||
org.osgi.util.tracker
|
||||
Web-ContextPath: /gwt
|
||||
Bundle-ClassPath: WEB-INF/classes/,
|
||||
WEB-INF/lib/gwt-maps.jar,
|
||||
WEB-INF/lib/gwt-servlet.jar
|
||||
TrackLifecycle: true
|
||||
+13
-3
@@ -21,8 +21,9 @@ import com.google.gwt.view.client.DefaultSelectionEventManager;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.google.gwt.view.client.SelectionModel;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaUtil;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
@@ -218,13 +219,22 @@ public class MediaPanel extends FlowPanel {
|
||||
startTimeColumn.setSortable(true);
|
||||
sortHandler.setComparator(startTimeColumn, new Comparator<MediaTrack>() {
|
||||
public int compare(MediaTrack mediaTrack1, MediaTrack mediaTrack2) {
|
||||
return mediaTrack1.startTime.compareTo(mediaTrack2.startTime);
|
||||
return MediaUtil.compareDatesAllowingNull(mediaTrack1.startTime, mediaTrack2.startTime);
|
||||
}
|
||||
});
|
||||
startTimeColumn.setFieldUpdater(new FieldUpdater<MediaTrack, String>() {
|
||||
public void update(int index, MediaTrack mediaTrack, String newStartTime) {
|
||||
// Called when the user changes the value.
|
||||
mediaTrack.startTime = TimeFormatUtil.DATETIME_FORMAT.parse(newStartTime);
|
||||
newStartTime = newStartTime.trim();
|
||||
if ("".equals(newStartTime)) {
|
||||
mediaTrack.startTime = null;
|
||||
} else {
|
||||
try {
|
||||
mediaTrack.startTime = TimeFormatUtil.DATETIME_FORMAT.parse(newStartTime);
|
||||
} catch (IllegalArgumentException e) {
|
||||
errorReporter.reportError(stringMessages.mediaDateFormatError(TimeFormatUtil.DATETIME_FORMAT.toString()));
|
||||
}
|
||||
}
|
||||
mediaService.updateStartTime(mediaTrack, new AsyncCallback<Void>() {
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -12,10 +12,10 @@ import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.MimeType;
|
||||
|
||||
public class MediaTrackDialog extends DataEntryDialog<MediaTrack> {
|
||||
|
||||
|
||||
+2
-2
@@ -10,10 +10,10 @@ import com.google.gwt.user.client.ui.TextArea;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.MimeType;
|
||||
|
||||
public class MediaTrackYoutubeDialog extends DataEntryDialog<MediaTrack> {
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public interface MediaPlayer {
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.Collection;
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
@RemoteServiceRelativePath("media")
|
||||
public interface MediaService extends RemoteService {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.util.Collection;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public interface MediaServiceAsync {
|
||||
|
||||
|
||||
+1
@@ -586,6 +586,7 @@ public interface StringMessages extends Messages {
|
||||
String loading();
|
||||
String showHiddenRaces();
|
||||
String selectedCompetitors();
|
||||
String mediaDateFormatError(String expectedTimeFormat);
|
||||
String filterNothing();
|
||||
String topNCompetitorsByRaceRank(int n);
|
||||
String topNCompetitorsByTotalRank(int n);
|
||||
|
||||
+2
-1
@@ -588,6 +588,7 @@ enableRaceFilter=Enable filter
|
||||
raceStatusColumn=Race Status
|
||||
loading=Loading (on a slow internet connection this can take some minutes)...
|
||||
showHiddenRaces=Show HIDDEN races
|
||||
mediaDateFormatError=Invalid date format. Use: {0}
|
||||
selectedCompetitors=Selected competitors
|
||||
filterNothing=Filter nothing
|
||||
topNCompetitorsByRaceRank=Race Top {0}
|
||||
@@ -645,4 +646,4 @@ showOnlyCurrentlyRunningRaces=Show currently running races
|
||||
seriesDefinesResultDiscardingRule=Series defines result discarding rules
|
||||
addSeries=Add series
|
||||
regattaDefinesResultDiscardingRules=Regatta defines result discarding rules
|
||||
startsWithZeroScore=Series starts with zero score
|
||||
startsWithZeroScore=Series starts with zero score
|
||||
+1
-1
@@ -2,8 +2,8 @@ package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.MediaPlayer;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
|
||||
public abstract class AbstractMediaPlayer implements MediaPlayer {
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.sap.sailing.gwt.ui.raceboard;
|
||||
import com.google.gwt.dom.client.AudioElement;
|
||||
import com.google.gwt.dom.client.MediaElement;
|
||||
import com.google.gwt.media.client.Audio;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public class AudioPlayer extends AbstractMediaPlayer {
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import com.google.gwt.user.client.ui.RadioButton;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public class MediaSelectionDialog implements CloseHandler<PopupPanel> {
|
||||
|
||||
|
||||
+5
-5
@@ -25,6 +25,9 @@ import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MediaType;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.Status;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.MediaPlayer;
|
||||
import com.sap.sailing.gwt.ui.client.PlayStateListener;
|
||||
@@ -32,9 +35,6 @@ import com.sap.sailing.gwt.ui.client.RaceTimesInfoProviderListener;
|
||||
import com.sap.sailing.gwt.ui.client.TimeListener;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.MediaType;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.Status;
|
||||
import com.sap.sailing.gwt.ui.raceboard.MediaSelectionDialog.MediaSelectionListener;
|
||||
import com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer.PopupCloseListener;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
@@ -143,10 +143,10 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
|
||||
native void addLoadMetadataHandler(MediaElement mediaElement, MediaTrack mediaTrack) /*-{
|
||||
var that = this;
|
||||
mediaElement.addEventListener('loadedmetadata', function() {
|
||||
that.@com.sap.sailing.gwt.ui.raceboard.MediaSelector::loadedmetadata(Lcom/sap/sailing/gwt/ui/client/shared/media/MediaTrack;)(mediaTrack);
|
||||
that.@com.sap.sailing.gwt.ui.raceboard.MediaSelector::loadedmetadata(Lcom/sap/sailing/domain/common/media/MediaTrack;)(mediaTrack);
|
||||
});
|
||||
mediaElement.addEventListener('error', function() {
|
||||
that.@com.sap.sailing.gwt.ui.raceboard.MediaSelector::mediaError(Lcom/sap/sailing/gwt/ui/client/shared/media/MediaTrack;)(mediaTrack);
|
||||
that.@com.sap.sailing.gwt.ui.raceboard.MediaSelector::mediaError(Lcom/sap/sailing/domain/common/media/MediaTrack;)(mediaTrack);
|
||||
});
|
||||
}-*/;
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public abstract class PopupWindowPlayer extends AbstractMediaPlayer {
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.http.client.URL;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public class VideoWindowPlayer extends PopupWindowPlayer {
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.http.client.URL;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public class YoutubeWindowPlayer extends PopupWindowPlayer {
|
||||
|
||||
|
||||
+17
-59
@@ -2,24 +2,15 @@ package com.sap.sailing.gwt.ui.server;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.persistence.media.DBMediaTrack;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class MediaServiceImpl extends RemoteServiceServlet implements MediaService {
|
||||
@@ -31,7 +22,7 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
|
||||
private ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
|
||||
|
||||
private static final long serialVersionUID = -8917349579281305977L;
|
||||
|
||||
|
||||
public MediaServiceImpl() {
|
||||
super();
|
||||
BundleContext context = Activator.getDefault();
|
||||
@@ -40,83 +31,50 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
|
||||
racingEventServiceTracker.open();
|
||||
}
|
||||
|
||||
private RacingEventService racingEventService() {
|
||||
return racingEventServiceTracker.getService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier) {
|
||||
TrackedRace trackedRace = racingEventServiceTracker.getService().getExistingTrackedRace(regattaAndRaceIdentifier);
|
||||
if (trackedRace != null) {
|
||||
Date raceStart = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
|
||||
Date raceEnd = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
|
||||
return createMediaTracksFromDB(mediaDB().queryOverlappingMediaTracks(raceStart , raceEnd));
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return racingEventService().getMediaTracksForRace(regattaAndRaceIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MediaTrack> getAllMediaTracks() {
|
||||
List<DBMediaTrack> allDBMediaTracks = mediaDB().loadAllMediaTracks();
|
||||
Collection<MediaTrack> result = createMediaTracksFromDB(allDBMediaTracks);
|
||||
return result;
|
||||
// try {
|
||||
// Date date = dateFormat.parse("2012-09-15 14:42:10 +0100");
|
||||
// return Arrays
|
||||
// .asList(new MediaTrack[] { new MediaTrack(
|
||||
// MediaType.VIDEO,
|
||||
// "Day 2 Final - 49er Europeans 2012",
|
||||
// "http://localhost:8888/media/HTML5/1809147112001_1842870496001_SAP-Regatta-Day02-Final_libtheora.ogv",
|
||||
// date) });
|
||||
// } catch (ParseException e) {
|
||||
// throw new RuntimeException(e); // just due to annoying date parse error potential
|
||||
// }
|
||||
}
|
||||
|
||||
private Collection<MediaTrack> createMediaTracksFromDB(Collection<DBMediaTrack> allDBMediaTracks) {
|
||||
Collection<MediaTrack> result = new ArrayList<MediaTrack>();
|
||||
for (DBMediaTrack dbMediaTrack : allDBMediaTracks) {
|
||||
MediaTrack mediaTrack = createMediaTrackFromDB(dbMediaTrack);
|
||||
result.add(mediaTrack );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private MediaTrack createMediaTrackFromDB(DBMediaTrack dbMediaTrack) {
|
||||
MimeType mimeType = dbMediaTrack.mimeType != null ? MimeType.valueOf(dbMediaTrack.mimeType) : null;
|
||||
MediaTrack mediaTrack = new MediaTrack(dbMediaTrack.dbId, dbMediaTrack.title, dbMediaTrack.url, dbMediaTrack.startTime, dbMediaTrack.durationInMillis, mimeType);
|
||||
return mediaTrack;
|
||||
return racingEventService().getAllMediaTracks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMediaTrack(MediaTrack mediaTrack) {
|
||||
String mimeType = mediaTrack.mimeType != null ? mediaTrack.mimeType.name() : null;
|
||||
mediaDB().insertMediaTrack(mediaTrack.title, mediaTrack.url, mediaTrack.startTime, mediaTrack.durationInMillis, mimeType);
|
||||
}
|
||||
|
||||
private MediaDB mediaDB() {
|
||||
return MediaDBFactory.INSTANCE.getDefaultMediaDB();
|
||||
if (mediaTrack.dbId != null) {
|
||||
throw new IllegalStateException("Property dbId must not be null for newly created media track.");
|
||||
}
|
||||
racingEventService().mediaTrackAdded(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMediaTrack(MediaTrack mediaTrack) {
|
||||
mediaDB().deleteMediaTrack(mediaTrack.dbId);
|
||||
racingEventService().mediaTrackDeleted(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTitle(MediaTrack mediaTrack) {
|
||||
mediaDB().updateTitle(mediaTrack.dbId, mediaTrack.title);
|
||||
racingEventService().mediaTrackTitleChanged(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUrl(MediaTrack mediaTrack) {
|
||||
mediaDB().updateUrl(mediaTrack.dbId, mediaTrack.url);
|
||||
racingEventService().mediaTrackUrlChanged(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStartTime(MediaTrack mediaTrack) {
|
||||
mediaDB().updateStartTime(mediaTrack.dbId, mediaTrack.startTime);
|
||||
racingEventService().mediaTrackStartTimeChanged(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDuration(MediaTrack mediaTrack) {
|
||||
mediaDB().updateDuration(mediaTrack.dbId, mediaTrack.durationInMillis);
|
||||
racingEventService().mediaTrackDurationChanged(mediaTrack);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1913,7 +1913,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
List<SwissTimingRaceRecordDTO> result = new ArrayList<SwissTimingRaceRecordDTO>();
|
||||
for (com.sap.sailing.domain.swisstimingadapter.RaceRecord rr : getService().getSwissTimingRaceRecords(hostname, port, canSendRequests)) {
|
||||
SwissTimingRaceRecordDTO swissTimingRaceRecordDTO = new SwissTimingRaceRecordDTO(rr.getRaceID(), rr.getDescription(), rr.getStartTime());
|
||||
BoatClass boatClass = com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE.getOrCreateBoatClassFromRaceID(rr.getRaceID());
|
||||
BoatClass boatClass = com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE.getRaceTypeFromRaceID(rr.getRaceID()).getBoatClass();
|
||||
swissTimingRaceRecordDTO.boatClass = boatClass != null ? boatClass.getName() : null;
|
||||
swissTimingRaceRecordDTO.discipline = rr.getRaceID().length() >= 3 ? rr.getRaceID().substring(2, 3) : null;
|
||||
result.add(swissTimingRaceRecordDTO);
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.sap.sailing.media.persistence.test;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.core.Is;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.domain.persistence.media.DBMediaTrack;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class MediaDBTest extends AbstractMongoDBTest {
|
||||
|
||||
public MediaDBTest() throws UnknownHostException, MongoException {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVideoTrack() {
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "http://localhost:8888/media/HTML5/1809147112001_1842870496001_SAP-Regatta-Day02-Final_libtheora.ogv";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
|
||||
DBMediaTrack videoTrack = mongoDB.loadAllMediaTracks().iterator().next();
|
||||
assertNotNull(videoTrack);
|
||||
assertThat(videoTrack.dbId, Is.is(dbId));
|
||||
assertThat(videoTrack.title, Is.is(videoTitle));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAllVideoTracks() {
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
int testEntryCount = 10;
|
||||
storeNumberOfTestMediaTracks(mongoDB, testEntryCount);
|
||||
List<DBMediaTrack> allMediaTracks = mongoDB.loadAllMediaTracks();
|
||||
assertThat(allMediaTracks.size(), is(testEntryCount));
|
||||
}
|
||||
|
||||
private void storeNumberOfTestMediaTracks(MediaDB mongoDB, int count) {
|
||||
final String videoTitleTemplate = "Test Video ";
|
||||
final String url = "http://localhost:8888/media/HTML5/1809147112001_1842870496001_SAP-Regatta-Day02-Final_libtheora.ogv";
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
mongoDB.insertMediaTrack(videoTitleTemplate + i, url, date, durationInMillis, mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteVideoTrack() {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
|
||||
|
||||
//delete
|
||||
mongoDB.deleteMediaTrack(dbId);
|
||||
|
||||
//assert not exists --> RuntimeException
|
||||
assertThat(mongoDB.loadAllMediaTracks().size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateStartTime() {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date originalDate = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, originalDate, durationInMillis, mimeType);
|
||||
|
||||
//update with new date
|
||||
Date newDate = new Date(originalDate.getTime() + 1000);
|
||||
mongoDB.updateStartTime(dbId, newDate);
|
||||
|
||||
//assert start time is updated and everything else preserved
|
||||
DBMediaTrack videoTrack = mongoDB.loadAllMediaTracks().iterator().next();
|
||||
assertThat(videoTrack.startTime, is(newDate));
|
||||
assertThat(videoTrack.durationInMillis, is(durationInMillis));
|
||||
assertThat(videoTrack.title, is(videoTitle));
|
||||
assertThat(videoTrack.url, is(url));
|
||||
assertThat(videoTrack.mimeType, is(mimeType));
|
||||
}
|
||||
|
||||
}
|
||||
-223
@@ -1,223 +0,0 @@
|
||||
package com.sap.sailing.media.persistence.test;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.core.Is;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.persistence.media.DBMediaTrack;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.gwt.ui.client.shared.media.MediaTrack.MimeType;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class TestMediaDB extends AbstractMongoDBTest {
|
||||
|
||||
private static final int FIFTEEN_MINUTES_IN_MILLIS = 15 * 60 * 1000;
|
||||
private static final int THIRTY_MINUTES_IN_MILLIS = 30 * 60 * 1000;
|
||||
private static final int ONE_HOUR_IN_MILLIS = 60 * 60 * 1000;
|
||||
|
||||
// private static final Logger logger = Logger.getLogger(TestCRUDMedia.class.getName());
|
||||
|
||||
public TestMediaDB() throws UnknownHostException, MongoException {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVideoTrack() {
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "http://localhost:8888/media/HTML5/1809147112001_1842870496001_SAP-Regatta-Day02-Final_libtheora.ogv";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
|
||||
DBMediaTrack videoTrack = mongoDB.loadMediaTrack(dbId);
|
||||
assertNotNull(videoTrack);
|
||||
assertThat(videoTrack.title, Is.is(videoTitle));
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testFailReadMissingVideoTrack() {
|
||||
final String dbId = "non-existing id";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
mongoDB.loadMediaTrack(dbId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAllVideoTracks() {
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
int testEntryCount = 10;
|
||||
storeNumberOfTestMediaTracks(mongoDB, testEntryCount);
|
||||
List<DBMediaTrack> allMediaTracks = mongoDB.loadAllMediaTracks();
|
||||
assertThat(allMediaTracks.size(), is(testEntryCount));
|
||||
}
|
||||
|
||||
private void storeNumberOfTestMediaTracks(MediaDB mongoDB, int count) {
|
||||
final String videoTitleTemplate = "Test Video ";
|
||||
final String url = "http://localhost:8888/media/HTML5/1809147112001_1842870496001_SAP-Regatta-Day02-Final_libtheora.ogv";
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
mongoDB.insertMediaTrack(videoTitleTemplate + i, url, date, durationInMillis, mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=RuntimeException.class)
|
||||
public void testDeleteVideoTrack() {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date date = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
|
||||
|
||||
//delete
|
||||
mongoDB.deleteMediaTrack(videoTitle);
|
||||
|
||||
//assert not exists --> RuntimeException
|
||||
mongoDB.loadMediaTrack(dbId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateStartTime() {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
Date originalDate = new Date();
|
||||
int durationInMillis = 23;
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, originalDate, durationInMillis, mimeType);
|
||||
|
||||
//update with new date
|
||||
Date newDate = new Date(originalDate.getTime() + 1000);
|
||||
mongoDB.updateStartTime(dbId, newDate);
|
||||
|
||||
//assert start time is updated and everything else preserved
|
||||
DBMediaTrack videoTrack = mongoDB.loadMediaTrack(dbId);
|
||||
assertThat(videoTrack.startTime, is(newDate));
|
||||
assertThat(videoTrack.durationInMillis, is(durationInMillis));
|
||||
assertThat(videoTrack.title, is(videoTitle));
|
||||
assertThat(videoTrack.url, is(url));
|
||||
assertThat(videoTrack.mimeType, is(mimeType));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_MatchingStartTimes_TrackLongerThanEndTime() {
|
||||
Date startTime = new Date();
|
||||
int duration = ONE_HOUR_IN_MILLIS;
|
||||
Date rangeStart = startTime;
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_MatchingStartTimes_TrackShorterThanEndTime() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = startTime;
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsBeforeEndsAfterRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = ONE_HOUR_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsAfterEndsBeforeRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
int duration = FIFTEEN_MINUTES_IN_MILLIS;
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsAfterEndsAfterRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsBeforeEndsBeforeRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_TrackEndsBeforeRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + duration + 1);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
|
||||
assertNoOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_TrackStartsAfterRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
|
||||
assertNoOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
private void assertOverlap(Date startTime, int oneHourInMillis, Date rangeStart, Date rangeEnd) {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
String mimeType = MimeType.ogv.name();
|
||||
String dbId = mongoDB.insertMediaTrack(videoTitle, url, startTime, oneHourInMillis, mimeType);
|
||||
|
||||
Collection<DBMediaTrack> videoTracks = mongoDB.queryOverlappingMediaTracks(rangeStart, rangeEnd);
|
||||
assertThat(videoTracks.size(), is(1));
|
||||
assertThat(videoTracks.iterator().next().dbId, is(dbId));
|
||||
}
|
||||
|
||||
private void assertNoOverlap(Date startTime, int oneHourInMillis, Date rangeStart, Date rangeEnd) {
|
||||
//insert test object
|
||||
final String videoTitle = "Test Video";
|
||||
final String url = "test";
|
||||
MediaDB mongoDB = MediaDBFactory.INSTANCE.getMediaDB(getMongoService());
|
||||
String mimeType = MimeType.ogv.name();
|
||||
mongoDB.insertMediaTrack(videoTitle, url, startTime, oneHourInMillis, mimeType);
|
||||
|
||||
Collection<DBMediaTrack> videoTracks = mongoDB.queryOverlappingMediaTracks(rangeStart, rangeEnd);
|
||||
assertThat(videoTracks.size(), is(0));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,4 +20,5 @@ Require-Bundle: com.sap.sailing.server,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.json.simple;bundle-version="1.1.0"
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
org.hamcrest;bundle-version="1.1.0"
|
||||
+17
@@ -3,10 +3,13 @@ package com.sap.sailing.server.replication.test;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -25,6 +28,8 @@ import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.test.TrackBasedTest;
|
||||
import com.sap.sailing.mongodb.MongoDBService;
|
||||
@@ -99,6 +104,14 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
|
||||
assertNotNull(master.getLeaderboardGroupByName(leaderBoardGroupName));
|
||||
assertNull(replica.getLeaderboardGroupByName(leaderBoardGroupName));
|
||||
|
||||
/* Media Library */
|
||||
MediaTrack mediaTrack1 = new MediaTrack("title-1", "url", new Date(), 1, MimeType.mp4);
|
||||
master.mediaTrackAdded(mediaTrack1);
|
||||
MediaTrack mediaTrack2 = new MediaTrack("title-2", "url", new Date(), 1, MimeType.ogv);
|
||||
master.mediaTrackAdded(mediaTrack2);
|
||||
MediaTrack mediaTrack3 = new MediaTrack("title-3", "url", new Date(), 1, MimeType.mp4);
|
||||
master.mediaTrackAdded(mediaTrack3);
|
||||
|
||||
/* fire up replication */
|
||||
performReplicationSetup();
|
||||
ReplicationMasterDescriptor the_master = replicationDescriptorPair.getB(); /* master descriptor */
|
||||
@@ -116,6 +129,10 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
|
||||
assertNotNull(replica.getLeaderboardGroupByName(leaderBoardGroupName));
|
||||
assertNotNull(replica.getLeaderboardByName(leaderboardName));
|
||||
assertTrue(replica.getAllRegattas().iterator().hasNext());
|
||||
|
||||
//System.out.println("InitialLoadReplicationObjectIdentityTest.testInitialLoad - replica.getAllMediaTracks: " + replica.getAllMediaTracks());
|
||||
|
||||
assertThat(replica.getAllMediaTracks().size(), is(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.sap.sailing.server.replication.test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class MediaReplicationTest extends AbstractServerReplicationTest {
|
||||
|
||||
private void waitSomeTime() throws InterruptedException {
|
||||
Thread.sleep(1000); // wait for JMS to deliver the message and the message to be applied
|
||||
}
|
||||
|
||||
/* util */
|
||||
private MediaTrack createMediaTrack() {
|
||||
String title = "title";
|
||||
String url = "url";
|
||||
Date startTime = new Date();
|
||||
int durationInMillis = 1;
|
||||
MimeType mimeType = MimeType.mp4;
|
||||
MediaTrack mediaTrack = new MediaTrack(title, url, startTime, durationInMillis, mimeType);
|
||||
return mediaTrack;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicInitialLoad() throws Exception {
|
||||
assertNotSame(master, replica);
|
||||
assertEquals(master.getAllMediaTracks().size(), replica.getAllMediaTracks().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddMediaTrackReplication() throws InterruptedException {
|
||||
assertThat(master.getAllMediaTracks().size(), is(0));
|
||||
assertThat(replica.getAllMediaTracks().size(), is(0));
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
assertThat(master.getAllMediaTracks().size(), is(1));
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMediaTrackReplication() throws InterruptedException {
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
master.mediaTrackDeleted(mediaTrack);
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMediaTrackTitleReplication() throws InterruptedException {
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
mediaTrack.title = mediaTrack.title + "x";
|
||||
master.mediaTrackTitleChanged(mediaTrack);
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(1));
|
||||
assertThat(replica.getAllMediaTracks().iterator().next().title, is(mediaTrack.title));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMediaTrackUrlReplication() throws InterruptedException {
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
mediaTrack.url = mediaTrack.url + "x";
|
||||
master.mediaTrackUrlChanged(mediaTrack);
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(1));
|
||||
assertThat(replica.getAllMediaTracks().iterator().next().url, is(mediaTrack.url));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMediaTrackStartTimeReplication() throws InterruptedException {
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
mediaTrack.startTime = new Date(mediaTrack.startTime.getTime() + 1000);
|
||||
master.mediaTrackStartTimeChanged(mediaTrack);
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(1));
|
||||
assertThat(replica.getAllMediaTracks().iterator().next().startTime, is(mediaTrack.startTime));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMediaTrackDurationReplication() throws InterruptedException {
|
||||
MediaTrack mediaTrack = createMediaTrack();
|
||||
master.mediaTrackAdded(mediaTrack);
|
||||
mediaTrack.durationInMillis = mediaTrack.durationInMillis + 1000;
|
||||
master.mediaTrackDurationChanged(mediaTrack);
|
||||
waitSomeTime();
|
||||
assertThat(replica.getAllMediaTracks().size(), is(1));
|
||||
assertThat(replica.getAllMediaTracks().iterator().next().durationInMillis, is(mediaTrack.durationInMillis));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,9 +15,9 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.mongodb,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.test
|
||||
com.sap.sailing.domain.test,
|
||||
org.hamcrest;bundle-version="1.1.0"
|
||||
Import-Package: junit.framework;version="4.8.1",
|
||||
org.junit;version="4.8.1",
|
||||
org.json.simple
|
||||
Export-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.impl
|
||||
Export-Package: com.sap.sailing.server.impl
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
package com.sap.sailing.server.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.server.impl.MediaLibrary.Interval;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
|
||||
public class MediaLibaryTest {
|
||||
|
||||
private static final int FIFTEEN_MINUTES_IN_MILLIS = 15 * 60 * 1000;
|
||||
private static final int THIRTY_MINUTES_IN_MILLIS = 30 * 60 * 1000;
|
||||
private static final int ONE_HOUR_IN_MILLIS = 60 * 60 * 1000;
|
||||
|
||||
private MediaLibrary mediaLibary;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.mediaLibary = new MediaLibrary();
|
||||
}
|
||||
|
||||
/* util */
|
||||
private MediaTrack createMediaTrack(String dbId) {
|
||||
String title = "title";
|
||||
String url = "url";
|
||||
Date startTime = new Date();
|
||||
int durationInMillis = 1;
|
||||
MimeType mimeType = MimeType.mp4;
|
||||
MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, durationInMillis, mimeType);
|
||||
return mediaTrack;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetElementsFromEmtpy() throws Exception {
|
||||
assertThat(this.mediaLibary.allTracks().size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateOneElement() throws Exception {
|
||||
String dbId = "1234";
|
||||
MediaTrack mediaTrack = createMediaTrack(dbId);
|
||||
this.mediaLibary.addMediaTrack(mediaTrack);
|
||||
Iterator<MediaTrack> allMediaTracks = this.mediaLibary.allTracks().iterator();
|
||||
assertThat(allMediaTracks.hasNext(), is(true));
|
||||
MediaTrack item = allMediaTracks.next();
|
||||
assertThat(allMediaTracks.hasNext(), is(false));
|
||||
assertTrue(item.equals(mediaTrack));
|
||||
assertThat(item.title, is(mediaTrack.title));
|
||||
assertThat(item.url, is(mediaTrack.url));
|
||||
assertThat(item.startTime, is(mediaTrack.startTime));
|
||||
assertThat(item.durationInMillis, is(mediaTrack.durationInMillis));
|
||||
assertThat(item.mimeType, is(mediaTrack.mimeType));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDeleteOneElement() throws Exception {
|
||||
String dbId = "1234";
|
||||
MediaTrack mediaTrack = createMediaTrack(dbId);
|
||||
this.mediaLibary.addMediaTrack(mediaTrack);
|
||||
this.mediaLibary.deleteMediaTrack(mediaTrack);
|
||||
Collection<MediaTrack> allMediaTracks = this.mediaLibary.allTracks();
|
||||
assertThat(allMediaTracks.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_MatchingStartTimes_TrackLongerThanEndTime() {
|
||||
Date startTime = new Date();
|
||||
int duration = ONE_HOUR_IN_MILLIS;
|
||||
Date rangeStart = startTime;
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_MatchingStartTimes_TrackShorterThanEndTime() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = startTime;
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsBeforeEndsAfterRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = ONE_HOUR_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsAfterEndsBeforeRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
int duration = FIFTEEN_MINUTES_IN_MILLIS;
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsAfterEndsAfterRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_StartsBeforeEndsBeforeRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + FIFTEEN_MINUTES_IN_MILLIS);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
|
||||
assertOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_TrackEndsBeforeRange() {
|
||||
Date startTime = new Date();
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
Date rangeStart = new Date(startTime.getTime() + duration + 1);
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
|
||||
assertNoOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMediaTracksBetween_TrackStartsAfterRange() {
|
||||
Date rangeStart = new Date();
|
||||
Date rangeEnd = new Date(rangeStart.getTime() + THIRTY_MINUTES_IN_MILLIS);
|
||||
Date startTime = new Date(rangeStart.getTime() + ONE_HOUR_IN_MILLIS);
|
||||
int duration = THIRTY_MINUTES_IN_MILLIS;
|
||||
|
||||
assertNoOverlap(startTime, duration, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheChangeStartTime() {
|
||||
MediaTrack originalMediaTrack = new MediaTrack();
|
||||
originalMediaTrack.dbId = "a";
|
||||
originalMediaTrack.startTime = new Date();
|
||||
originalMediaTrack.durationInMillis = 100;
|
||||
|
||||
Date queryStartTime = new Date(originalMediaTrack.startTime.getTime() + 1);
|
||||
Date queryEndTime = new Date(originalMediaTrack.deriveEndTime().getTime() - 1);
|
||||
|
||||
mediaLibary.addMediaTrack(originalMediaTrack);
|
||||
|
||||
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksInTimeRange(queryStartTime, queryEndTime);
|
||||
assertThat(firstQueryResult.size(), is(1));
|
||||
|
||||
MediaTrack changedMediaTrack = new MediaTrack();
|
||||
changedMediaTrack.dbId = "a";
|
||||
changedMediaTrack.startTime = new Date(originalMediaTrack.startTime.getTime() + 101);
|
||||
changedMediaTrack.durationInMillis = 100;
|
||||
mediaLibary.startTimeChanged(changedMediaTrack);
|
||||
|
||||
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksInTimeRange(queryStartTime, queryEndTime);
|
||||
assertThat(secondQueryResult.size(), is(0));
|
||||
|
||||
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksInTimeRange(changedMediaTrack.startTime, changedMediaTrack.deriveEndTime());
|
||||
assertThat(thirdQueryResult.size(), is(1));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheRemoveMediaTrack() {
|
||||
MediaTrack mediaTrack = new MediaTrack();
|
||||
mediaTrack.dbId = "a";
|
||||
mediaTrack.startTime = new Date();
|
||||
mediaTrack.durationInMillis = 100;
|
||||
|
||||
Date originalStartTime = mediaTrack.startTime;
|
||||
Date originalEndTime = mediaTrack.deriveEndTime();
|
||||
|
||||
mediaLibary.addMediaTrack(mediaTrack);
|
||||
|
||||
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksInTimeRange(originalStartTime, originalEndTime);
|
||||
assertThat(firstQueryResult.size(), is(1));
|
||||
|
||||
mediaLibary.deleteMediaTrack(mediaTrack);
|
||||
|
||||
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksInTimeRange(originalStartTime, originalEndTime);
|
||||
assertThat(secondQueryResult.size(), is(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheAddSecondMediaTrackWithSameInterval() {
|
||||
MediaTrack firstMediaTrack = new MediaTrack();
|
||||
firstMediaTrack.dbId = "a";
|
||||
firstMediaTrack.startTime = new Date();
|
||||
firstMediaTrack.durationInMillis = 100;
|
||||
mediaLibary.addMediaTrack(firstMediaTrack);
|
||||
|
||||
Date queryStartTime = new Date(firstMediaTrack.startTime.getTime() + 1);
|
||||
Date queryEndTime = new Date(firstMediaTrack.deriveEndTime().getTime() - 1);
|
||||
|
||||
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksInTimeRange(queryStartTime, queryEndTime);
|
||||
assertThat(firstQueryResult.size(), is(1));
|
||||
|
||||
MediaTrack secondMediaTrack = new MediaTrack();
|
||||
secondMediaTrack.dbId = "b";
|
||||
secondMediaTrack.startTime = firstMediaTrack.startTime;
|
||||
secondMediaTrack.durationInMillis = firstMediaTrack.durationInMillis;
|
||||
mediaLibary.addMediaTrack(secondMediaTrack);
|
||||
|
||||
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksInTimeRange(queryStartTime, queryEndTime);
|
||||
assertThat(secondQueryResult.size(), is(2));
|
||||
|
||||
Date uncachedStartTime = new Date(firstMediaTrack.startTime.getTime() + 2);
|
||||
Date uncachedEndTime = new Date(firstMediaTrack.deriveEndTime().getTime() - 2);
|
||||
|
||||
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksInTimeRange(uncachedStartTime, uncachedEndTime);
|
||||
assertThat(thirdQueryResult.size(), is(2));
|
||||
}
|
||||
|
||||
private void assertOverlap(Date startTime, int durationInMillis, Date rangeStart, Date rangeEnd) {
|
||||
//insert test object
|
||||
String dbId = "1234";
|
||||
String title = "title";
|
||||
String url = "url";
|
||||
MimeType mimeType = MimeType.mp4;
|
||||
MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, durationInMillis, mimeType);
|
||||
mediaLibary.addMediaTrack(mediaTrack);
|
||||
|
||||
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksInTimeRange(rangeStart, rangeEnd);
|
||||
assertThat(mediaTracks.size(), is(1));
|
||||
assertThat(mediaTracks.iterator().next().dbId, is(dbId));
|
||||
}
|
||||
|
||||
private void assertNoOverlap(Date startTime, int durationInMillis, Date rangeStart, Date rangeEnd) {
|
||||
//insert test object
|
||||
String dbId = "1234";
|
||||
String title = "title";
|
||||
String url = "url";
|
||||
MimeType mimeType = MimeType.mp4;
|
||||
MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, durationInMillis, mimeType);
|
||||
mediaLibary.addMediaTrack(mediaTrack);
|
||||
|
||||
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksInTimeRange(rangeStart, rangeEnd);
|
||||
assertThat(mediaTracks.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntervalEqualsIdentical() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime() + 1);
|
||||
Interval interval = new Interval(date1, date2);
|
||||
assertTrue(interval.equals(interval));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntervalEqualsSame() throws Exception {
|
||||
Date date1_1 = new Date();
|
||||
Date date1_2 = new Date(date1_1.getTime() + 1);
|
||||
Date date2_1 = new Date(date1_1.getTime());
|
||||
Date date2_2 = new Date(date1_2.getTime());
|
||||
Interval interval1 = new Interval(date1_1, date1_2);
|
||||
Interval interval2 = new Interval(date2_1, date2_2);
|
||||
assertTrue(interval1.equals(interval2));
|
||||
assertEquals(interval1.hashCode(), interval2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntervalEqualsNull() throws Exception {
|
||||
Date date1 = new Date();
|
||||
Date date2 = new Date(date1.getTime() + 1);
|
||||
Interval interval = new Interval(date1, date2);
|
||||
assertFalse(interval.equals(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntervalNotEquals() throws Exception {
|
||||
Date date1_1 = new Date();
|
||||
Date date1_2 = new Date(date1_1.getTime() + 1);
|
||||
Date date2_1 = new Date(date1_1.getTime() + 2);
|
||||
Date date2_2 = new Date(date1_1.getTime() + 3);
|
||||
Interval interval1 = new Interval(date1_1, date1_2);
|
||||
Interval interval2 = new Interval(date2_1, date2_2);
|
||||
assertFalse(interval1.equals(interval2));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,6 @@
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator*1.0.0.qualifier@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||
</launchConfiguration>
|
||||
@@ -12,11 +12,11 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
@@ -34,6 +34,7 @@ import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
@@ -501,4 +502,22 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
|
||||
|
||||
CourseArea getCourseArea(Serializable courseAreaId);
|
||||
|
||||
void mediaTrackAdded(MediaTrack mediaTrack);
|
||||
|
||||
void mediaTracksAdded(Collection<MediaTrack> mediaTracks);
|
||||
|
||||
void mediaTrackTitleChanged(MediaTrack mediaTrack);
|
||||
|
||||
void mediaTrackUrlChanged(MediaTrack mediaTrack);
|
||||
|
||||
void mediaTrackStartTimeChanged(MediaTrack mediaTrack);
|
||||
|
||||
void mediaTrackDurationChanged(MediaTrack mediaTrack);
|
||||
|
||||
void mediaTrackDeleted(MediaTrack mediaTrack);
|
||||
|
||||
Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier);
|
||||
|
||||
Collection<MediaTrack> getAllMediaTracks();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
package com.sap.sailing.server.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaUtil;
|
||||
|
||||
class MediaLibrary {
|
||||
|
||||
static class Interval {
|
||||
|
||||
public final Date begin;
|
||||
public final Date end;
|
||||
|
||||
public Interval(Date begin, Date end) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (obj instanceof Interval) {
|
||||
Interval interval = (Interval) obj;
|
||||
return MediaUtil.equalsDatesAllowingNull(this.begin, interval.begin)
|
||||
&& MediaUtil.equalsDatesAllowingNull(this.end, interval.end);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(new Date[] { begin, end });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of MediaTracks kept by this library. Due to complex write operations which require explicit write-locking
|
||||
* anyway there's no need to realize this collection with built-in concurrency support.
|
||||
*/
|
||||
private final Map<MediaTrack, MediaTrack> mediaTracksByDbId = new HashMap<MediaTrack, MediaTrack>();
|
||||
|
||||
/**
|
||||
* The cache used during lookups by overlapping interval. Realized as ConcurrentMap to prevent from need for
|
||||
* write-locking during lookup operation. Cached values are realized as Set to allow for quicker removal from cache
|
||||
* result in case a MediaTrack is being removed from the library or changes values such that it needs to be removed
|
||||
* from the cache.
|
||||
*/
|
||||
private final ConcurrentMap<Interval, Set<MediaTrack>> cacheByInterval = new ConcurrentHashMap<Interval, Set<MediaTrack>>();
|
||||
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = lock.readLock();
|
||||
private final Lock writeLock = lock.writeLock();
|
||||
|
||||
// /**
|
||||
// * Sort in reverse order of start time! For equal start times compare dbId to distinguish different instances.
|
||||
// */
|
||||
// private static final Comparator<MediaTrack> COMPARATOR_BY_REVERSE_STARTTIME = new Comparator<MediaTrack>() {
|
||||
//
|
||||
// @Override
|
||||
// public int compare(MediaTrack mediaTrack1, MediaTrack mediaTrack2) {
|
||||
// int result = compareDatesAllowingNull(mediaTrack2.startTime, mediaTrack1.startTime);
|
||||
// if (result == 0) {
|
||||
// return mediaTrack1.dbId.compareTo(mediaTrack2.dbId);
|
||||
// } else {
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// };
|
||||
|
||||
/**
|
||||
* NOTE: The implementation of this lookup using simple linear search is a trade off between development effort and
|
||||
* performance gain.
|
||||
*
|
||||
* Actually, efficient lookup of overlapping intervals is supposed to be performed using an interval tree, e.g.
|
||||
* http://thekevindolan.com/2010/02/interval-tree/
|
||||
*
|
||||
* However, considering the expected low number of media entries and the expected high rate of cache hits doesn't
|
||||
* justify providing a dedicated interval tree implementation (given that there's none readily available).
|
||||
*
|
||||
* TODO: A slight performance gain might be achieved assuming that more recent media tracks are requested more frequently
|
||||
* than older ones. Thus, sorting the list of media tracks by start time and starting linear search from the more
|
||||
* recent end might reduce loop cycles during linear search. E.g. use a SortedMap with COMPARATOR_BY_REVERSE_STARTTIME commented out above.
|
||||
*
|
||||
* @param startTime
|
||||
* @param endTime
|
||||
* @return
|
||||
*/
|
||||
Set<MediaTrack> findMediaTracksInTimeRange(Date startTime, Date endTime) {
|
||||
|
||||
if (startTime != null) {
|
||||
|
||||
Interval interval = new Interval(startTime, endTime);
|
||||
readLock.lock();
|
||||
try {
|
||||
Set<MediaTrack> cachedMediaTracks = cacheByInterval.get(interval);
|
||||
if (cachedMediaTracks == null) {
|
||||
|
||||
Set<MediaTrack> result = new HashSet<MediaTrack>();
|
||||
for (MediaTrack mediaTrack : mediaTracksByDbId.values()) {
|
||||
if (mediaTrack.overlapsWith(startTime, endTime)) {
|
||||
result.add(mediaTrack);
|
||||
}
|
||||
}
|
||||
cachedMediaTracks = cacheByInterval.putIfAbsent(interval, result);
|
||||
if (cachedMediaTracks != null) {
|
||||
return cachedMediaTracks;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return cachedMediaTracks;
|
||||
}
|
||||
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
// else
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding media tracks is expected to happen so rarely that we don't optimize for it and simply re-use the add-many
|
||||
* method.
|
||||
*
|
||||
* @param mediaTrack
|
||||
*/
|
||||
void addMediaTrack(MediaTrack mediaTrack) {
|
||||
addMediaTracks(Collections.singleton(mediaTrack));
|
||||
}
|
||||
|
||||
void addMediaTracks(Collection<MediaTrack> mediaTracks) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
for (MediaTrack mediaTrack : mediaTracks) {
|
||||
this.mediaTracksByDbId.put(mediaTrack, mediaTrack);
|
||||
updateCache_Add(mediaTrack);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void deleteMediaTrack(MediaTrack mediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack deletedMediaTrack = mediaTracksByDbId.remove(mediaTrack);
|
||||
updateCache_Remove(deletedMediaTrack);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void titleChanged(MediaTrack changedMediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
|
||||
if (mediaTrack != null) {
|
||||
mediaTrack.title = changedMediaTrack.title;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void urlChanged(MediaTrack changedMediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
|
||||
if (mediaTrack != null) {
|
||||
mediaTrack.url = changedMediaTrack.url;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void mimeTypeChanged(MediaTrack changedMediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
|
||||
if (mediaTrack != null) {
|
||||
mediaTrack.mimeType = changedMediaTrack.mimeType;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void startTimeChanged(MediaTrack changedMediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
|
||||
if (mediaTrack != null) {
|
||||
mediaTrack.startTime = changedMediaTrack.startTime;
|
||||
updateCache_Change(mediaTrack);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void durationChanged(MediaTrack changedMediaTrack) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
|
||||
if (mediaTrack != null) {
|
||||
mediaTrack.durationInMillis = changedMediaTrack.durationInMillis;
|
||||
updateCache_Change(mediaTrack);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called only under write lock!
|
||||
*/
|
||||
private void updateCache_Add(MediaTrack mediaTrack) {
|
||||
for (Entry<Interval, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
|
||||
Interval interval = cacheEntry.getKey();
|
||||
if (mediaTrack.overlapsWith(interval.begin, interval.end)) {
|
||||
cacheEntry.getValue().add(mediaTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called only under write lock!
|
||||
*/
|
||||
private void updateCache_Change(MediaTrack mediaTrack) {
|
||||
for (Entry<Interval, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
|
||||
cacheEntry.getValue().remove(mediaTrack);
|
||||
Interval interval = cacheEntry.getKey();
|
||||
if (mediaTrack.overlapsWith(interval.begin, interval.end)) {
|
||||
cacheEntry.getValue().add(mediaTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called only under write lock!
|
||||
*/
|
||||
private void updateCache_Remove(MediaTrack mediaTrack) {
|
||||
for (Entry<Interval, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
|
||||
cacheEntry.getValue().remove(mediaTrack);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<MediaTrack> allTracks() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return new ArrayList<MediaTrack>(mediaTracksByDbId.values());
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void serialize(ObjectOutputStream stream) throws IOException {
|
||||
readLock.lock();
|
||||
try {
|
||||
stream.writeObject(new ArrayList<MediaTrack>(mediaTracksByDbId.values()));
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void deserialize(ObjectInputStream stream) throws ClassNotFoundException, IOException {
|
||||
addMediaTracks((Collection<MediaTrack>) stream.readObject());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
mediaTracksByDbId.clear();
|
||||
cacheByInterval.clear();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+117
-13
@@ -12,7 +12,9 @@ import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -27,11 +29,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
@@ -60,6 +57,8 @@ import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
@@ -77,6 +76,9 @@ import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.media.DBMediaTrack;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
@@ -115,6 +117,7 @@ import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
import com.sap.sailing.server.Replicator;
|
||||
import com.sap.sailing.server.operationaltransformation.AddCourseArea;
|
||||
import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
|
||||
import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
||||
@@ -124,11 +127,16 @@ import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordWindFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RemoveEvent;
|
||||
import com.sap.sailing.server.operationaltransformation.RemoveMediaTrackOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.RemoveWindFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RenameEvent;
|
||||
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateEvent;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateMarkPassings;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackDurationOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackStartTimeOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackTitleOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackUrlOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateRaceTimes;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
|
||||
@@ -208,22 +216,26 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
|
||||
private final RaceLogScoringReplicator raceLogScoringReplicator;
|
||||
|
||||
private final MediaDB mediaDB;
|
||||
|
||||
private final MediaLibrary mediaLibrary;
|
||||
|
||||
public RacingEventServiceImpl() {
|
||||
this(MongoFactory.INSTANCE.getDefaultDomainObjectFactory(), MongoFactory.INSTANCE.getDefaultMongoObjectFactory());
|
||||
this(MongoFactory.INSTANCE.getDefaultDomainObjectFactory(), MongoFactory.INSTANCE.getDefaultMongoObjectFactory(), MediaDBFactory.INSTANCE.getDefaultMediaDB());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the default factories for the tracking adapters
|
||||
*/
|
||||
private RacingEventServiceImpl(DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory) {
|
||||
private RacingEventServiceImpl(DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory, MediaDB mediaDB) {
|
||||
this(domainObjectFactory, mongoObjectFactory, SwissTimingFactory.INSTANCE,
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE, DomainFactory.INSTANCE);
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE, DomainFactory.INSTANCE, mediaDB);
|
||||
}
|
||||
|
||||
private RacingEventServiceImpl(DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
|
||||
SwissTimingFactory swissTimingFactory,
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory swissTimingDomainFactory,
|
||||
DomainFactory tractracDomainFactory) {
|
||||
DomainFactory tractracDomainFactory, MediaDB mediaDb) {
|
||||
assert swissTimingDomainFactory.getBaseDomainFactory() == tractracDomainFactory.getBaseDomainFactory();
|
||||
logger.info("Created " + this);
|
||||
this.tractracDomainFactory = tractracDomainFactory;
|
||||
@@ -246,6 +258,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
delayToLiveInMillis = TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS;
|
||||
this.raceLogReplicator = new RaceLogReplicator(this);
|
||||
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
|
||||
this.mediaDB = mediaDb;
|
||||
this.mediaLibrary = new MediaLibrary();
|
||||
|
||||
// Add one default leaderboard that aggregates all races currently tracked by this service.
|
||||
// This is more for debugging purposes than for anything else.
|
||||
@@ -255,17 +269,18 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
loadRaceIDToRegattaAssociations();
|
||||
loadStoredLeaderboardsAndGroups();
|
||||
loadStoredEvents();
|
||||
loadMediaLibary();
|
||||
}
|
||||
|
||||
public RacingEventServiceImpl(MongoDBService mongoDBService) {
|
||||
this(MongoFactory.INSTANCE.getDomainObjectFactory(mongoDBService), MongoFactory.INSTANCE.getMongoObjectFactory(mongoDBService));
|
||||
this(MongoFactory.INSTANCE.getDomainObjectFactory(mongoDBService), MongoFactory.INSTANCE.getMongoObjectFactory(mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(mongoDBService));
|
||||
}
|
||||
|
||||
public RacingEventServiceImpl(MongoDBService mongoDBService, SwissTimingFactory swissTimingFactory,
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory swissTimingDomainFactory,
|
||||
DomainFactory tractracDomainFactory) {
|
||||
DomainFactory tractracDomainFactory, MediaDB mediaDB) {
|
||||
this(MongoFactory.INSTANCE.getDomainObjectFactory(mongoDBService), MongoFactory.INSTANCE.getMongoObjectFactory(mongoDBService),
|
||||
swissTimingFactory, swissTimingDomainFactory, tractracDomainFactory);
|
||||
swissTimingFactory, swissTimingDomainFactory, tractracDomainFactory, mediaDB);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -300,7 +315,24 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collects media track references from the configured sources (mongo DB by default, ftp folder yet to be implemented).
|
||||
* The method is expected to be called initially blocking the API until finished.
|
||||
*
|
||||
* Subsequent calls (assumed to be triggered from the admin console or in scheduled intervals) don't need to block. In that case,
|
||||
* the API will simply serve the current state.
|
||||
*
|
||||
*/
|
||||
private void loadMediaLibary() {
|
||||
Collection<DBMediaTrack> allDBMediaTracks = mediaDB.loadAllMediaTracks();
|
||||
for (DBMediaTrack dbMediaTrack : allDBMediaTracks) {
|
||||
MimeType mimeType = dbMediaTrack.mimeType != null ? MimeType.valueOf(dbMediaTrack.mimeType) : null;
|
||||
MediaTrack mediaTrack = new MediaTrack(dbMediaTrack.dbId, dbMediaTrack.title, dbMediaTrack.url, dbMediaTrack.startTime, dbMediaTrack.durationInMillis, mimeType);
|
||||
mediaTrackAdded(mediaTrack);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLeaderboard(Leaderboard leaderboard) {
|
||||
synchronized (leaderboardsByName) {
|
||||
@@ -1624,6 +1656,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
oos.writeObject(leaderboardGroupsByName);
|
||||
logger.info("serializing leaderboardsByName");
|
||||
oos.writeObject(leaderboardsByName);
|
||||
logger.info("serializing mediaLibrary");
|
||||
mediaLibrary.serialize(oos);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // the type-parameters in the casts of the de-serialized collection objects can't be checked
|
||||
@@ -1649,6 +1683,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
leaderboardGroupsByName.clear();
|
||||
leaderboardsByName.clear();
|
||||
eventsById.clear();
|
||||
mediaLibrary.clear();
|
||||
logger.info("receiving eventsById");
|
||||
eventsById.putAll((Map<Serializable, Event>) ois.readObject());
|
||||
logger.info("Recieved " + eventsById.size() + " NEW events");
|
||||
@@ -1675,6 +1710,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
((LeaderboardGroupMetaLeaderboard) leaderboard).registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
}
|
||||
logger.info("receiving mediaLibrary");
|
||||
mediaLibrary.deserialize(ois);
|
||||
logger.info("Done with initial replication on "+this);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(oldContextClassloader);
|
||||
@@ -1782,4 +1819,71 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
return courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackAdded(MediaTrack mediaTrack) {
|
||||
String mimeType = mediaTrack.mimeType != null ? mediaTrack.mimeType.name() : null;
|
||||
if (mediaTrack.dbId == null) {
|
||||
mediaTrack.dbId = mediaDB.insertMediaTrack(mediaTrack.title, mediaTrack.url, mediaTrack.startTime, mediaTrack.durationInMillis, mimeType);
|
||||
}
|
||||
mediaLibrary.addMediaTrack(mediaTrack);
|
||||
replicate(new AddMediaTrackOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTracksAdded(Collection<MediaTrack> mediaTracks) {
|
||||
mediaLibrary.addMediaTracks(mediaTracks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackTitleChanged(MediaTrack mediaTrack) {
|
||||
mediaDB.updateTitle(mediaTrack.dbId, mediaTrack.title);
|
||||
mediaLibrary.titleChanged(mediaTrack);
|
||||
replicate(new UpdateMediaTrackTitleOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackUrlChanged(MediaTrack mediaTrack) {
|
||||
mediaDB.updateUrl(mediaTrack.dbId, mediaTrack.url);
|
||||
mediaLibrary.urlChanged(mediaTrack);
|
||||
replicate(new UpdateMediaTrackUrlOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackStartTimeChanged(MediaTrack mediaTrack) {
|
||||
mediaDB.updateStartTime(mediaTrack.dbId, mediaTrack.startTime);
|
||||
mediaLibrary.startTimeChanged(mediaTrack);
|
||||
replicate(new UpdateMediaTrackStartTimeOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackDurationChanged(MediaTrack mediaTrack) {
|
||||
mediaDB.updateDuration(mediaTrack.dbId, mediaTrack.durationInMillis);
|
||||
mediaLibrary.durationChanged(mediaTrack);
|
||||
replicate(new UpdateMediaTrackDurationOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediaTrackDeleted(MediaTrack mediaTrack) {
|
||||
mediaDB.deleteMediaTrack(mediaTrack.dbId);
|
||||
mediaLibrary.deleteMediaTrack(mediaTrack);
|
||||
replicate(new RemoveMediaTrackOperation(mediaTrack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier) {
|
||||
TrackedRace trackedRace = getExistingTrackedRace(regattaAndRaceIdentifier);
|
||||
if (trackedRace != null) {
|
||||
Date raceStart = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
|
||||
Date raceEnd = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
|
||||
return mediaLibrary.findMediaTracksInTimeRange(raceStart , raceEnd);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MediaTrack> getAllMediaTracks() {
|
||||
return mediaLibrary.allTracks();
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
|
||||
public abstract class AbstractMediaTrackOperation extends AbstractRacingEventServiceOperation<Void> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final MediaTrack mediaTrack;
|
||||
|
||||
public AbstractMediaTrackOperation(MediaTrack mediaTrack) {
|
||||
this.mediaTrack = mediaTrack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class AddMediaTrackOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AddMediaTrackOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackAdded(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class RemoveMediaTrackOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RemoveMediaTrackOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackDeleted(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class UpdateMediaTrackDurationOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UpdateMediaTrackDurationOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackDurationChanged(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class UpdateMediaTrackStartTimeOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UpdateMediaTrackStartTimeOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackStartTimeChanged(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class UpdateMediaTrackTitleOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UpdateMediaTrackTitleOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackTitleChanged(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class UpdateMediaTrackUrlOperation extends AbstractMediaTrackOperation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UpdateMediaTrackUrlOperation(MediaTrack mediaTrack) {
|
||||
super(mediaTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.mediaTrackUrlChanged(this.mediaTrack);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user