Supposedly final.

- With from master pending.
- Merge to master deferred after weekend with three events
This commit is contained in:
Jens Rommel
2013-05-03 18:11:20 +02:00
parent 344f2db3ef
commit 2aeef5426c
33 changed files with 775 additions and 279 deletions
@@ -8,6 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: com.sap.sailing.domain.common,
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
@@ -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,9 @@ public class MediaTrack implements IsSerializable {
public Status status = Status.UNDEFINED;
public MediaTrack() {
super();
}
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 +80,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 +96,20 @@ public class MediaTrack implements IsSerializable {
public boolean isYoutube() {
return (mimeType != null) && MediaSubType.youtube.equals(mimeType.mediaSubType);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MediaTrack) {
MediaTrack mediaTrack = (MediaTrack) obj;
return this.dbId.equals(mediaTrack.dbId);
} else {
return false;
}
}
@Override
public int hashCode() {
return this.dbId == null ? 0 : this.dbId.hashCode();
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.domain.persistence.media;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -14,11 +13,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 +25,4 @@ public interface MediaDB {
void updateDuration(String dbId, int durationInMillis);
Collection<DBMediaTrack> queryOverlappingMediaTracks(Date rangeStart, Date rangeEnd);
}
@@ -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();
}
}
}
@@ -27,7 +27,6 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.swisstimingreplayadapter
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",
@@ -21,8 +21,8 @@ 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.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;
@@ -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> {
@@ -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> {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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> {
@@ -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);
});
}-*/;
@@ -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,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,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 {
@@ -4,23 +4,25 @@ 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 java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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.common.media.MediaTrack;
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 com.sap.sailing.domain.tracking.TrackedRace;
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;
import com.sap.sailing.server.operationaltransformation.AddMediaTrackBatchOperation;
import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation;
import com.sap.sailing.server.operationaltransformation.RemoveMediaTrackOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackOperation;
public class MediaServiceImpl extends RemoteServiceServlet implements MediaService {
@@ -31,6 +33,8 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
private ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private static final long serialVersionUID = -8917349579281305977L;
CountDownLatch initializationProgress = new CountDownLatch(1);
public MediaServiceImpl() {
super();
@@ -38,85 +42,119 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
racingEventServiceTracker = new ServiceTracker<RacingEventService, RacingEventService>(
context, RacingEventService.class.getName(), null);
racingEventServiceTracker.open();
}
@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();
}
}
@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;
}
@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);
startInitializationThread();
}
private MediaDB mediaDB() {
return MediaDBFactory.INSTANCE.getDefaultMediaDB();
}
private RacingEventService racingEventService() {
return racingEventServiceTracker.getService();
}
private void waitForInitialization() {
try {
int timeout = 10;
TimeUnit timeoutUnit = TimeUnit.SECONDS;
if (!initializationProgress.await(timeout, timeoutUnit)) {
throw new RuntimeException("Media library initialization timed out: " + timeout + ' ' + timeoutUnit);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private void startInitializationThread() {
new Thread(new Runnable() {
@Override
public void run() {
updateMediaLibary();
initializationProgress.countDown();
}
}).start();
}
/**
* 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 updateMediaLibary() {
Collection<DBMediaTrack> allDBMediaTracks = mediaDB().loadAllMediaTracks();
Collection<MediaTrack> allMediaTracks = new ArrayList<MediaTrack>(allDBMediaTracks.size());
for (DBMediaTrack dbMediaTrack : allDBMediaTracks) {
MediaTrack mediaTrack = createMediaTrackFromDB(dbMediaTrack);
allMediaTracks.add(mediaTrack );
}
racingEventService().apply(new AddMediaTrackBatchOperation(allMediaTracks));
}
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;
}
@Override
public Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier) {
waitForInitialization();
return racingEventService().getMediaTracksForRace(regattaAndRaceIdentifier);
}
@Override
public Collection<MediaTrack> getAllMediaTracks() {
waitForInitialization();
return racingEventService().getAllMediaTracks();
}
@Override
public void addMediaTrack(MediaTrack mediaTrack) {
if (mediaTrack.dbId != null) {
throw new IllegalStateException("Property dbId must be null for newly created media track.");
}
waitForInitialization();
racingEventService().apply(new AddMediaTrackOperation(mediaTrack));
String mimeType = mediaTrack.mimeType != null ? mediaTrack.mimeType.name() : null;
mediaDB().insertMediaTrack(mediaTrack.title, mediaTrack.url, mediaTrack.startTime, mediaTrack.durationInMillis, mimeType);
}
@Override
public void deleteMediaTrack(MediaTrack mediaTrack) {
waitForInitialization();
racingEventService().apply(new RemoveMediaTrackOperation(mediaTrack));
mediaDB().deleteMediaTrack(mediaTrack.dbId);
}
@Override
public void updateTitle(MediaTrack mediaTrack) {
waitForInitialization();
racingEventService().apply(new UpdateMediaTrackOperation(mediaTrack));
mediaDB().updateTitle(mediaTrack.dbId, mediaTrack.title);
}
@Override
public void updateUrl(MediaTrack mediaTrack) {
waitForInitialization();
racingEventService().apply(new UpdateMediaTrackOperation(mediaTrack));
mediaDB().updateUrl(mediaTrack.dbId, mediaTrack.url);
}
@Override
public void updateStartTime(MediaTrack mediaTrack) {
waitForInitialization();
racingEventService().apply(new UpdateMediaTrackOperation(mediaTrack));
mediaDB().updateStartTime(mediaTrack.dbId, mediaTrack.startTime);
}
@Override
public void updateDuration(MediaTrack mediaTrack) {
waitForInitialization();
racingEventService().apply(new UpdateMediaTrackOperation(mediaTrack));
mediaDB().updateDuration(mediaTrack.dbId, mediaTrack.durationInMillis);
}
}
@@ -1,7 +1,6 @@
package com.sap.sailing.media.persistence.test;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -9,23 +8,18 @@ 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 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();
}
@@ -39,18 +33,12 @@ public class TestMediaDB extends AbstractMongoDBTest {
int durationInMillis = 23;
String mimeType = MimeType.ogv.name();
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
DBMediaTrack videoTrack = mongoDB.loadMediaTrack(dbId);
DBMediaTrack videoTrack = mongoDB.loadAllMediaTracks().iterator().next();
assertNotNull(videoTrack);
assertThat(videoTrack.dbId, Is.is(dbId));
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());
@@ -72,7 +60,7 @@ public class TestMediaDB extends AbstractMongoDBTest {
}
}
@Test(expected=RuntimeException.class)
@Test
public void testDeleteVideoTrack() {
//insert test object
final String videoTitle = "Test Video";
@@ -84,10 +72,10 @@ public class TestMediaDB extends AbstractMongoDBTest {
String dbId = mongoDB.insertMediaTrack(videoTitle, url, date, durationInMillis, mimeType);
//delete
mongoDB.deleteMediaTrack(videoTitle);
mongoDB.deleteMediaTrack(dbId);
//assert not exists --> RuntimeException
mongoDB.loadMediaTrack(dbId);
assertThat(mongoDB.loadAllMediaTracks().size(), is(0));
}
@Test
@@ -106,7 +94,7 @@ public class TestMediaDB extends AbstractMongoDBTest {
mongoDB.updateStartTime(dbId, newDate);
//assert start time is updated and everything else preserved
DBMediaTrack videoTrack = mongoDB.loadMediaTrack(dbId);
DBMediaTrack videoTrack = mongoDB.loadAllMediaTracks().iterator().next();
assertThat(videoTrack.startTime, is(newDate));
assertThat(videoTrack.durationInMillis, is(durationInMillis));
assertThat(videoTrack.title, is(videoTitle));
@@ -114,110 +102,4 @@ public class TestMediaDB extends AbstractMongoDBTest {
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"
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@@ -25,6 +26,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 +102,16 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
assertNotNull(master.getLeaderboardGroupByName(leaderBoardGroupName));
assertNull(replica.getLeaderboardGroupByName(leaderBoardGroupName));
/* Media Library */
String dbId = "1234";
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);
master.mediaTrackAdded(mediaTrack);
/* fire up replication */
performReplicationSetup();
ReplicationMasterDescriptor the_master = replicationDescriptorPair.getB(); /* master descriptor */
@@ -116,6 +129,7 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
assertNotNull(replica.getLeaderboardGroupByName(leaderBoardGroupName));
assertNotNull(replica.getLeaderboardByName(leaderboardName));
assertTrue(replica.getAllRegattas().iterator().hasNext());
assertTrue(replica.getAllMediaTracks().iterator().hasNext());
}
@Test
@@ -0,0 +1,135 @@
package com.sap.sailing.server.replication.test;
import java.util.Arrays;
import java.util.Collection;
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 com.sap.sailing.server.operationaltransformation.AddMediaTrackBatchOperation;
import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation;
import com.sap.sailing.server.operationaltransformation.RemoveMediaTrackOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackOperation;
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 {
/* 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 testBasicInitialLoad() throws Exception {
assertNotSame(master, replica);
assertEquals(master.getAllMediaTracks().size(), replica.getAllMediaTracks().size());
}
@Test
public void testAddMediaTrackReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
assertThat(master.getAllMediaTracks().size(), is(0));
assertThat(replica.getAllMediaTracks().size(), is(0));
master.apply(addMediaTrackOperation);
assertThat(master.getAllMediaTracks().size(), is(1));
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().size(), is(1));
}
@Test
public void testDeleteMediaTrackReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
RemoveMediaTrackOperation removeMediaTrackOperation = new RemoveMediaTrackOperation(mediaTrack);
master.apply(removeMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().size(), is(0));
}
@Test
public void testaddMediaTrackBatchReplication() throws InterruptedException {
MediaTrack mediaTrack1 = createMediaTrack("1");
MediaTrack mediaTrack2 = createMediaTrack("2");
Collection<MediaTrack> mediaTrackBatch = Arrays.asList(new MediaTrack[] {mediaTrack1, mediaTrack2});
AddMediaTrackBatchOperation addMediaTrackBatchOperation = new AddMediaTrackBatchOperation(mediaTrackBatch);
master.apply(addMediaTrackBatchOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().size(), is(2));
}
@Test
public void testUpdateMediaTrackTitleReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
mediaTrack.title = mediaTrack.title + "x";
UpdateMediaTrackOperation updateMediaTrackOperation = new UpdateMediaTrackOperation(mediaTrack);
master.apply(updateMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().iterator().next().title, is(mediaTrack.title));
}
@Test
public void testUpdateMediaTrackUrlReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
mediaTrack.url = mediaTrack.url + "x";
UpdateMediaTrackOperation updateMediaTrackOperation = new UpdateMediaTrackOperation(mediaTrack);
master.apply(updateMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().iterator().next().url, is(mediaTrack.url));
}
@Test
public void testUpdateMediaTrackStartTimeReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
mediaTrack.startTime = new Date(mediaTrack.startTime.getTime() + 1000);
UpdateMediaTrackOperation updateMediaTrackOperation = new UpdateMediaTrackOperation(mediaTrack);
master.apply(updateMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().iterator().next().startTime, is(mediaTrack.startTime));
}
@Test
public void testUpdateMediaTrackDurationReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
mediaTrack.durationInMillis = mediaTrack.durationInMillis + 1000;
UpdateMediaTrackOperation updateMediaTrackOperation = new UpdateMediaTrackOperation(mediaTrack);
master.apply(updateMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().iterator().next().durationInMillis, is(mediaTrack.durationInMillis));
}
@Test
public void testUpdateMediaTrackMimeTypeReplication() throws InterruptedException {
MediaTrack mediaTrack = createMediaTrack("1");
AddMediaTrackOperation addMediaTrackOperation = new AddMediaTrackOperation(mediaTrack);
master.apply(addMediaTrackOperation);
mediaTrack.mimeType = MimeType.mp3;
UpdateMediaTrackOperation updateMediaTrackOperation = new UpdateMediaTrackOperation(mediaTrack);
master.apply(updateMediaTrackOperation);
Thread.sleep(500); // wait for JMS to deliver the message and the message to be applied
assertThat(replica.getAllMediaTracks().iterator().next().mimeType, is(mediaTrack.mimeType));
}
}
@@ -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
@@ -0,0 +1,193 @@
package com.sap.sailing.server.impl;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
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.RacingEventServiceOperation;
import com.sap.sailing.server.Replicator;
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;
private Replicator replicator;
@Before
public void before() {
replicator = new Replicator() {
@Override
public <T> void replicate(RacingEventServiceOperation<T> operation) {
}
};
this.mediaLibary = new MediaLibrary(replicator);
}
/* 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);
}
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));
}
}
@@ -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,16 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
CourseArea getCourseArea(Serializable courseAreaId);
void mediaTrackAdded(MediaTrack mediaTrack);
void mediaTracksAdded(Collection<MediaTrack> mediaTracks);
void mediaTrackChanged(MediaTrack mediaTrack);
void mediaTrackDeleted(MediaTrack mediaTrack);
Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier);
Collection<MediaTrack> getAllMediaTracks();
}
@@ -0,0 +1,88 @@
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.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.server.Replicator;
class MediaLibrary {
/* public class MediaTrack{
MediaItem(boolean isMutable) {
this.isMutable = isMutable;
}
public final boolean isMutable;
public String id;
public String title;
public String url;
public Date startTime;
public int durationInMillis;
public String mimeType;
}*/
private List<MediaTrack> mediaTracks;
MediaLibrary(Replicator replicator) {
this.mediaTracks = new CopyOnWriteArrayList<MediaTrack>();
}
Collection<MediaTrack> findMediaTracksInTimeRange(Date startTime, Date endTime) {
Collection<MediaTrack> result = new ArrayList<MediaTrack>();
for (MediaTrack mediaTrack : mediaTracks) {
long mediaStartTime = mediaTrack.startTime.getTime();
long mediaEndTime = mediaStartTime + mediaTrack.durationInMillis;
if (startTime.getTime() < mediaEndTime && mediaStartTime < endTime.getTime()) {
result.add(mediaTrack);
}
}
return result ;
}
void addMediaTrack(MediaTrack mediaTrack) {
mediaTracks.add(mediaTrack);
}
void addMediaTracks(Collection<MediaTrack> mediaTracks) {
this.mediaTracks.addAll(mediaTracks);
}
void deleteMediaTrack(MediaTrack mediaTrack) {
mediaTracks.remove(mediaTrack);
}
void applyChanges(MediaTrack changedMediaTrack) {
for (MediaTrack mediaTrack : mediaTracks) {
if (mediaTrack.equals(changedMediaTrack)) {
mediaTrack.title = changedMediaTrack.title;
mediaTrack.url = changedMediaTrack.url;
mediaTrack.startTime = changedMediaTrack.startTime;
mediaTrack.durationInMillis = changedMediaTrack.durationInMillis;
mediaTrack.mimeType = changedMediaTrack.mimeType;
return;
}
}
}
Collection<MediaTrack> allTracks() {
return new ArrayList<MediaTrack>(mediaTracks);
}
void serialize(ObjectOutputStream stream) throws IOException {
stream.writeObject(mediaTracks);
}
@SuppressWarnings("unchecked")
void deserialize(ObjectInputStream stream) throws ClassNotFoundException, IOException {
addMediaTracks((Collection<MediaTrack>) stream.readObject());
}
}
@@ -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,7 +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;
@@ -56,6 +57,7 @@ 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.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -203,6 +205,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
private final RaceLogScoringReplicator raceLogScoringReplicator;
private MediaLibrary mediaLibrary;
public RacingEventServiceImpl() {
this(MongoFactory.INSTANCE.getDefaultDomainObjectFactory(), MongoFactory.INSTANCE.getDefaultMongoObjectFactory());
}
@@ -241,6 +245,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
delayToLiveInMillis = TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS;
this.raceLogReplicator = new RaceLogReplicator(this);
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
this.mediaLibrary = new MediaLibrary(this);
// Add one default leaderboard that aggregates all races currently tracked by this service.
// This is more for debugging purposes than for anything else.
@@ -1598,6 +1603,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 +1656,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);
@@ -1756,4 +1765,41 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
return courseArea;
}
@Override
public void mediaTrackAdded(MediaTrack mediaTrack) {
mediaLibrary.addMediaTrack(mediaTrack);
}
@Override
public void mediaTracksAdded(Collection<MediaTrack> mediaTracks) {
mediaLibrary.addMediaTracks(mediaTracks);
}
@Override
public void mediaTrackChanged(MediaTrack mediaTrack) {
mediaLibrary.applyChanges(mediaTrack);
}
@Override
public void mediaTrackDeleted(MediaTrack mediaTrack) {
mediaLibrary.deleteMediaTrack(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();
}
}
@@ -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;
}
}
@@ -0,0 +1,35 @@
package com.sap.sailing.server.operationaltransformation;
import java.util.Collection;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
public class AddMediaTrackBatchOperation extends AbstractRacingEventServiceOperation<Void> {
private static final long serialVersionUID = 1L;
private final Collection<MediaTrack> mediaTracks;
public AddMediaTrackBatchOperation(Collection<MediaTrack> mediaTracks) {
this.mediaTracks = mediaTracks;
}
@Override
public Void internalApplyTo(RacingEventService toState) throws Exception {
toState.mediaTracksAdded(this.mediaTracks);
return null;
}
@Override
public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
return null; //no op
}
@Override
public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
return null; //no op
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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 UpdateMediaTrackOperation extends AbstractMediaTrackOperation {
private static final long serialVersionUID = 1L;
public UpdateMediaTrackOperation(MediaTrack mediaTrack) {
super(mediaTrack);
}
@Override
public Void internalApplyTo(RacingEventService toState) throws Exception {
toState.mediaTrackChanged(this.mediaTrack);
return null;
}
}