Merge branch 'master' into ubilabs--rcapp--develop

This commit is contained in:
Peter Siegmund committed 2015-06-15 15:06:26 +02:00
commit f6f6a1d1b8
91 files changed
+5652 -3398

No files matched your search

@@ -1,47 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="false"/>
<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9998"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.dashboards.gwt.RibDashboard"/>
</listAttribute>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/dashboards/RibDashboard.html"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.sap.sailing.dashboards.gwt"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.dashboards.gwt&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-servlet.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war &quot;${project_loc:com.sap.sailing.dashboards.gwt}&quot; -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9998 com.sap.sailing.dashboards.gwt.RibDashboard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
</launchConfiguration>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="false"/>
<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9998"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.dashboards.gwt.RibDashboard"/>
</listAttribute>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/dashboards/RibDashboard.html"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.sap.sailing.dashboards.gwt"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.dashboards.gwt&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-servlet.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war &quot;${project_loc:com.sap.sailing.dashboards.gwt}&quot; -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9998 com.sap.sailing.dashboards.gwt.RibDashboard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
</launchConfiguration>
@@ -7,6 +7,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Image;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sse.gwt.client.media.ImageDTO;
public class EventLogo extends Image {
@@ -22,9 +23,9 @@ public class EventLogo extends Image {
sailingServiceAsync.getEventById(eventUUID, true, new AsyncCallback<EventDTO>() {
@Override
public void onSuccess(final EventDTO event) {
final String logoUrl = event.getLogoImageURL();
if (logoUrl != null) {
eventLogo.getElement().setAttribute("src", logoUrl);
final ImageDTO logo = event.getLogoImage();
if (logo != null) {
eventLogo.getElement().setAttribute("src", logo.getSourceRef());
} else {
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
}
File diff suppressed because it is too large. Load diff
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.persistence.impl;
public enum FieldNames {
// general:
TIME_AS_MILLIS, KNOT_SPEED, DEGREE_BEARING, LAT_DEG, LNG_DEG,
@@ -18,6 +19,8 @@ public enum FieldNames {
EVENT_IMAGE_URLS,
EVENT_VIDEO_URLS,
EVENT_SPONSOR_IMAGE_URLS,
EVENT_IMAGES,
EVENT_VIDEOS,
EVENT_OFFICIAL_WEBSITE_URL,
EVENT_LOGO_IMAGE_URL,
@@ -128,5 +131,13 @@ public enum FieldNames {
RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE,
// Handicap factors
REGATTA_LOG_TIME_ON_TIME_FACTOR, REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE, REGATTA_RANKING_METRIC, REGATTA_RANKING_METRIC_TYPE
REGATTA_LOG_TIME_ON_TIME_FACTOR, REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE, REGATTA_RANKING_METRIC, REGATTA_RANKING_METRIC_TYPE,
// image fields
IMAGE_URL, IMAGE_LOCALE, IMAGE_TITLE, IMAGE_SUBTITLE, IMAGE_MIMETYPE, IMAGE_COPYRIGHT, IMAGE_CREATEDATDATE,
IMAGE_WIDTH_IN_PX, IMAGE_HEIGHT_IN_PX, IMAGE_TAGS,
// video fields
VIDEO_URL, VIDEO_LOCALE, VIDEO_TITLE, VIDEO_SUBTITLE, VIDEO_MIMETYPE, VIDEO_COPYRIGHT, VIDEO_CREATEDATDATE,
VIDEO_TAGS, VIDEO_THUMBNAIL_URL, VIDEO_LENGTH_IN_SECONDS;
}
@@ -112,6 +112,8 @@ import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class MongoObjectFactoryImpl implements MongoObjectFactory {
private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName());
@@ -514,6 +516,10 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
serverCollection.remove(query);
}
/**
* StoreEvent() uses some deprecated methods of event to keep backward compatibility.
*/
@SuppressWarnings("deprecation")
@Override
public void storeEvent(Event event) {
DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name());
@@ -546,6 +552,18 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
sponsorImageURLs.add(sponsorImageURL.toString());
}
eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs);
BasicDBList images = new BasicDBList();
for (ImageDescriptor image : event.getImages()) {
DBObject imageObject = createImageObject(image);
images.add(imageObject);
}
eventDBObject.put(FieldNames.EVENT_IMAGES.name(), images);
BasicDBList videos = new BasicDBList();
for (VideoDescriptor video: event.getVideos()) {
DBObject videoObject = createVideoObject(video);
videos.add(videoObject);
}
eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos);
eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
// now store the links to the leaderboard groups
DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name());
@@ -1208,7 +1226,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
DBObject entry = (DBObject) JSON.parse(json.toString());
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
@Override
public void removeAllCompetitors() {
logger.info("Removing all persistent competitor info");
@@ -1403,4 +1421,41 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name(), event.getTimeOnDistanceAllowancePerNauticalMile().asSeconds());
storeRegattaLogEvent(regattaLikeId, result);
}
private DBObject createImageObject(ImageDescriptor image) {
DBObject result = new BasicDBObject();
result.put(FieldNames.IMAGE_URL.name(), image.getURL().toString());
result.put(FieldNames.IMAGE_LOCALE.name(), image.getLocale() != null ? image.getLocale().toLanguageTag() : null);
result.put(FieldNames.IMAGE_TITLE.name(), image.getTitle());
result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle());
result.put(FieldNames.IMAGE_COPYRIGHT.name(), image.getCopyright());
result.put(FieldNames.IMAGE_WIDTH_IN_PX.name(), image.getWidthInPx());
result.put(FieldNames.IMAGE_HEIGHT_IN_PX.name(), image.getHeightInPx());
storeTimePoint(image.getCreatedAtDate(), result, FieldNames.IMAGE_CREATEDATDATE);
BasicDBList tags = new BasicDBList();
for (String tag : image.getTags()) {
tags.add(tag);
}
result.put(FieldNames.IMAGE_TAGS.name(), tags);
return result;
}
private DBObject createVideoObject(VideoDescriptor video) {
DBObject result = new BasicDBObject();
result.put(FieldNames.VIDEO_URL.name(), video.getURL().toString());
result.put(FieldNames.VIDEO_LOCALE.name(), video.getLocale() != null ? video.getLocale().toLanguageTag() : null);
result.put(FieldNames.VIDEO_THUMBNAIL_URL.name(), video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null);
result.put(FieldNames.VIDEO_TITLE.name(), video.getTitle());
result.put(FieldNames.VIDEO_SUBTITLE.name(), video.getSubtitle());
result.put(FieldNames.VIDEO_MIMETYPE.name(), video.getMimeType() != null ? video.getMimeType().name() : null);
result.put(FieldNames.VIDEO_COPYRIGHT.name(), video.getCopyright());
result.put(FieldNames.VIDEO_LENGTH_IN_SECONDS.name(), video.getLengthInSeconds());
storeTimePoint(video.getCreatedAtDate(), result, FieldNames.VIDEO_CREATEDATDATE);
BasicDBList tags = new BasicDBList();
for (String tag : video.getTags()) {
tags.add(tag);
}
result.put(FieldNames.VIDEO_TAGS.name(), tags);
return result;
}
}
@@ -1,19 +1,20 @@
package com.sap.sailing.domain.base;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.Map;
import com.sap.sailing.domain.common.Renamable;
import com.sap.sse.common.Named;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.WithMedia;
/**
* Base interface for an Event consisting of all static information, which might be shared
* by the server and an Android application.
*/
public interface EventBase extends Named, WithDescription, Renamable, WithID {
public interface EventBase extends Named, WithDescription, Renamable, WithID, WithMedia {
void setDescription(String description);
@@ -41,6 +42,7 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID {
void setPublic(boolean isPublic);
/**
* @deprecated
* Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to image resources that can be
* used to represent the event, e.g., on a web page.
*
@@ -48,70 +50,29 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID {
*/
Iterable<URL> getImageURLs();
void addImageURL(URL imageURL);
void removeImageURL(URL imageURL);
/**
* @deprecated
* An event may have zero or more sponsors, each of which usually want to see their logo on the web page.
*
* @return the sponsors' logos; always non-<code>null</code> but possibly empty
*/
Iterable<URL> getSponsorImageURLs();
void addSponsorImageURL(URL sponsorImageURL);
void removeSponsorImageURL(URL sponsorImageURL);
/**
* Replaces the {@link #getSponsorImageURLs() current contents of the sponsorship image URL sequence} by the image URLs in
* <code>sponsorImageURLs</code>.
*
* @param sponsorImageURLs
* if <code>null</code>, the internal sequence of sponsorship image URLs is cleared but remains valid (non-
* <code>null</code>)
*/
void setSponsorImageURLs(Iterable<URL> sponsorImageURLs);
/**
* @deprecated
* An optional logo image; may return <code>null</code>.
*/
URL getLogoImageURL();
void setLogoImageURL(URL logoImageURL);
/**
* Replaces the {@link #getImageURLs() current contents of the image URL sequence} by the image URLs in
* <code>imageURLs</code>.
*
* @param imageURLs
* if <code>null</code>, the internal sequence of image URLs is cleared but remains valid (non-
* <code>null</code>)
*/
void setImageURLs(Iterable<URL> imageURLs);
/**
* @deprecated
* Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to video resources that can be
* used to represent the event, e.g., on a web page.
*
* @return a non-<code>null</code> value which may be empty
*/
Iterable<URL> getVideoURLs();
void addVideoURL(URL videoURL);
void removeVideoURL(URL videoURL);
/**
* Replaces the {@link #getVideoURLs() current contents of the video URL sequence} by the video URLs in
* <code>videoURLs</code>.
*
* @param videoURLs
* if <code>null</code>, the internal sequence of image URLs is cleared but remains valid (non-
* <code>null</code>)
*/
void setVideoURLs(Iterable<URL> videoURLs);
/**
* @return the URL of the event's official web site, or <code>null</code> if such a site does not exist or its URL
* is not known
@@ -122,9 +83,8 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID {
Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups();
/**
* For the images references by the image URLs in {@link #getImageURLs()}, {@link #getSponsorImageURLs()} and {@link #getLogoImageURL()}
* determines the image dimensions.
*/
ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException;
/**
* Sets and converts all event images and videos from the old URL based format to the new richer format
* */
boolean setMediaURLs(Iterable<URL> imageURLs, Iterable<URL> sponsorImageURLs, Iterable<URL> videoURLs, URL logoImageURL, Map<URL, ImageSize> imageSizes);
}
@@ -3,7 +3,10 @@ package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -11,6 +14,16 @@ import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.Venue;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.ImageDescriptorImpl;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.MediaDescriptor;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MediaUtils;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.media.VideoDescriptorImpl;
public abstract class EventBaseImpl implements EventBase {
private static final long serialVersionUID = -5749964088848611074L;
@@ -22,11 +35,9 @@ public abstract class EventBaseImpl implements EventBase {
private final UUID id;
private TimePoint startDate;
private TimePoint endDate;
private ConcurrentLinkedQueue<URL> imageURLs;
private ConcurrentLinkedQueue<URL> videoURLs;
private ConcurrentLinkedQueue<URL> sponsorImageURLs;
private URL logoImageURL;
private URL officialWebsiteURL;
private ConcurrentLinkedQueue<ImageDescriptor> images;
private ConcurrentLinkedQueue<VideoDescriptor> videos;
protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id) {
this(name, startDate, endDate, new VenueImpl(venueName), isPublic, id);
@@ -43,21 +54,17 @@ public abstract class EventBaseImpl implements EventBase {
this.endDate = endDate;
this.venue = venue;
this.isPublic = isPublic;
this.imageURLs = new ConcurrentLinkedQueue<URL>();
this.videoURLs = new ConcurrentLinkedQueue<URL>();
this.sponsorImageURLs = new ConcurrentLinkedQueue<URL>();
this.images = new ConcurrentLinkedQueue<ImageDescriptor>();
this.videos = new ConcurrentLinkedQueue<VideoDescriptor>();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (imageURLs == null) {
imageURLs = new ConcurrentLinkedQueue<URL>();
if (images == null) {
images = new ConcurrentLinkedQueue<ImageDescriptor>();
}
if (videoURLs == null) {
videoURLs = new ConcurrentLinkedQueue<URL>();
}
if (sponsorImageURLs == null) {
sponsorImageURLs = new ConcurrentLinkedQueue<URL>();
if (videos == null) {
videos = new ConcurrentLinkedQueue<VideoDescriptor>();
}
}
@@ -128,87 +135,41 @@ public abstract class EventBaseImpl implements EventBase {
@Override
public Iterable<URL> getImageURLs() {
return Collections.unmodifiableCollection(imageURLs);
List<URL> result = new ArrayList<URL>();
for (ImageDescriptor image : images) {
if (!image.hasTag(MediaTagConstants.SPONSOR) && !image.hasTag(MediaTagConstants.LOGO)) {
result.add(image.getURL());
}
}
return result;
}
@Override
public void addImageURL(URL imageURL) {
if (!imageURLs.contains(imageURL)) {
imageURLs.add(imageURL);
}
}
@Override
public void removeImageURL(URL imageURL) {
imageURLs.remove(imageURL);
}
@Override
public void setImageURLs(Iterable<URL> imageURLs) {
this.imageURLs.clear();
if (imageURLs != null) {
Util.addAll(imageURLs, this.imageURLs);
}
}
@Override
public Iterable<URL> getVideoURLs() {
return Collections.unmodifiableCollection(videoURLs);
}
@Override
public void addVideoURL(URL videoURL) {
if (!videoURLs.contains(videoURL)) {
videoURLs.add(videoURL);
}
}
@Override
public void removeVideoURL(URL videoURL) {
videoURLs.remove(videoURL);
}
@Override
public void setVideoURLs(Iterable<URL> videoURLs) {
this.videoURLs.clear();
if (videoURLs != null) {
Util.addAll(videoURLs, this.videoURLs);
List<URL> result = new ArrayList<URL>();
for(VideoDescriptor video: videos) {
result.add(video.getURL());
}
return result;
}
@Override
public Iterable<URL> getSponsorImageURLs() {
return Collections.unmodifiableCollection(sponsorImageURLs);
List<URL> result = new ArrayList<URL>();
for(MediaDescriptor media : findMediaWithTag(images, MediaTagConstants.SPONSOR)) {
result.add(media.getURL());
}
return result;
}
@Override
public void addSponsorImageURL(URL sponsorImageURL) {
if (!sponsorImageURLs.contains(sponsorImageURL)) {
sponsorImageURLs.add(sponsorImageURL);
}
}
@Override
public void removeSponsorImageURL(URL sponsorImageURL) {
sponsorImageURLs.remove(sponsorImageURL);
}
@Override
public void setSponsorImageURLs(Iterable<URL> sponsorImageURLs) {
this.sponsorImageURLs.clear();
if (sponsorImageURLs != null) {
Util.addAll(sponsorImageURLs, this.sponsorImageURLs);
}
}
@Override
public URL getLogoImageURL() {
return logoImageURL;
}
@Override
public void setLogoImageURL(URL logoImageURL) {
this.logoImageURL = logoImageURL;
URL result = null;
ImageDescriptor media = findImageWithTag(MediaTagConstants.LOGO);
if(media != null) {
result = media.getURL();
}
return result;
}
@Override
@@ -221,4 +182,165 @@ public abstract class EventBaseImpl implements EventBase {
this.officialWebsiteURL = officialWebsiteURL;
}
@Override
public Iterable<ImageDescriptor> getImages() {
return Collections.unmodifiableCollection(images);
}
@Override
public void addImage(ImageDescriptor image) {
if (!images.contains(image)) {
images.add(image);
}
}
@Override
public void removeImage(ImageDescriptor image) {
images.remove(image);
}
@Override
public void setImages(Iterable<ImageDescriptor> images) {
this.images.clear();
if (images != null) {
Util.addAll(images, this.images);
}
}
@Override
public Iterable<VideoDescriptor> getVideos() {
return Collections.unmodifiableCollection(videos);
}
@Override
public void addVideo(VideoDescriptor video) {
if (!videos.contains(video)) {
videos.add(video);
}
}
@Override
public void removeVideo(VideoDescriptor video) {
videos.remove(video);
}
@Override
public void setVideos(Iterable<VideoDescriptor> videos) {
this.videos.clear();
if (videos != null) {
Util.addAll(videos, this.videos);
}
}
@Override
public ImageDescriptor findImageWithTag(String tagName) {
ImageDescriptor result = null;
List<ImageDescriptor> mediaWithTag = findMediaWithTag(images, tagName);
if(mediaWithTag.size() > 0) {
result = mediaWithTag.get(0);
}
return result;
}
@Override
public VideoDescriptor findVideoWithTag(String tagName) {
VideoDescriptor result = null;
List<VideoDescriptor> mediaWithTag = findMediaWithTag(videos, tagName);
if(mediaWithTag.size() > 0) {
result = mediaWithTag.get(0);
}
return result;
}
@Override
public List<ImageDescriptor> findImagesWithTag(String tagName) {
return findMediaWithTag(images, tagName);
}
@Override
public List<VideoDescriptor> findVideosWithTag(String tagName) {
return findMediaWithTag(videos, tagName);
}
private <T extends MediaDescriptor> List<T> findMediaWithTag(Iterable<T> media, String tagName) {
List<T> result = new ArrayList<>();
for (T mediaEntry : media) {
if(mediaEntry.hasTag(tagName)) {
result.add(mediaEntry);
}
}
return result;
}
/**
* Sets and converts all event images and videos from the old URL based format to the new richer format
*/
public boolean setMediaURLs(Iterable<URL> imageURLs, Iterable<URL> sponsorImageURLs, Iterable<URL> videoURLs,
URL logoImageURL, Map<URL, ImageSize> imageSizes) {
boolean changed = false;
for (URL url : imageURLs) {
if (!hasMedia(images, url)) {
ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url));
String urlAsString = url.toString();
if (urlAsString.toLowerCase().indexOf("stage") > 0) {
image.addTag(MediaTagConstants.STAGE);
} else if (urlAsString.toLowerCase().indexOf("eventteaser") > 0) {
image.addTag(MediaTagConstants.TEASER);
} else {
image.addTag(MediaTagConstants.GALLERY);
}
addImage(image);
changed = true;
}
}
for (URL url : sponsorImageURLs) {
if (!hasMedia(images, url)) {
ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url));
image.addTag(MediaTagConstants.SPONSOR);
addImage(image);
changed = true;
}
}
if (logoImageURL != null && !hasMedia(images, logoImageURL)) {
ImageDescriptor image = migrateImageURLtoImage(logoImageURL, getStartDate(), imageSizes.get(logoImageURL));
image.addTag(MediaTagConstants.LOGO);
addImage(image);
changed = true;
}
for (URL url : videoURLs) {
if (!hasMedia(videos, url)) {
MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString());
VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, getStartDate());
addVideo(video);
changed = true;
}
}
return changed;
}
private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt, ImageSize imageSize) {
ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt);
if (imageSize != null) {
image.setSize(imageSize.getWidth(), imageSize.getHeight());
} else {
Pair<Integer, Integer> imageDimensions = MediaUtils.getImageDimensions(url);
if (imageDimensions != null) {
image.setSize(imageDimensions);
}
}
return image;
}
private boolean hasMedia(Iterable<? extends MediaDescriptor> media, URL url) {
for (MediaDescriptor mediaEntry : media) {
if (url.equals(mediaEntry.getURL())) {
return true;
}
}
return false;
}
}
@@ -1,16 +1,11 @@
package com.sap.sailing.domain.base.impl;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.Venue;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.media.ImageSize;
/**
* A simplified implementation of the {@link EventBase} interface which maintains an immutable collection of
@@ -23,7 +18,6 @@ import com.sap.sse.common.media.ImageSize;
public class StrippedEventImpl extends EventBaseImpl {
private static final long serialVersionUID = 5608501747499933988L;
private final Iterable<LeaderboardGroupBase> leaderboardGroups;
private final Map<URL, ImageSize> imageSizes;
public StrippedEventImpl(String name, TimePoint startDate, TimePoint endDate, String venueName,
boolean isPublic, UUID id, Iterable<LeaderboardGroupBase> leaderboardGroups) {
@@ -34,20 +28,10 @@ public class StrippedEventImpl extends EventBaseImpl {
boolean isPublic, UUID id, Iterable<LeaderboardGroupBase> leaderboardGroups) {
super(name, startDate, endDate, venue, isPublic, id);
this.leaderboardGroups = leaderboardGroups;
this.imageSizes = new HashMap<URL, ImageSize>();
}
@Override
public Iterable<LeaderboardGroupBase> getLeaderboardGroups() {
return leaderboardGroups;
}
public void setImageSize(URL imageURL, ImageSize imageSize) {
imageSizes.put(imageURL, imageSize);
}
@Override
public ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException {
return imageSizes.get(imageURL);
}
}
@@ -1,15 +1,11 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
@@ -17,8 +13,6 @@ import javax.imageio.stream.ImageInputStream;
import org.junit.Test;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.impl.EventImpl;
import com.sap.sailing.domain.common.impl.ImageSizeImpl;
import com.sap.sse.common.media.ImageSize;
@@ -56,15 +50,4 @@ public class CalculateImageSizeFromUrlTest {
}
return null;
}
@Test
public void testEventImageSize() throws MalformedURLException, InterruptedException, ExecutionException {
Event e = new EventImpl("Event Name", /* startDate */ null, /* endDate */ null, "Kiel", /* isPublic */ true, UUID.randomUUID());
int width = Math.max(10, (int) (200. * Math.random()));
int height = Math.max(10, (int) (100. * Math.random()));
URL imageURL = new URL("http://placekitten.com/" + width + "/" + height);
e.addImageURL(imageURL);
ImageSize expectedSize = new ImageSizeImpl(width, height);
assertEquals(expectedSize, e.getImageSize(imageURL));
}
}
@@ -1,64 +1,49 @@
package com.sap.sailing.domain.base;
import java.net.URL;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sse.common.media.ImageSize;
/**
* An event is a group of {@link Regatta regattas} carried out at a common venue within a common time frame. For
* example, Kiel Week 2011 is an event, and the International German Championship 2011 held, e.g., in Travem�nde, is an event,
* too.
*
* @author Axel Uhl (D043530)
*
*/
public interface Event extends EventBase {
Iterable<Regatta> getRegattas();
void addRegatta(Regatta regatta);
void removeRegatta(Regatta regatta);
/**
* For events, the ID is always a UUID.
*/
UUID getId();
/**
* Returns a non-<code>null</code> live but unmodifiable collection of leaderboard groups that were previously
* {@link #addLeaderboardGroup(LeaderboardGroup) added} to this event, in the order of their addition. Therefore, to
* change the iteration order, {@link #removeLeaderboardGroup(LeaderboardGroup)} and
* {@link #addLeaderboardGroup(LeaderboardGroup)} need to be used.
*/
@Override
Iterable<LeaderboardGroup> getLeaderboardGroups();
void addLeaderboardGroup(LeaderboardGroup leaderboardGroup);
/**
* @return <code>true</code> if and only if a leaderboard group equal to <code>leaderboardGroup</code> was part of
* {@link #getLeaderboardGroups()} and therefore was actually removed
*/
boolean removeLeaderboardGroup(LeaderboardGroup leaderboardGroup);
/**
* Replaces the {@link #getLeaderboardGroups() current contents of the leaderboard groups sequence} by the
* leaderboard groups in <code>leaderboardGroups</code>.
*/
void setLeaderboardGroups(Iterable<LeaderboardGroup> leaderboardGroups);
/**
* For the images references by the image URLs in {@link #getImageURLs()}, {@link #getSponsorImageURLs()} and {@link #getLogoImageURL()}
* determines the image dimensions. The retrieval of the image size is started when the URL is added to this event, and the result is
* cached. Should the image change its size afterwards or change its availability status, this event won't notice unless the image is
* removed from this event and added again.<p>
*
* Note that exceptions may result should the image be unavailable. If the image URL leads to a document that is not an image,
* <code>null</code> will result.
*/
ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException;
}
package com.sap.sailing.domain.base;
import java.util.UUID;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
/**
* An event is a group of {@link Regatta regattas} carried out at a common venue within a common time frame. For
* example, Kiel Week 2011 is an event, and the International German Championship 2011 held, e.g., in Travem�nde, is an event,
* too.
*
* @author Axel Uhl (D043530)
*
*/
public interface Event extends EventBase {
Iterable<Regatta> getRegattas();
void addRegatta(Regatta regatta);
void removeRegatta(Regatta regatta);
/**
* For events, the ID is always a UUID.
*/
UUID getId();
/**
* Returns a non-<code>null</code> live but unmodifiable collection of leaderboard groups that were previously
* {@link #addLeaderboardGroup(LeaderboardGroup) added} to this event, in the order of their addition. Therefore, to
* change the iteration order, {@link #removeLeaderboardGroup(LeaderboardGroup)} and
* {@link #addLeaderboardGroup(LeaderboardGroup)} need to be used.
*/
@Override
Iterable<LeaderboardGroup> getLeaderboardGroups();
void addLeaderboardGroup(LeaderboardGroup leaderboardGroup);
/**
* @return <code>true</code> if and only if a leaderboard group equal to <code>leaderboardGroup</code> was part of
* {@link #getLeaderboardGroups()} and therefore was actually removed
*/
boolean removeLeaderboardGroup(LeaderboardGroup leaderboardGroup);
/**
* Replaces the {@link #getLeaderboardGroups() current contents of the leaderboard groups sequence} by the
* leaderboard groups in <code>leaderboardGroups</code>.
*/
void setLeaderboardGroups(Iterable<LeaderboardGroup> leaderboardGroups);
}
@@ -2,47 +2,26 @@ package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Venue;
import com.sap.sailing.domain.common.impl.ImageSizeImpl;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.media.ImageSize;
public class EventImpl extends EventBaseImpl implements Event {
private static final long serialVersionUID = 855135446595485715L;
private static final Logger logger = Logger.getLogger(EventImpl.class.getName());
private final Set<Regatta> regattas;
private ConcurrentLinkedQueue<LeaderboardGroup> leaderboardGroups;
private transient ConcurrentHashMap<URL, Future<ImageSize>> imageSizeFetchers;
private transient ExecutorService executor;
public EventImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id) {
this(name, startDate, endDate, new VenueImpl(venueName), isPublic, id);
}
@@ -54,8 +33,6 @@ public class EventImpl extends EventBaseImpl implements Event {
super(name, startDate, endDate, venue, isPublic, id);
this.regattas = new HashSet<Regatta>();
this.leaderboardGroups = new ConcurrentLinkedQueue<>();
this.imageSizeFetchers = new ConcurrentHashMap<>();
this.executor = Executors.newCachedThreadPool();
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
@@ -63,8 +40,6 @@ public class EventImpl extends EventBaseImpl implements Event {
if (leaderboardGroups == null) {
leaderboardGroups = new ConcurrentLinkedQueue<>();
}
this.imageSizeFetchers = new ConcurrentHashMap<>();
this.executor = Executors.newCachedThreadPool();
}
@Override
@@ -106,110 +81,4 @@ public class EventImpl extends EventBaseImpl implements Event {
public boolean removeLeaderboardGroup(LeaderboardGroup leaderboardGroup) {
return leaderboardGroups.remove(leaderboardGroup);
}
private Future<ImageSize> getOrCreateImageSizeCalculator(final URL imageURL) {
Future<ImageSize> imageSizeFetcher = imageSizeFetchers.get(imageURL);
if (imageSizeFetcher == null) {
imageSizeFetcher = executor.submit(new Callable<ImageSize>() {
@Override
public ImageSize call() throws IOException {
ImageSize result = null;
ImageInputStream in = null;
try {
URLConnection conn = imageURL.openConnection();
in = ImageIO.createImageInputStream(conn.getInputStream());
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
result = new ImageSizeImpl(reader.getWidth(0), reader.getHeight(0));
} finally {
reader.dispose();
}
}
} catch (IOException ioe) {
logger.log(Level.SEVERE, "Stale image link "+imageURL+" for event "+getName()+". Please double-check and replace or remove.", ioe);
throw ioe;
} finally {
if (in != null) {
in.close();
}
}
return result;
}
});
imageSizeFetchers.put(imageURL, imageSizeFetcher);
}
return imageSizeFetcher;
}
@Override
public ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException {
Future<ImageSize> imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL);
return imageSizeCalculator.get();
}
@Override
public void addImageURL(URL imageURL) {
super.addImageURL(imageURL);
refreshImageSizeFetcher(imageURL);
}
private void refreshImageSizeFetcher(URL imageURL) {
if (imageURL != null) {
removeImageSizeFetcher(imageURL);
getOrCreateImageSizeCalculator(imageURL);
}
}
@Override
public void removeImageURL(URL imageURL) {
super.removeImageURL(imageURL);
removeImageSizeFetcher(imageURL);
}
private void removeImageSizeFetcher(URL imageURL) {
if (imageURL != null) {
imageSizeFetchers.remove(imageURL);
}
}
@Override
public void setImageURLs(Iterable<URL> imageURLs) {
super.setImageURLs(imageURLs);
if (imageURLs != null) {
for (URL imageURL : imageURLs) {
refreshImageSizeFetcher(imageURL);
}
}
}
@Override
public void addSponsorImageURL(URL sponsorImageURL) {
super.addSponsorImageURL(sponsorImageURL);
refreshImageSizeFetcher(sponsorImageURL);
}
@Override
public void removeSponsorImageURL(URL sponsorImageURL) {
super.removeSponsorImageURL(sponsorImageURL);
removeImageSizeFetcher(sponsorImageURL);
}
@Override
public void setSponsorImageURLs(Iterable<URL> sponsorImageURLs) {
super.setSponsorImageURLs(sponsorImageURLs);
if (sponsorImageURLs != null) {
for (URL imageURL : sponsorImageURLs) {
refreshImageSizeFetcher(imageURL);
}
}
}
@Override
public void setLogoImageURL(URL logoImageURL) {
super.setLogoImageURL(logoImageURL);
refreshImageSizeFetcher(logoImageURL);
}
}
@@ -3,18 +3,13 @@
xmlns:r="urn:import:com.sap.sailing.gwt.home.client.place.event.partials.raceListLive"
xmlns:o="urn:import:com.sap.sailing.gwt.home.client.place.event.overview">
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
.space-top {
margin-top: 2em;
}
</ui:style>
<g:HTMLPanel>
<o:EventOverviewStage ui:field="stage" />
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<r:RacesListLive ui:field="racesListLive" addStyleNames="{style.space-top}" />
<r:RacesListLive ui:field="racesListLive" addStyleNames="{res.mainCss.spacermargin} {res.mainCss.spacermargintopmediumbig}" />
</div>
</div>
<g:SimplePanel ui:field="content" addStyleNames="{style.space-top}" />
<g:SimplePanel ui:field="content" />
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,52 +1,20 @@
.countdown {
font-size: 1rem;
}
.countdown_content {
font-size: inherit;
}
.countdown_content_panewrapper {
font-size: 0;
}
.countdown_content_pane {
border: 0.2em solid #fff;
background: #008fcc;
color: #fff;
text-align: center;
display: inline-block;
margin-right: 0.333333333333333em;
padding: 0.666666666666667em 0.333333333333333em;
border-radius: 0.666666666666667em;
width: 4.666666666666667em;
height: 4.666666666666667em;
text-shadow: none;
box-shadow: 0 0 18px rgba(0,0,0,0.13), 0 2px 6px rgba(0,0,0,0.25);
}
.countdown_content_panefirst,
.countdown_content_panesecond,
.countdown_content_panethird,
.countdown_content_panefourth {
font-size: 1rem;
text-transform: uppercase;
}
.countdown_content_pane_count {
font-weight: bold;
font-size: 2em;
line-height: 1em;
}
.countdown_content_pane_unit {
font-size: 0.8em;
}
.countdown {
font-size: 1rem;
position: relative;
height: 28.333333333333332em;
margin-top: 1.333333333333333em;
}
@media (max-width: 976px) {
.countdown {
height: 22em;
}
}
.countdown_image {
width: 100%;
height: 100%;
background-size: 67.8em 50.46666666666667em;
background-position: center -0.933333333333333em;
background-image: url("../images/home/countdown-thumbnail.png");
}
.countdown_content {
position: absolute;
top: 50%;
@@ -63,12 +31,6 @@
font-size: 1.466666666666667em;
color: #f6f9fc;
}
.countdown_image {
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
}
.countdown_info {
position: absolute;
bottom: 0;
@@ -95,7 +57,6 @@
margin-top: 0.181818181818182em;
}
.countdown_info_lable {
width: 3.333333333333333em;
display: inline-block;
padding-left: 0.4em;
margin-left: 1.333333333333333em;
@@ -21,6 +21,7 @@ import com.sap.sailing.gwt.home.client.app.PlaceNavigation;
import com.sap.sailing.gwt.home.client.place.event.EventView;
import com.sap.sailing.gwt.home.client.place.event.EventView.Presenter;
import com.sap.sailing.gwt.home.client.place.event.partials.countdown.CountdownResources.LocalCss;
import com.sap.sailing.gwt.home.client.place.event.partials.countdownTimer.CountdownTimer;
import com.sap.sailing.gwt.home.client.shared.stage.StageResources;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewRaceTickerStageDTO;
@@ -72,7 +73,7 @@ public class Countdown extends Composite {
}
if(data.getStartTime() != null) {
this.tickerContainer.setWidget(new CountdownTicker(data.getStartTime()));
this.tickerContainer.setWidget(new CountdownTimer(data.getStartTime()));
} else {
this.tickerContainer.setWidget(null);
}
@@ -12,17 +12,9 @@ public interface CountdownResources extends ClientBundle {
public interface LocalCss extends CssResource {
String countdown();
String countdown_content();
String countdown_content_panewrapper();
String countdown_content_pane();
String countdown_content_panefirst();
String countdown_content_panesecond();
String countdown_content_panethird();
String countdown_content_panefourth();
String countdown_content_pane_count();
String countdown_content_pane_unit();
String countdown_content_title();
String countdown_image();
String countdown_content();
String countdown_content_title();
String countdown_info();
String countdown_info_text();
String countdown_info_text_title();
@@ -1,14 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" >
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.place.event.partials.countdown.CountdownResources" />
<g:HTMLPanel ui:field="countdown" addStyleNames="{local_res.css.countdown_content_panewrapper}">
<div ui:field="majorContainer" class="{local_res.css.countdown_content_pane} {local_res.css.countdown_content_panefirst}">
<div ui:field="majorValue" class="{local_res.css.countdown_content_pane_count}"></div>
<div ui:field="majorUnit" class="{local_res.css.countdown_content_pane_unit}"></div>
</div>
<div ui:field="minorContainer" class="{local_res.css.countdown_content_pane} {local_res.css.countdown_content_panesecond}">
<div ui:field="minorValue" class="{local_res.css.countdown_content_pane_count}"></div>
<div ui:field="minorUnit" class="{local_res.css.countdown_content_pane_unit}"></div>
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -0,0 +1,41 @@
/**
* Styles for countdown on the stage
*/
.countdowntimer {
font-size: 1rem;
}
.countdowntimer_content {
font-size: inherit;
}
.countdowntimer_content_panewrapper {
font-size: 0;
}
.countdowntimer_content_pane {
border: 0.2em solid #fff;
background: #008fcc;
color: #fff;
text-align: center;
display: inline-block;
margin-right: 0.333333333333333em;
padding: 0.666666666666667em 0.333333333333333em;
border-radius: 0.666666666666667em;
width: 4.666666666666667em;
height: 4.666666666666667em;
text-shadow: none;
box-shadow: 0 0 18px rgba(0,0,0,0.13), 0 2px 6px rgba(0,0,0,0.25);
}
.countdowntimer_content_panefirst,
.countdowntimer_content_panesecond,
.countdowntimer_content_panethird,
.countdowntimer_content_panefourth {
font-size: 1rem;
text-transform: uppercase;
}
.countdowntimer_content_pane_count {
font-weight: bold;
font-size: 2em;
line-height: 1em;
}
.countdowntimer_content_pane_unit {
font-size: 0.8em;
}
@@ -1,24 +1,24 @@
package com.sap.sailing.gwt.home.client.place.event.partials.countdown;
package com.sap.sailing.gwt.home.client.place.event.partials.countdownTimer;
import java.util.Date;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.client.shared.Countdown;
import com.sap.sailing.gwt.home.client.shared.Countdown.CountdownListener;
import com.sap.sailing.gwt.home.client.shared.Countdown.RemainingTime;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class CountdownTicker extends Composite {
public class CountdownTimer extends Widget {
private static CountdownTickerUiBinder uiBinder = GWT.create(CountdownTickerUiBinder.class);
interface CountdownTickerUiBinder extends UiBinder<Widget, CountdownTicker> {
interface CountdownTickerUiBinder extends UiBinder<Element, CountdownTimer> {
}
@UiField DivElement majorContainer, majorValue, majorUnit;
@@ -26,8 +26,9 @@ public class CountdownTicker extends Composite {
private final Countdown countdown;
public CountdownTicker(Date startTime) {
initWidget(uiBinder.createAndBindUi(this));
public CountdownTimer(Date startTime) {
CountdownTimerResources.INSTANCE.css().ensureInjected();
setElement(uiBinder.createAndBindUi(this));
this.countdown = new Countdown(new MillisecondsTimePoint(startTime), new CountdownTickerListener());
}
@@ -0,0 +1,16 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared">
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.place.event.partials.countdownTimer.CountdownTimerResources" />
<div class="{local_res.css.countdowntimer}">
<div class="{local_res.css.countdowntimer_content}">
<div ui:field="majorContainer" class="{local_res.css.countdowntimer_content_pane} {local_res.css.countdowntimer_content_panefirst}">
<div ui:field="majorValue" class="{local_res.css.countdowntimer_content_pane_count}"></div>
<div ui:field="majorUnit" class="{local_res.css.countdowntimer_content_pane_unit}"></div>
</div>
<div ui:field="minorContainer" class="{local_res.css.countdowntimer_content_pane} {local_res.css.countdowntimer_content_panesecond}">
<div ui:field="minorValue" class="{local_res.css.countdowntimer_content_pane_count}"></div>
<div ui:field="minorUnit" class="{local_res.css.countdowntimer_content_pane_unit}"></div>
</div>
</div>
</div>
</ui:UiBinder>
@@ -0,0 +1,25 @@
package com.sap.sailing.gwt.home.client.place.event.partials.countdownTimer;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface CountdownTimerResources extends ClientBundle {
public static final CountdownTimerResources INSTANCE = GWT.create(CountdownTimerResources.class);
@Source("CountdownTimer.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String countdowntimer();
String countdowntimer_content();
String countdowntimer_content_panewrapper();
String countdowntimer_content_pane();
String countdowntimer_content_panefirst();
String countdowntimer_content_panesecond();
String countdowntimer_content_panethird();
String countdowntimer_content_panefourth();
String countdowntimer_content_pane_count();
String countdowntimer_content_pane_unit();
}
}
@@ -103,7 +103,7 @@ public class EventHeader extends Composite {
}
private void initFields() {
String logoUrl = event.getLogoImageURL() != null ? event.getLogoImageURL() : EventHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri().asString();
String logoUrl = event.getLogoImage() != null ? event.getLogoImage().getSourceRef() : EventHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri().asString();
eventLogo.getStyle().setBackgroundImage("url(" + logoUrl + ")");
eventLogo.setTitle(event.getDisplayName());
@@ -7,7 +7,7 @@
<o:EventOverviewStage ui:field="stage" />
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<r:RacesListLive ui:field="racesListLive" />
<r:RacesListLive ui:field="racesListLive" addStyleNames="{res.mainCss.spacermargin} {res.mainCss.spacermargintopmediumbig}" />
</div>
</div>
</g:HTMLPanel>
@@ -73,7 +73,7 @@ public class SeriesHeader extends Composite {
}
private void initFields() {
String logoUrl = series.getLogoImageURL() != null ? series.getLogoImageURL() : SeriesHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri().asString();
String logoUrl = series.getLogoImage() != null ? series.getLogoImage().getSourceRef() : SeriesHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri().asString();
eventLogo.getStyle().setBackgroundImage("url(" + logoUrl + ")");
eventLogo.setTitle(series.getDisplayName());
eventName.setInnerText(series.getDisplayName());
@@ -14,9 +14,6 @@ import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
@@ -42,8 +39,8 @@ import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO.EventSeriesSt
import com.sap.sailing.gwt.ui.shared.general.EventMetadataDTO;
import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO;
import com.sap.sailing.gwt.ui.shared.general.EventState;
import com.sap.sailing.gwt.ui.shared.media.MediaConstants;
import com.sap.sailing.gwt.ui.shared.media.MediaDTO;
import com.sap.sailing.gwt.ui.shared.media.MediaUtils;
import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO;
import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO;
import com.sap.sailing.gwt.ui.shared.start.EventStageDTO;
@@ -57,9 +54,11 @@ import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.MediaType;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.util.ServiceTrackerFactory;
/**
@@ -93,7 +92,6 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
}
private static final long serialVersionUID = 3947782997746039939L;
private static final Logger logger = Logger.getLogger(HomeServiceImpl.class.getName());
private static final int MAX_STAGE_EVENTS = 5;
private static final int MAX_RECENT_EVENTS = 3;
@@ -183,14 +181,14 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventReferenceDTO eventRef = new EventReferenceDTO(holder.event);
Iterable<URL> videosOfEvent = holder.event.getVideoURLs();
Iterable<VideoDescriptor> videosOfEvent = holder.event.getVideos();
if (!Util.isEmpty(videosOfEvent) && result.getVideos().size() < MAX_VIDEO_COUNT) {
URL youTubeRandomUrl = HomeServiceUtil.getRandomURL(videosOfEvent);
VideoDescriptor youTubeRandomUrl = HomeServiceUtil.getRandomVideo(videosOfEvent);
MimeType type = MediaUtils.detectMimeTypeFromUrl(youTubeRandomUrl.toString());
if (type.mediaType == MediaType.video) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.toString(), type, //
holder.event.getEndDate().asDate() // FIXME: using event enddate for now
MimeType type = youTubeRandomUrl.getMimeType();
if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.getURL().toString(), type, //
youTubeRandomUrl.getCreatedAtDate().asDate()
);
candidate.setTitle(holder.event.getName());
result.addVideo(candidate);
@@ -217,22 +215,18 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventBase event = holder.event;
EventReferenceDTO eventRef = new EventReferenceDTO(holder.event);
for (URL url : HomeServiceUtil.getSailingLovesPhotographyImages(event)) {
try {
ImageSize imageSize = event.getImageSize(url);
if(imageSize != null) {
// TODO: do we habe a title?
photoGalleryUrls.add(new SailingImageDTO(eventRef, url.toString(), imageSize, null));
}
} catch (Exception e) {
for (ImageDescriptor url : HomeServiceUtil.getSailingLovesPhotographyImages(event)) {
if(url.hasSize()) {
SailingImageDTO sailingImageDTO = new SailingImageDTO(eventRef, url.getURL().toString(), null);
sailingImageDTO.setSizeInPx(url.getWidthInPx(), url.getHeightInPx());
photoGalleryUrls.add(sailingImageDTO);
}
}
for (URL videoUrl : event.getVideoURLs()) {
MimeType type = MediaUtils.detectMimeTypeFromUrl(videoUrl.toString());
if (type.mediaType == MediaType.video) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.toString(), type, //
holder.event.getEndDate().asDate() // FIXME: using event enddate for now
for (VideoDescriptor videoUrl : event.getVideos()) {
MimeType type = videoUrl.getMimeType();
if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.getURL().toString(), type, //
videoUrl.getCreatedAtDate().asDate()
);
candidate.setTitle(holder.event.getName());
videoCandidates.add(candidate);
@@ -281,7 +275,8 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventViewDTO dto = new EventViewDTO();
mapToMetadataDTO(event, dto);
dto.setLogoImageURL(event.getLogoImageURL() == null ? null : event.getLogoImageURL().toString());
ImageDescriptor logoImage = event.findImageWithTag(MediaTagConstants.LOGO);
dto.setLogoImage(logoImage != null ? convertToImageDTO(logoImage) : null);
dto.setOfficialWebsiteURL(event.getOfficialWebsiteURL() == null ? null : event.getOfficialWebsiteURL().toString());
dto.setHasMedia(HomeServiceUtil.hasMedia(event));
@@ -345,8 +340,8 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
dto.setType(dto.getRegattas().size() == 1 ? EventType.SINGLE_REGATTA: EventType.MULTI_REGATTA);
}
// TODO fmittag: put in correct event ID
if("406cffc2-b491-4f7e-b78e-a21abd97006a".equals(event.getId().toString())) {
// Special solution for Kieler Woche 2015
if("a9d6c5d5-cac3-47f2-9b5c-506e441819a1".equals(event.getId().toString())) {
dto.setSailorsInfoURL("http://sailorsinfo.kieler-woche.de/");
}
@@ -373,7 +368,8 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventSeriesViewDTO dto = new EventSeriesViewDTO();
dto.setId(id);
dto.setLogoImageURL(o.getLogoImageURL() == null ? null : o.getLogoImageURL().toString());
ImageDescriptor logoImage = o.findImageWithTag(MediaTagConstants.LOGO);
dto.setLogoImage(logoImage != null ? convertToImageDTO(logoImage) : null);
// TODO implement correctly. We currently do not show media for series.
dto.setHasMedia(false);
@@ -430,25 +426,20 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventReferenceDTO eventRef = new EventReferenceDTO(event);
String eventName = event.getName();
// TODO implement correctly and fill metadata
MediaDTO media = new MediaDTO();
for(URL url : HomeServiceUtil.getPhotoGalleryImageURLs(event)) {
ImageSize imageSize = null;
try {
imageSize = event.getImageSize(url);
} catch (InterruptedException | ExecutionException e) {
logger.log(Level.FINE, "Was unable to obtain image size for "+url+" earlier.", e);
}
SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), imageSize, //
event.getEndDate().asDate() // FIXME: using the event end date for now, we need a better solution for migration
);
entry.setTitle(eventName);
for(ImageDescriptor image : HomeServiceUtil.getPhotoGalleryImages(event)) {
SailingImageDTO entry = new SailingImageDTO(eventRef, image.getURL().toString(), image.getCreatedAtDate().asDate());
entry.setSizeInPx(image.getWidthInPx(), image.getHeightInPx());
entry.setTitle(image.getTitle() != null ? image.getTitle(): eventName);
entry.setSubtitle(image.getSubtitle());
entry.setTags(image.getTags());
entry.setCopyright(image.getCopyright());
media.addPhoto(entry);
}
for(URL url : event.getVideoURLs()) {
MimeType type = MediaUtils.detectMimeTypeFromUrl(url.toString());
if (type.mediaType == MediaType.video) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.toString(), type, null);
for(VideoDescriptor url : event.getVideos()) {
MimeType type = url.getMimeType();
if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) {
SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.getURL().toString(), type, null);
media.addVideo(candidate);
}
}
@@ -534,4 +525,20 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
}
return null;
}
private ImageDTO convertToImageDTO(ImageDescriptor image) {
ImageDTO result = new ImageDTO(image.getURL().toString(), image.getCreatedAtDate() != null ? image.getCreatedAtDate().asDate() : null);
result.setCopyright(image.getCopyright());
result.setTitle(image.getTitle());
result.setSubtitle(image.getSubtitle());
result.setMimeType(image.getMimeType());
result.setSizeInPx(image.getWidthInPx(), image.getHeightInPx());
result.setLocale(image.getLocale() != null ? image.getLocale().toString() : null);
List<String> tags = new ArrayList<String>();
for(String tag: image.getTags()) {
tags.add(tag);
}
result.setTags(tags);
return result;
}
}
@@ -1,15 +1,13 @@
package com.sap.sailing.gwt.server;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseArea;
@@ -25,20 +23,23 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.gwt.ui.shared.eventview.HasRegattaMetadata.RegattaState;
import com.sap.sailing.gwt.ui.shared.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.ui.shared.general.EventState;
import com.sap.sailing.gwt.ui.shared.media.MediaConstants;
import com.sap.sse.common.Util;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.MediaDescriptor;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.VideoDescriptor;
public final class HomeServiceUtil {
private HomeServiceUtil() {
}
private static final int MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS = 500;
private static final String STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE = "stage";
private static final String THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE = "eventteaser";
public static String findEventThumbnailImageUrlAsString(EventBase event) {
URL url = findEventThumbnailImageUrl(event);
return url == null ? null : url.toString();
ImageDescriptor url = findEventThumbnailImage(event);
return url == null ? null : url.getURL().toString();
}
public static boolean isFakeSeries(EventBase event) {
@@ -100,47 +101,43 @@ public final class HomeServiceUtil {
return EventState.RUNNING;
}
private static URL findEventThumbnailImageUrl(EventBase event) {
private static ImageDescriptor findEventThumbnailImage(EventBase event) {
final class ImageHolder {
final int PERFECT_HEIGHT = 240;
final int PERFECT_WIDTH = 370;
final double PERFECT_RATIO = PERFECT_HEIGHT / (double) PERFECT_WIDTH;
final URL url;
final int height;
final int width;
final int size;
final double ratio;
final ImageDescriptor image;
final boolean stage;
ImageHolder() {
this(null, null);
this(null);
}
ImageHolder(URL url, ImageSize imageSize) {
this(url, imageSize == null ? -1 : imageSize.getWidth(), imageSize == null ? -1 : imageSize.getHeight());
}
ImageHolder(URL url, int width, int height) {
this.url = url;
this.height = height;
this.width = width;
if(width == -1 || height == -1) {
this.size = -1;
ImageHolder(ImageDescriptor image) {
this.image = image;
this.stage = image == null ? false : hasTag(image, MediaTagConstants.STAGE);
this.height = image == null || image.getHeightInPx() == null ? 0 : image.getHeightInPx();
this.width = image == null || image.getWidthInPx() == null ? 0 : image.getWidthInPx();
this.size = height * width;
if(width == 0) {
this.ratio = -1;
} else {
this.size = height * width;
this.ratio = height / (double) width;
}
}
boolean isBetterWorstcaseThan(ImageHolder otherImageHolder) {
if (isNull()) {
return false;
}
if (this.url != null && url.toString().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
if (stage) {
return false;
}
@@ -175,13 +172,13 @@ public final class HomeServiceUtil {
}
boolean isNull() {
return size == -1;
return image == null;
}
}
// search for name pattern
for (URL imageUrl : event.getImageURLs()) {
if (imageUrl.toString().toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
for (ImageDescriptor imageUrl : event.getImages()) {
if (hasTag(imageUrl, MediaTagConstants.TEASER)) {
return imageUrl;
}
}
@@ -189,16 +186,11 @@ public final class HomeServiceUtil {
ImageHolder actualWorstcase = new ImageHolder();
ImageHolder bestFit = new ImageHolder();
for (URL candidateImageUrl : getPhotoGalleryImageURLs(event)) {
ImageHolder candidate;
try {
candidate = new ImageHolder(candidateImageUrl, event.getImageSize(candidateImageUrl));
} catch (Exception e) {
candidate = new ImageHolder(candidateImageUrl, -1, -1);
}
for (ImageDescriptor candidateImage : getPhotoGalleryImages(event)) {
ImageHolder candidate = new ImageHolder(candidateImage);
if (candidate.isPerfectFit()) {
return candidate.url;
return candidate.image;
}
if (candidate.fitsRatio() && candidate.isBigEnough()) {
@@ -214,20 +206,20 @@ public final class HomeServiceUtil {
}
if (!bestFit.isNull()) {
return bestFit.url;
return bestFit.image;
}
if (!actualWorstcase.isNull()) {
return actualWorstcase.url;
return actualWorstcase.image;
}
return null;
}
/**
* The stage image is determined from the {@link #imageURLs} collection by a series of heuristics and fall-back
* The stage image is determined from the {@link #images} collection by a series of heuristics and fall-back
* rules:
* <ol>
* <li>If one or more image URLs has "stage" (ignoring case) in its name, only they are considered candidates.</li>
* <li>If no image URL has "stage" (ignoring case) in its name, all images from {@link #imageURLs} are considered
* <li>If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.</li>
* <li>If no image has {@link MediaConstants#STAGE} tag, all images are considered
* candidates.</li>
* <li>From all candidates, the one with the biggest known size (determined by the product of width and height) is
* chosen.</li>
@@ -235,107 +227,88 @@ public final class HomeServiceUtil {
* </ol>
*/
public static String getStageImageURLAsString(final EventBase event) {
URL url = getStageImageURL(event);
return url == null ? null : url.toString();
ImageDescriptor image = getStageImage(event);
return image == null ? null : image.getURL().toString();
}
/**
* The stage image is determined from the {@link #imageURLs} collection by a series of heuristics and fall-back
* The stage image is determined from the {@link #images} collection by a series of heuristics and fall-back
* rules:
* <ol>
* <li>If one or more image URLs has "stage" (ignoring case) in its name, only they are considered candidates.</li>
* <li>If no image URL has "stage" (ignoring case) in its name, all images from {@link #imageURLs} are considered
* <li>If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.</li>
* <li>If no image has {@link MediaConstants#STAGE} tag, all images are considered
* candidates.</li>
* <li>From all candidates, the one with the biggest known size (determined by the product of width and height) is
* chosen.</li>
* <li>If the size isn't known for any candidate, the first candidate in {@link #imageURLs} is picked.</li>
* </ol>
*/
public static URL getStageImageURL(final EventBase event) {
final URL result;
if (Util.isEmpty(event.getImageURLs())) {
result = null;
} else {
Comparator<URL> stageImageComparator = new Comparator<URL>() {
@Override
public int compare(URL url1, URL url2) {
String o1 = url1.toString();
String o2 = url2.toString();
int result;
int o1NameHack = o1.toLowerCase().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE) ? 1 :
o1.toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE) ? -1 : 0;
int o2NameHack = o2.toLowerCase().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE) ? 1 :
o2.toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE) ? -1 : 0;
final int preResultBasedOnNameHack = o1NameHack - o2NameHack;
if (preResultBasedOnNameHack == 0) {
try {
result = compareBySize(url1, url2);
} catch (Exception e) {
result = 0;
}
} else {
result = preResultBasedOnNameHack;
}
return result;
}
private int compareBySize(URL o1, URL o2) throws InterruptedException, ExecutionException {
final int result;
final ImageSize o1Size = event.getImageSize(o1);
final ImageSize o2Size = event.getImageSize(o2);
result = (o1Size == null ? 0 : (o1Size.getWidth() * o1Size.getHeight()))
- (o2Size == null ? 0 : (o2Size.getWidth() * o2Size.getHeight()));
return result;
}
};
List<URL> sortedImageURLs = new ArrayList<>();
for (URL url : event.getImageURLs()) {
sortedImageURLs.add(url);
}
Collections.sort(sortedImageURLs, stageImageComparator);
result = sortedImageURLs.get(sortedImageURLs.size() - 1);
}
return result;
}
public static List<String> getPhotoGalleryImageURLsAsString(EventBase event) {
List<URL> urls = getPhotoGalleryImageURLs(event);
List<String> result = new ArrayList<String>(urls.size());
for (URL url : urls) {
result.add(url.toString());
}
return result;
}
public static List<URL> getPhotoGalleryImageURLs(EventBase event) {
URL stageImageURL = getStageImageURL(event); // if set, exclude stage image from photo gallery
List<URL> result = new ArrayList<>();
Iterable<URL> imageURLs = event.getImageURLs();
public static ImageDescriptor getStageImage(final EventBase event) {
ImageDescriptor bestMatch = null;
boolean first = true;
for (Iterator<URL> iter = imageURLs.iterator(); iter.hasNext(); ) {
URL imageUrl = iter.next();
if(imageUrl.toString().toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
for(ImageDescriptor candidate : event.getImages()) {
if(bestMatch == null || isBetterStageImage(candidate, bestMatch)) {
bestMatch = candidate;
continue;
}
if ((first && !iter.hasNext()) || !Util.equalsWithNull(imageUrl, stageImageURL)) {
result.add(imageUrl);
}
return bestMatch;
}
private static boolean isBetterStageImage(ImageDescriptor candidate, ImageDescriptor reference) {
boolean stage = hasTag(candidate, MediaTagConstants.STAGE);
boolean stageRef = hasTag(reference, MediaTagConstants.STAGE);
if(stage != stageRef) {
return stage;
}
boolean teaser = hasTag(candidate, MediaTagConstants.TEASER);
boolean teaserRef = hasTag(reference, MediaTagConstants.TEASER);
if(teaser != teaserRef) {
return !teaser;
}
int size = candidate.getArea();
int sizeRef = candidate.getArea();
if(size != sizeRef) {
return size > sizeRef;
}
return candidate.getCreatedAtDate().compareTo(reference.getCreatedAtDate()) > 0;
}
public static List<String> getPhotoGalleryImageURLsAsString(EventBase event) {
List<ImageDescriptor> urls = getPhotoGalleryImages(event);
List<String> result = new ArrayList<String>(urls.size());
for (ImageDescriptor url : urls) {
result.add(url.getURL().toString());
}
return result;
}
public static List<ImageDescriptor> getPhotoGalleryImages(EventBase event) {
ImageDescriptor stageImage = getStageImage(event); // if set, exclude stage image from photo gallery
List<ImageDescriptor> result = new ArrayList<>();
Iterable<ImageDescriptor> imageURLs = event.getImages();
boolean first = true;
for (Iterator<ImageDescriptor> iter = imageURLs.iterator(); iter.hasNext(); ) {
ImageDescriptor image = iter.next();
if(hasTag(image, MediaTagConstants.TEASER)) {
continue;
}
if ((first && !iter.hasNext()) || !Util.equalsWithNull(image, stageImage)) {
result.add(image);
}
first = false;
}
return result;
}
public static List<URL> getSailingLovesPhotographyImages(EventBase event) {
final List<URL> acceptedImages = new LinkedList<>();
for (URL candidateImageUrl : event.getImageURLs()) {
try {
ImageSize imageSize = event.getImageSize(candidateImageUrl);
if (imageSize != null && imageSize.getHeight() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) {
acceptedImages.add(candidateImageUrl);
}
} catch (Exception e) {
// TODO what should we do here?
public static List<ImageDescriptor> getSailingLovesPhotographyImages(EventBase event) {
final List<ImageDescriptor> acceptedImages = new LinkedList<>();
for (ImageDescriptor candidateImageUrl : event.getImages()) {
if (candidateImageUrl.hasSize() && candidateImageUrl.getHeightInPx() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) {
acceptedImages.add(candidateImageUrl);
}
}
return acceptedImages;
@@ -389,12 +362,16 @@ public final class HomeServiceUtil {
}
public static boolean hasPhotos(Event event) {
// FIXME filter teaser images
return Util.size(event.getImageURLs()) > 1;
for(ImageDescriptor image : event.getImages()) {
if(!hasTag(image, MediaTagConstants.TEASER)) {
return true;
}
}
return false;
}
public static boolean hasVideos(Event event) {
return !Util.isEmpty(event.getVideoURLs());
return !Util.isEmpty(event.getVideos());
}
public static boolean isPartOfEvent(Event event, Regatta regattaEntity) {
@@ -406,11 +383,97 @@ public final class HomeServiceUtil {
return false;
}
public static URL getRandomURL(Iterable<URL> urls) {
public static VideoDescriptor getRandomVideo(Iterable<VideoDescriptor> urls) {
if(Util.isEmpty(urls)) {
return null;
}
int size = Util.size(urls);
return Util.get(urls, new Random(size).nextInt(size));
}
public static VideoDescriptor getStageVideo(Event event, Locale locale, Collection<String> rankedTags, boolean acceptOtherTags) {
VideoDescriptor bestMatch = null;
for (VideoDescriptor videoCandidate : event.getVideos()) {
if(!MediaConstants.SUPPORTED_VIDEO_TYPES.contains(videoCandidate.getMimeType())) {
continue;
}
if(!acceptOtherTags && !hasOneTag(videoCandidate, rankedTags)) {
continue;
}
LocaleMatch localeMatch = matchLocale(videoCandidate, locale);
if(localeMatch == LocaleMatch.NO_MATCH) {
continue;
}
if(bestMatch == null) {
bestMatch = videoCandidate;
continue;
}
int compareByTag = compareByTag(videoCandidate, bestMatch, rankedTags);
if(compareByTag > 0 || (compareByTag == 0 && isBetter(videoCandidate, bestMatch, locale))) {
bestMatch = videoCandidate;
continue;
}
}
return bestMatch;
}
private static int compareByTag(VideoDescriptor videoCandidate, VideoDescriptor bestMatch,
Collection<String> rankedTags) {
for(String rankedTag : rankedTags) {
boolean hasTag = hasTag(videoCandidate, rankedTag);
boolean hasTagBestMatch = hasTag(bestMatch, rankedTag);
if(hasTag != hasTagBestMatch) {
return hasTag ? 1 : -1;
}
}
return 0;
}
private static boolean isBetter(VideoDescriptor candidate, VideoDescriptor reference, Locale locale) {
LocaleMatch localeMatch = matchLocale(candidate, locale);
LocaleMatch localeMatchRef = matchLocale(reference, locale);
if(localeMatch != localeMatchRef) {
return localeMatch.compareTo(localeMatchRef) < 0 ? true : false;
}
// TODO filter by length
return candidate.getCreatedAtDate().compareTo(reference.getCreatedAtDate()) > 0;
}
private static boolean hasTag(MediaDescriptor videoCandidate, String tag) {
return Util.contains(videoCandidate.getTags(), tag);
}
private static boolean hasOneTag(MediaDescriptor videoCandidate, Collection<String> acceptedTags) {
for(String tag : videoCandidate.getTags()) {
if(acceptedTags.contains(tag)) {
return true;
}
}
return false;
}
private enum LocaleMatch {
PERFECT, NOT_TAGGED, EN_FALLBACK, NO_MATCH
}
private static LocaleMatch matchLocale(VideoDescriptor videoCandidate, Locale locale) {
Locale localeOfCandidate = videoCandidate.getLocale();
if(localeOfCandidate == null) {
return LocaleMatch.NOT_TAGGED;
}
if(videoCandidate.getLocale().equals(locale)) {
return LocaleMatch.PERFECT;
}
if(videoCandidate.getLocale().equals(Locale.ENGLISH)) {
return LocaleMatch.EN_FALLBACK;
}
return LocaleMatch.NO_MATCH;
}
}
@@ -8,6 +8,8 @@ import java.util.List;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
public class EventCreateDialog extends EventDialog {
@@ -29,9 +31,9 @@ public class EventCreateDialog extends EventDialog {
endDateBox.setFormat("dd/mm/yyyy hh:ii");
officialWebsiteURLEntryField = createTextBox(null);
officialWebsiteURLEntryField.setVisibleLength(50);
logoImageURLEntryField = createTextBox(null);
logoImageURLEntryField.setVisibleLength(50);
isPublicCheckBox = createCheckbox("");
isPublicCheckBox.setValue(false);
imagesListComposite.fillImages(Collections.<ImageDTO>emptyList());
videosListComposite.fillVideos(Collections.<VideoDTO>emptyList());
}
}
@@ -23,8 +23,9 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
public class EventDetailsComposite extends Composite {
private EventDTO event;
@@ -38,11 +39,9 @@ public class EventDetailsComposite extends Composite {
private final Label isPublic;
private final Anchor officialWebsiteURL;
private final Anchor eventOverviewURL;
private final Anchor logoImageURL;
private final SimpleStringListComposite courseAreaNamesList;
private final SimpleStringListComposite imageURLList;
private final SimpleStringListComposite videoURLList;
private final SimpleStringListComposite sponsorImageURLList;
private final SimpleStringListComposite leaderboardGroupList;
private final CaptionPanel mainPanel;
@@ -70,11 +69,9 @@ public class EventDetailsComposite extends Composite {
isPublic = createLabelAndValueWidget(grid, currentRow++, stringMessages.isPublic(), "IsPublicLabel");
officialWebsiteURL = createAnchorAndValueWidget(grid, currentRow++, stringMessages.eventOfficialWebsiteURL(), "OfficialWebsiteURLLabel");
eventOverviewURL = createAnchorAndValueWidget(grid, currentRow++, stringMessages.eventOverviewURL(), "EventOverviewURLLabel");
logoImageURL = createAnchorAndValueWidget(grid, currentRow++, stringMessages.eventLogoImageURL(), "LogoImageURLLabel");
courseAreaNamesList = createLableAndValueListWidget(grid, currentRow++, stringMessages.courseAreas(), "CourseAreaValueList");
imageURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.imageURLs(), "ImageURLValueList");
videoURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.videoURLs(), "VideoURLValueList");
sponsorImageURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.sponsorImageURLs(), "SponsorImageURLValueList");
imageURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.images(), "ImageURLValueList");
videoURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.videos(), "VideoURLValueList");
leaderboardGroupList = createLableAndValueListWidget(grid, currentRow++, stringMessages.leaderboardGroups(), "LeaderboardGroupValueList");
for(int i=0; i < rows; i++) {
@@ -136,8 +133,6 @@ public class EventDetailsComposite extends Composite {
String regattaOverviewLink = EntryPointLinkFactory.createRegattaOverviewLink(regattaOverviewURLParameters);
eventOverviewURL.setText(regattaOverviewLink);
eventOverviewURL.setHref(regattaOverviewLink);
logoImageURL.setText(event.getLogoImageURL());
logoImageURL.setHref(event.getLogoImageURL());
List<String> courseAreaNames = new ArrayList<>();
if (event.venue.getCourseAreas() != null && event.venue.getCourseAreas().size() > 0) {
@@ -148,14 +143,15 @@ public class EventDetailsComposite extends Composite {
courseAreaNamesList.setValues(courseAreaNames);
List<String> imageURLStringsAsList = new ArrayList<>();
Util.addAll(event.getImageURLs(), imageURLStringsAsList);
for(ImageDTO image: event.getImages()) {
imageURLStringsAsList.add(image.getSourceRef());
}
imageURLList.setValues(imageURLStringsAsList);
List<String> videoURLStringsAsList = new ArrayList<>();
Util.addAll(event.getVideoURLs(), videoURLStringsAsList);
for(VideoDTO video: event.getVideos()) {
videoURLStringsAsList.add(video.getSourceRef());
}
videoURLList.setValues(videoURLStringsAsList);
List<String> sponsorImageURLStringsAsList = new ArrayList<>();
Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList);
sponsorImageURLList.setValues(sponsorImageURLStringsAsList);
List<String> leaderboardGroupNamesAsList = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) {
leaderboardGroupNamesAsList.add(leaderboardGroupDTO.getName());
@@ -1,7 +1,6 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -30,6 +29,8 @@ import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO> {
protected StringMessages stringMessages;
@@ -41,14 +42,12 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
protected CheckBox isPublicCheckBox;
protected UUID id;
protected TextBox officialWebsiteURLEntryField;
protected TextBox logoImageURLEntryField;
protected StringListInlineEditorComposite courseAreaNameList;
protected StringListInlineEditorComposite imageURLList;
protected StringListInlineEditorComposite videoURLList;
protected StringListInlineEditorComposite sponsorImageURLList;
protected StringConstantsListEditorComposite leaderboardGroupList;
protected List<LeaderboardGroupDTO> availableLeaderboardGroups;
protected ImagesListComposite imagesListComposite;
protected VideosListComposite videosListComposite;
protected static class EventParameterValidator implements Validator<EventDTO> {
private StringMessages stringMessages;
@@ -133,21 +132,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
SuggestedCourseAreaNames.suggestedCourseAreaNames, stringMessages.enterCourseAreaName(), 50));
courseAreaNameList.addValueChangeHandler(valueChangeHandler);
final List<String> imageSuggestionURLs = Arrays.asList(new String[] { "http://", "https://", "http://www.", "https://www" });
imageURLList = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(),
/* suggestValues */ imageSuggestionURLs, stringMessages.enterImageURL(), 80));
imageURLList.addValueChangeHandler(valueChangeHandler);
List<String> videoURLSuggestions = new ArrayList<>(imageSuggestionURLs);
videoURLSuggestions.add("http://www.youtube.com/watch?v=");
videoURLList = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(),
/* suggestValues */ videoURLSuggestions, stringMessages.enterVideoURL(), 80));
videoURLList.addValueChangeHandler(valueChangeHandler);
sponsorImageURLList = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(),
/* suggestValues */ imageSuggestionURLs, stringMessages.enterSponsorImageURL(), 80));
sponsorImageURLList.addValueChangeHandler(valueChangeHandler);
List<String> leaderboardGroupNames = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: availableLeaderboardGroups) {
leaderboardGroupNames.add(leaderboardGroupDTO.getName());
@@ -156,6 +140,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
new StringConstantsListEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(),
leaderboardGroupNames, "Select a leaderboard group..."));
leaderboardGroupList.addValueChangeHandler(valueChangeHandler);
imagesListComposite = new ImagesListComposite(stringMessages);
videosListComposite = new VideosListComposite(stringMessages);
}
@Override
@@ -170,7 +157,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
result.setName(nameEntryField.getText());
result.setDescription(descriptionEntryField.getText());
result.setOfficialWebsiteURL(officialWebsiteURLEntryField.getText().trim().isEmpty() ? null : officialWebsiteURLEntryField.getText().trim());
result.setLogoImageURL(logoImageURLEntryField.getText().trim().isEmpty() ? null : logoImageURLEntryField.getText().trim());
result.startDate = startDateBox.getValue();
result.endDate = endDateBox.getValue();
result.isPublic = isPublicCheckBox.getValue();
@@ -182,14 +168,11 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
courseAreaDTO.setName(courseAreaName);
courseAreas.add(courseAreaDTO);
}
for (String imageURL : imageURLList.getValue()) {
result.addImageURL(imageURL);
for(ImageDTO image: imagesListComposite.getAllImages()) {
result.addImage(image);
}
for (String videoURL : videoURLList.getValue()) {
result.addVideoURL(videoURL);
}
for (String sponsorImageURL : sponsorImageURLList.getValue()) {
result.addSponsorImageURL(sponsorImageURL);
for(VideoDTO video: videosListComposite.getAllVideos()) {
result.addVideo(video);
}
result.venue = new VenueDTO(venueEntryField.getText(), courseAreas);
return result;
@@ -204,7 +187,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
panel.add(additionalWidget);
}
Grid formGrid = new Grid(8, 2);
Grid formGrid = new Grid(7, 2);
panel.add(formGrid);
formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":"));
@@ -221,17 +204,14 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
formGrid.setWidget(5, 1, isPublicCheckBox);
formGrid.setWidget(6, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
formGrid.setWidget(6, 1, officialWebsiteURLEntryField);
formGrid.setWidget(7, 0, new Label(stringMessages.eventLogoImageURL() + ":"));
formGrid.setWidget(7, 1, logoImageURLEntryField);
TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX);
tabPanel.setHeight("250px");
panel.add(tabPanel);
tabPanel.add(new ScrollPanel(leaderboardGroupList), stringMessages.leaderboardGroups());
tabPanel.add(new ScrollPanel(courseAreaNameList), stringMessages.courseAreas());
tabPanel.add(new ScrollPanel(imageURLList), stringMessages.imageURLs());
tabPanel.add(new ScrollPanel(videoURLList), stringMessages.videoURLs());
tabPanel.add(new ScrollPanel(sponsorImageURLList), stringMessages.sponsorImageURLs());
tabPanel.add(new ScrollPanel(imagesListComposite), "Images");
tabPanel.add(new ScrollPanel(videosListComposite), "Videos");
return panel;
}
@@ -8,7 +8,6 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sse.common.Util;
public class EventEditDialog extends EventDialog {
public EventEditDialog(EventDTO event, Collection<EventDTO> otherExistingEvents, List<LeaderboardGroupDTO> availableLeaderboardGroups, StringMessages stringMessages, DialogCallback<EventDTO> callback) {
@@ -37,22 +36,13 @@ public class EventEditDialog extends EventDialog {
}
officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL());
officialWebsiteURLEntryField.setVisibleLength(50);
logoImageURLEntryField = createTextBox(event.getLogoImageURL());
logoImageURLEntryField.setVisibleLength(50);
courseAreaNameList.setValue(courseAreaNames);
List<String> imageURLStringsAsList = new ArrayList<>();
Util.addAll(event.getImageURLs(), imageURLStringsAsList);
imageURLList.setValue(imageURLStringsAsList);
List<String> videoURLStringsAsList = new ArrayList<>();
Util.addAll(event.getVideoURLs(), videoURLStringsAsList);
videoURLList.setValue(videoURLStringsAsList);
List<String> sponsorImageURLStringsAsList = new ArrayList<>();
Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList);
sponsorImageURLList.setValue(sponsorImageURLStringsAsList);
List<String> leaderboardGroupNames = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) {
leaderboardGroupNames.add(leaderboardGroupDTO.getName());
}
leaderboardGroupList.setValue(leaderboardGroupNames);
imagesListComposite.fillImages(event.getImages());
videosListComposite.fillVideos(event.getVideos());
}
}
@@ -283,12 +283,12 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
return builder.toSafeHtml();
}
};
TextColumn<EventDTO> imageURLsColumn = new TextColumn<EventDTO>() {
TextColumn<EventDTO> imagesColumn = new TextColumn<EventDTO>() {
@Override
public String getValue(EventDTO event) {
String result = "";
int imageCount = Util.size(event.getImageURLs());
int imageCount = Util.size(event.getImages());
if(imageCount > 0) {
result = imageCount + " image(s)";
}
@@ -296,11 +296,11 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
}
};
TextColumn<EventDTO> videoURLsColumn = new TextColumn<EventDTO>() {
TextColumn<EventDTO> videosColumn = new TextColumn<EventDTO>() {
@Override
public String getValue(EventDTO event) {
String result = "";
int videoCount = Util.size(event.getVideoURLs());
int videoCount = Util.size(event.getVideos());
if(videoCount > 0) {
result = videoCount + " video(s)";
}
@@ -308,18 +308,6 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
}
};
TextColumn<EventDTO> sponsorImageURLsColumn = new TextColumn<EventDTO>() {
@Override
public String getValue(EventDTO event) {
String result = "";
int sponsorImageCount = Util.size(event.getSponsorImageURLs());
if(sponsorImageCount > 0) {
result = sponsorImageCount + " sponsor image(s)";
}
return result;
}
};
SafeHtmlCell associatedRegattasCell = new SafeHtmlCell();
Column<EventDTO, SafeHtml> associatedRegattasColumn = new Column<EventDTO, SafeHtml>(associatedRegattasCell) {
@Override
@@ -358,9 +346,6 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
isPublicColumn.setSortable(true);
startEndDateColumn.setSortable(true);
courseAreasColumn.setSortable(true);
imageURLsColumn.setSortable(true);
videoURLsColumn.setSortable(true);
sponsorImageURLsColumn.setSortable(true);
leaderboardGroupsColumn.setSortable(true);
table.addColumn(eventSelectionCheckboxColumn, eventSelectionCheckboxColumn.getHeader());
@@ -370,9 +355,8 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
table.addColumn(isPublicColumn, stringMessages.isPublic());
table.addColumn(courseAreasColumn, stringMessages.courseAreas());
table.addColumn(leaderboardGroupsColumn, stringMessages.leaderboardGroups());
table.addColumn(imageURLsColumn, stringMessages.imageURLs());
table.addColumn(videoURLsColumn, stringMessages.videoURLs());
table.addColumn(sponsorImageURLsColumn, stringMessages.sponsorImageURLs());
table.addColumn(imagesColumn, stringMessages.images());
table.addColumn(videosColumn, stringMessages.videos());
table.addColumn(associatedRegattasColumn, stringMessages.regattas());
table.addColumn(eventActionColumn, stringMessages.actions());
table.setSelectionModel(eventSelectionCheckboxColumn.getSelectionModel(), eventSelectionCheckboxColumn.getSelectionManager());
@@ -507,8 +491,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
sailingService.updateEvent(oldEvent.id, oldEvent.getName(), updatedEvent.getDescription(),
updatedEvent.startDate, updatedEvent.endDate, updatedEvent.venue,
updatedEvent.isPublic, updatedEventLeaderboardGroupIds,
updatedEvent.getOfficialWebsiteURL(), updatedEvent.getLogoImageURL(),
updatedEvent.getImageURLs(), updatedEvent.getVideoURLs(), updatedEvent.getSponsorImageURLs(),
updatedEvent.getOfficialWebsiteURL(), updatedEvent.getImages(), updatedEvent.getVideos(),
new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable t) {
@@ -579,9 +562,8 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
courseAreaNames.add(courseAreaDTO.getName());
}
sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate,
newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImageURLs(),
newEvent.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getLogoImageURL(),
newEvent.getOfficialWebsiteURL(), new AsyncCallback<EventDTO>() {
newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(),
newEvent.getImages(), newEvent.getVideos(), new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable t) {
errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage());
@@ -0,0 +1,34 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Arrays;
import com.google.gwt.core.client.GWT;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.ImagesBarCell;
import com.sap.sse.gwt.client.IconResources;
public class ImageConfigImagesBarCell extends ImagesBarCell {
static final String ACTION_REMOVE = "ACTION_REMOVE";
static final String ACTION_EDIT = "ACTION_EDIT";
private final StringMessages stringMessages;
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
public ImageConfigImagesBarCell(StringMessages stringMessages) {
super();
this.stringMessages = stringMessages;
}
public ImageConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringMessages) {
super();
this.stringMessages = stringMessages;
}
@Override
protected Iterable<ImageSpec> getImageSpecs() {
return Arrays.asList(
new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(IconResources.INSTANCE.removeIcon()))
);
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.media.ImageDTO;
public class ImageCreateDialog extends ImageDialog {
public ImageCreateDialog(String initialTag, StringMessages stringMessages, DialogCallback<ImageDTO> callback) {
super(new ImageParameterValidator(stringMessages), stringMessages, callback);
createdAtLabel = new Label(creationDate.toString());
titleTextBox = createTextBox(null);
titleTextBox.setVisibleLength(50);
subtitleTextBox = createTextBox(null);
subtitleTextBox.setVisibleLength(50);
copyrightTextBox = createTextBox(null);
copyrightTextBox.setVisibleLength(50);
widthInPxBox = createIntegerBox(null, 10);
heightInPxBox = createIntegerBox(null, 10);
List<String> tags = new ArrayList<>();
if(initialTag != null && !initialTag.isEmpty()) {
tags.add(initialTag);
}
tagsListEditor.setValue(tags);
}
}
@@ -0,0 +1,155 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Image;
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.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.media.MediaConstants;
import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.media.ImageDTO;
public abstract class ImageDialog extends DataEntryDialog<ImageDTO> {
protected final StringMessages stringMessages;
protected final URLFieldWithFileUpload imageURLAndUploadComposite;
protected final Date creationDate;
protected Label createdAtLabel;
protected TextBox titleTextBox;
protected TextBox subtitleTextBox;
protected TextBox copyrightTextBox;
protected IntegerBox widthInPxBox;
protected IntegerBox heightInPxBox;
protected StringListInlineEditorComposite tagsListEditor;
final Image image;
protected static class ImageParameterValidator implements Validator<ImageDTO> {
private StringMessages stringMessages;
public ImageParameterValidator(StringMessages stringMessages) {
this.stringMessages = stringMessages;
}
@Override
public String getErrorMessage(ImageDTO imageToValidate) {
String errorMessage = null;
if(imageToValidate.getSourceRef() == null || imageToValidate.getSourceRef().isEmpty()) {
errorMessage = stringMessages.pleaseEnterNonEmptyUrl();
}
return errorMessage;
}
}
public ImageDialog(ImageParameterValidator validator, StringMessages stringMessages, DialogCallback<ImageDTO> callback) {
super(stringMessages.image(), null, stringMessages.ok(), stringMessages.cancel(), validator,
callback);
this.stringMessages = stringMessages;
this.creationDate = new Date();
getDialogBox().getWidget().setWidth("730px");
image = new Image();
image.addLoadHandler(new LoadHandler() {
@Override
public void onLoad(LoadEvent event) {
int width = image.getOffsetWidth();
int height = image.getOffsetHeight();
if(width > 0 && height > 0) {
widthInPxBox.setValue(width);
heightInPxBox.setValue(height);
}
}
});
image.getElement().getStyle().setPosition(Position.ABSOLUTE);
image.getElement().getStyle().setVisibility(Visibility.HIDDEN);
imageURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
imageURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
validate();
image.setUrl(event.getValue());
}
});
tagsListEditor = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
MediaConstants.imageTagSuggestions, "Enter tags for the image", 50));
}
@Override
protected ImageDTO getResult() {
ImageDTO result = new ImageDTO(imageURLAndUploadComposite.getURL(), creationDate);
result.setTitle(titleTextBox.getValue());
result.setSubtitle(subtitleTextBox.getValue());
result.setCopyright(copyrightTextBox.getValue());
if(widthInPxBox.getValue() != null && heightInPxBox.getValue() != null) {
result.setSizeInPx(widthInPxBox.getValue(), heightInPxBox.getValue());
}
List<String> tags = new ArrayList<String>();
for (String tag: tagsListEditor.getValue()) {
tags.add(tag);
}
result.setTags(tags);
return result;
}
@Override
protected Widget getAdditionalWidget() {
final VerticalPanel panel = new VerticalPanel();
panel.setWidth("100%");
Widget additionalWidget = super.getAdditionalWidget();
if (additionalWidget != null) {
panel.add(additionalWidget);
}
Grid formGrid = new Grid(8, 2);
panel.add(formGrid);
formGrid.setWidget(0, 0, new Label("Created at:"));
formGrid.setWidget(0, 1, createdAtLabel);
formGrid.setWidget(1, 0, new Label("Image URL:"));
formGrid.setWidget(1, 1, imageURLAndUploadComposite);
formGrid.setWidget(2, 0, new Label(stringMessages.title() + ":"));
formGrid.setWidget(2, 1, titleTextBox);
formGrid.setWidget(3, 0, new Label("Subtitle:"));
formGrid.setWidget(3, 1, subtitleTextBox);
formGrid.setWidget(4, 0, new Label("Copyright:"));
formGrid.setWidget(4, 1, copyrightTextBox);
formGrid.setWidget(5, 0, new Label("Width in px:"));
formGrid.setWidget(5, 1, widthInPxBox);
formGrid.setWidget(6, 0, new Label("Height in px:"));
formGrid.setWidget(6, 1, heightInPxBox);
formGrid.setWidget(7, 0, new Label("Tags:"));
formGrid.setWidget(7, 1, tagsListEditor);
panel.add(image);
return panel;
}
@Override
public void show() {
super.show();
imageURLAndUploadComposite.setFocus(true);
}
}
@@ -0,0 +1,27 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.media.ImageDTO;
public class ImageEditDialog extends ImageDialog {
public ImageEditDialog(ImageDTO image, StringMessages stringMessages, DialogCallback<ImageDTO> callback) {
super(new ImageParameterValidator(stringMessages), stringMessages, callback);
createdAtLabel = new Label(image.getCreatedAtDate().toString());
imageURLAndUploadComposite.setURL(image.getSourceRef());
titleTextBox = createTextBox(image.getTitle());
titleTextBox.setVisibleLength(50);
subtitleTextBox = createTextBox(image.getSubtitle());
subtitleTextBox.setVisibleLength(50);
copyrightTextBox = createTextBox(image.getCopyright());
copyrightTextBox.setVisibleLength(50);
widthInPxBox = createIntegerBox(image.getWidthInPx(), 10);
heightInPxBox = createIntegerBox(image.getHeightInPx(), 10);
List<String> tags = new ArrayList<String>();
tags.addAll(image.getTags());
tagsListEditor.setValue(tags);
}
}
@@ -0,0 +1,313 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Comparator;
import java.util.List;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.domain.common.impl.NaturalComparator;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.media.ImageDTO;
/**
* /** A composite showing the list of media images
*
* @author Frank Mittag (C5163974)
*/
public class ImagesListComposite extends Composite {
private final StringMessages stringMessages;
private CellTable<ImageDTO> imageTable;
private SingleSelectionModel<ImageDTO> imageSelectionModel;
private ListDataProvider<ImageDTO> imageListDataProvider;
private final Label noImagesLabel;
private final SimplePanel mainPanel;
private final VerticalPanel panel;
public static class AnchorCell extends AbstractCell<SafeHtml> {
@Override
public void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml safeHtml, SafeHtmlBuilder sb) {
sb.append(safeHtml);
}
}
interface AnchorTemplates extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<a target=\"_blank\" href=\"{0}\">{1}</a>")
SafeHtml cell(String url, String displayName);
}
private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
public ImagesListComposite(final StringMessages stringMessages) {
this.stringMessages = stringMessages;
mainPanel = new SimplePanel();
panel = new VerticalPanel();
mainPanel.setWidget(panel);
HorizontalPanel imagesControlsPanel = new HorizontalPanel();
imagesControlsPanel.setSpacing(5);
panel.add(imagesControlsPanel);
Button addPhotoBtn = new Button("Add gallery photo");
addPhotoBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
openCreateImageDialog(MediaTagConstants.GALLERY);
}
});
imagesControlsPanel.add(addPhotoBtn);
Button addStateImageBtn = new Button("Add stage image");
addStateImageBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
openCreateImageDialog(MediaTagConstants.STAGE);
}
});
imagesControlsPanel.add(addStateImageBtn);
Button addEventTeaseImageBtn = new Button("Add teaser image");
addEventTeaseImageBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
openCreateImageDialog(MediaTagConstants.TEASER);
}
});
imagesControlsPanel.add(addEventTeaseImageBtn);
Button addLogoImageBtn = new Button("Add event logo");
addLogoImageBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
openCreateImageDialog(MediaTagConstants.LOGO);
}
});
imagesControlsPanel.add(addLogoImageBtn);
imageSelectionModel = new SingleSelectionModel<ImageDTO>();
imageListDataProvider = new ListDataProvider<ImageDTO>();
imageTable = createImagesTable();
imageTable.ensureDebugId("ImagesCellTable");
imageTable.setVisible(false);
imageSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
}
});
panel.add(imageTable);
noImagesLabel = new Label("No images defined yet.");
noImagesLabel.ensureDebugId("NoImagesLabel");
noImagesLabel.setWordWrap(false);
panel.add(noImagesLabel);
initWidget(mainPanel);
}
private CellTable<ImageDTO> createImagesTable() {
CellTable<ImageDTO> table = new CellTable<ImageDTO>(/* pageSize */10000, tableRes);
imageListDataProvider.addDataDisplay(table);
table.setWidth("100%");
AnchorCell anchorCell = new AnchorCell();
Column<ImageDTO, SafeHtml> shortImageNameColumn = new Column<ImageDTO, SafeHtml>(anchorCell) {
@Override
public SafeHtml getValue(ImageDTO image) {
String linkName = "";
String link = image.getSourceRef();
if(link.endsWith("/")) {
link = link.substring(0, link.length() - 1);
}
int index = link.lastIndexOf("/");
if(index > 0) {
linkName = link.substring(index+1, link.length());
}
return ANCHORTEMPLATE.cell(image.getSourceRef(), linkName);
}
};
TextColumn<ImageDTO> titleColumn = new TextColumn<ImageDTO>() {
@Override
public String getValue(ImageDTO image) {
return image.getTitle() != null ? image.getTitle() : "";
}
};
TextColumn<ImageDTO> sizeColumn = new TextColumn<ImageDTO>() {
@Override
public String getValue(ImageDTO image) {
String imageSize = "";
if (image.getWidthInPx() != null && image.getHeightInPx() != null) {
imageSize = image.getWidthInPx() + " x " + image.getHeightInPx();
}
return imageSize;
}
};
TextColumn<ImageDTO> createdAtDateColumn = new TextColumn<ImageDTO>() {
@Override
public String getValue(ImageDTO image) {
return DateAndTimeFormatterUtil.formatDateAndTime(image.getCreatedAtDate());
}
};
SafeHtmlCell tagsCell = new SafeHtmlCell();
Column<ImageDTO, SafeHtml> tagsColumn = new Column<ImageDTO, SafeHtml>(tagsCell) {
@Override
public SafeHtml getValue(ImageDTO image) {
SafeHtmlBuilder builder = new SafeHtmlBuilder();
int tagsCount = image.getTags().size();
int i = 1;
for (String tag : image.getTags()) {
builder.appendEscaped(tag);
if (i < tagsCount) {
builder.appendHtmlConstant(",&nbsp;");
// not more than 4 tags per line
if (i % 4 == 0) {
builder.appendHtmlConstant("<br>");
}
}
i++;
}
return builder.toSafeHtml();
}
};
ImagesBarColumn<ImageDTO, ImageConfigImagesBarCell> imageActionColumn = new ImagesBarColumn<ImageDTO, ImageConfigImagesBarCell>(
new ImageConfigImagesBarCell(stringMessages));
imageActionColumn.setFieldUpdater(new FieldUpdater<ImageDTO, String>() {
@Override
public void update(int index, ImageDTO image, String value) {
if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
imageListDataProvider.getList().remove(image);
updateTableVisisbilty();
} else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) {
openEditImageDialog(image);
}
}
});
titleColumn.setSortable(true);
createdAtDateColumn.setSortable(true);
table.addColumn(shortImageNameColumn, "Short name:");
table.addColumn(titleColumn, stringMessages.title());
table.addColumn(createdAtDateColumn, "Created At");
table.addColumn(sizeColumn, "Size");
table.addColumn(tagsColumn, "Tags");
table.addColumn(imageActionColumn, stringMessages.actions());
table.addColumnSortHandler(getImageTableColumnSortHandler(imageListDataProvider.getList(), titleColumn, createdAtDateColumn));
table.getColumnSortList().push(createdAtDateColumn);
return table;
}
private ListHandler<ImageDTO> getImageTableColumnSortHandler(List<ImageDTO> imageRecords,
TextColumn<ImageDTO> titleColumn, TextColumn<ImageDTO> createdAtDateColumn) {
ListHandler<ImageDTO> result = new ListHandler<ImageDTO>(imageRecords);
result.setComparator(titleColumn, new Comparator<ImageDTO>() {
@Override
public int compare(ImageDTO i1, ImageDTO i2) {
return new NaturalComparator().compare(i1.getTitle(), i2.getTitle());
}
});
result.setComparator(createdAtDateColumn, new Comparator<ImageDTO>() {
@Override
public int compare(ImageDTO e1, ImageDTO e2) {
int result;
if (e1.getCreatedAtDate() != null && e2.getCreatedAtDate() != null) {
result = e2.getCreatedAtDate().compareTo(e1.getCreatedAtDate());
} else if (e1.getCreatedAtDate() == null && e2.getCreatedAtDate() != null) {
result = 1;
} else if (e1.getCreatedAtDate() != null && e2.getCreatedAtDate() == null) {
result = -1;
} else {
result = 0;
}
return result;
}
});
return result;
}
private void openCreateImageDialog(String initialTag) {
ImageCreateDialog dialog = new ImageCreateDialog(initialTag, stringMessages, new DialogCallback<ImageDTO>() {
@Override
public void cancel() {
}
@Override
public void ok(ImageDTO newImage) {
imageListDataProvider.getList().add(newImage);
updateTableVisisbilty();
}
});
dialog.show();
}
private void openEditImageDialog(final ImageDTO selectedImage) {
ImageEditDialog dialog = new ImageEditDialog(selectedImage, stringMessages, new DialogCallback<ImageDTO>() {
@Override
public void cancel() {
}
@Override
public void ok(ImageDTO updatedImage) {
imageListDataProvider.getList().remove(selectedImage);
imageListDataProvider.getList().add(updatedImage);
updateTableVisisbilty();
}
});
dialog.show();
}
private void updateTableVisisbilty() {
if (imageListDataProvider.getList().isEmpty()) {
imageTable.setVisible(false);
noImagesLabel.setVisible(true);
} else {
imageTable.setVisible(true);
noImagesLabel.setVisible(false);
}
}
public void fillImages(List<ImageDTO> images) {
imageSelectionModel.clear();
imageListDataProvider.getList().clear();
imageListDataProvider.getList().addAll(images);
updateTableVisisbilty();
}
public List<ImageDTO> getAllImages() {
return imageListDataProvider.getList();
}
}
@@ -30,14 +30,11 @@ public class RegattaImportDialog extends DataEntryDialog<String>{
protected CheckBox isPublicCheckBox;
protected UUID id;
protected TextBox officialWebsiteURLEntryField;
protected TextBox logoImageURLEntryField;
protected StringListInlineEditorComposite courseAreaNameList;
protected StringListInlineEditorComposite imageURLList;
protected StringListInlineEditorComposite videoURLList;
protected StringListInlineEditorComposite sponsorImageURLList;
public RegattaImportDialog(StringMessages stringMessages, String message,
com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator<String> validator,
com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback<String> callback) {
@@ -53,7 +50,7 @@ public class RegattaImportDialog extends DataEntryDialog<String>{
panel.add(additionalWidget);
}
Grid formGrid = new Grid(8, 2);
Grid formGrid = new Grid(7, 2);
panel.add(formGrid);
formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":"));
@@ -70,8 +67,6 @@ public class RegattaImportDialog extends DataEntryDialog<String>{
formGrid.setWidget(5, 1, isPublicCheckBox);
formGrid.setWidget(6, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
formGrid.setWidget(6, 1, officialWebsiteURLEntryField);
formGrid.setWidget(7, 0, new Label(stringMessages.eventLogoImageURL() + ":"));
formGrid.setWidget(7, 1, logoImageURLEntryField);
panel.add(createHeadlineLabel(stringMessages.courseAreas()));
panel.add(courseAreaNameList);
@@ -89,7 +84,6 @@ public class RegattaImportDialog extends DataEntryDialog<String>{
result.setName(nameEntryField.getText());
result.setDescription(descriptionEntryField.getText());
result.setOfficialWebsiteURL(officialWebsiteURLEntryField.getText().trim().isEmpty() ? null : officialWebsiteURLEntryField.getText().trim());
result.setLogoImageURL(logoImageURLEntryField.getText().trim().isEmpty() ? null : logoImageURLEntryField.getText().trim());
result.startDate = startDateBox.getValue();
result.endDate = endDateBox.getValue();
result.isPublic = isPublicCheckBox.getValue();
@@ -101,15 +95,6 @@ public class RegattaImportDialog extends DataEntryDialog<String>{
courseAreaDTO.setName(courseAreaName);
courseAreas.add(courseAreaDTO);
}
for (String imageURL : imageURLList.getValue()) {
result.addImageURL(imageURL);
}
for (String videoURL : videoURLList.getValue()) {
result.addVideoURL(videoURL);
}
for (String sponsorImageURL : sponsorImageURLList.getValue()) {
result.addSponsorImageURL(sponsorImageURL);
}
result.venue = new VenueDTO(venueEntryField.getText(), courseAreas);
return "OK";
}
@@ -246,9 +246,9 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
courseAreaNames.add(courseAreaDTO.getName());
}
sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate,
newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImageURLs(),
newEvent.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getLogoImageURL(),
newEvent.getOfficialWebsiteURL(), new AsyncCallback<EventDTO>() {
newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(),
newEvent.getImages(), newEvent.getVideos(),
new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable t) {
errorReporter.reportError(stringMessages.errorTryingToCreateNewEvent(newEvent.getName(), t.getMessage()));
@@ -0,0 +1,34 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Arrays;
import com.google.gwt.core.client.GWT;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.ImagesBarCell;
import com.sap.sse.gwt.client.IconResources;
public class VideoConfigImagesBarCell extends ImagesBarCell {
static final String ACTION_REMOVE = "ACTION_REMOVE";
static final String ACTION_EDIT = "ACTION_EDIT";
private final StringMessages stringMessages;
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
public VideoConfigImagesBarCell(StringMessages stringMessages) {
super();
this.stringMessages = stringMessages;
}
public VideoConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringMessages) {
super();
this.stringMessages = stringMessages;
}
@Override
protected Iterable<ImageSpec> getImageSpecs() {
return Arrays.asList(
new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(IconResources.INSTANCE.removeIcon()))
);
}
}
@@ -0,0 +1,25 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collections;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.gwt.client.media.VideoDTO;
public class VideoCreateDialog extends VideoDialog {
public VideoCreateDialog(StringMessages stringMessages, DialogCallback<VideoDTO> callback) {
super(new VideoParameterValidator(stringMessages), stringMessages, callback);
createdAtLabel = new Label(creationDate.toString());
titleTextBox = createTextBox(null);
titleTextBox.setVisibleLength(50);
subtitleTextBox = createTextBox(null);
subtitleTextBox.setVisibleLength(50);
copyrightTextBox = createTextBox(null);
copyrightTextBox.setVisibleLength(50);
lengthIntegerBox = createIntegerBox(null, 10);
tagsListEditor.setValue(Collections.<String>emptyList());
setSelectedMimeType(MimeType.unknown);
}
}
@@ -0,0 +1,193 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
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.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.media.MediaConstants;
import com.sap.sse.common.Util;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.media.VideoDTO;
public abstract class VideoDialog extends DataEntryDialog<VideoDTO> {
private static final String NO_LOCALE_TEXT = "---";
protected final StringMessages stringMessages;
protected final URLFieldWithFileUpload videoURLAndUploadComposite;
protected final Date creationDate;
protected Label createdAtLabel;
protected TextBox titleTextBox;
protected TextBox subtitleTextBox;
protected TextBox copyrightTextBox;
protected final ListBox mimeTypeListBox;
protected final ListBox localeListBox;
protected IntegerBox lengthIntegerBox;
protected final URLFieldWithFileUpload thumbnailURLAndUploadComposite;
protected StringListInlineEditorComposite tagsListEditor;
protected static class VideoParameterValidator implements Validator<VideoDTO> {
private StringMessages stringMessages;
public VideoParameterValidator(StringMessages stringMessages) {
this.stringMessages = stringMessages;
}
@Override
public String getErrorMessage(VideoDTO videoToValidate) {
String errorMessage = null;
if(videoToValidate.getSourceRef() == null || videoToValidate.getSourceRef().isEmpty()) {
errorMessage = stringMessages.pleaseEnterNonEmptyUrl();
} else if (videoToValidate.getMimeType() == null) {
errorMessage = "You must select the mime type for the video.";
}
return errorMessage;
}
}
public VideoDialog(VideoParameterValidator validator, StringMessages stringMessages, DialogCallback<VideoDTO> callback) {
super(stringMessages.video(), null, stringMessages.ok(), stringMessages.cancel(), validator,
callback);
this.stringMessages = stringMessages;
this.creationDate = new Date();
getDialogBox().getWidget().setWidth("730px");
mimeTypeListBox = createListBox(false);
mimeTypeListBox.addItem(MimeType.unknown.name());
mimeTypeListBox.addItem(MimeType.aac.name());
mimeTypeListBox.addItem(MimeType.mp4.name());
mimeTypeListBox.addItem(MimeType.ogg.name());
mimeTypeListBox.addItem(MimeType.ogv.name());
mimeTypeListBox.addItem(MimeType.qt.name());
mimeTypeListBox.addItem(MimeType.youtube.name());
mimeTypeListBox.addItem(MimeType.vimeo.name());
GWT.debugger();
localeListBox = createListBox(false);
localeListBox.addItem(NO_LOCALE_TEXT, "");
localeListBox.addItem("English", "en");
localeListBox.addItem("German", "de");
localeListBox.addItem("Russian", "ru");
localeListBox.addItem("Chinese", "zh");
videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
validate();
}
});
thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
tagsListEditor = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
MediaConstants.videoTagSuggestions, "Enter tags for the video", 50));
}
@Override
protected VideoDTO getResult() {
VideoDTO result = new VideoDTO(videoURLAndUploadComposite.getURL(), getSelectedMimeType(), creationDate);
result.setTitle(titleTextBox.getValue());
result.setSubtitle(subtitleTextBox.getValue());
result.setCopyright(copyrightTextBox.getValue());
result.setLocale(getSelectedLocale());
List<String> tags = new ArrayList<String>();
for (String tag: tagsListEditor.getValue()) {
tags.add(tag);
}
result.setTags(tags);
return result;
}
protected void setSelectedMimeType(MimeType mimeType) {
for(int i = 0; i < mimeTypeListBox.getItemCount(); i++) {
if(mimeTypeListBox.getItemText(i).equals(mimeType.name())) {
mimeTypeListBox.setSelectedIndex(i);
break;
}
}
}
private MimeType getSelectedMimeType() {
MimeType result = null;
int selectedIndex = mimeTypeListBox.getSelectedIndex();
if(selectedIndex >= 0) {
result = MimeType.valueOf(mimeTypeListBox.getSelectedValue());
}
return result;
}
protected void setSelectedLocale(String locale) {
for(int i = 0; i < localeListBox.getItemCount(); i++) {
if(Util.equalsWithNull(localeListBox.getValue(i), locale)) {
localeListBox.setSelectedIndex(i);
return;
}
}
localeListBox.setSelectedIndex(0);
}
private String getSelectedLocale() {
return localeListBox.getSelectedValue();
}
@Override
protected Widget getAdditionalWidget() {
final VerticalPanel panel = new VerticalPanel();
panel.setWidth("100%");
Widget additionalWidget = super.getAdditionalWidget();
if (additionalWidget != null) {
panel.add(additionalWidget);
}
Grid formGrid = new Grid(10, 2);
panel.add(formGrid);
formGrid.setWidget(0, 0, new Label("Created at:"));
formGrid.setWidget(0, 1, createdAtLabel);
formGrid.setWidget(1, 0, new Label("Video URL:"));
formGrid.setWidget(1, 1, videoURLAndUploadComposite);
formGrid.setWidget(2, 0, new Label("Mime Type:"));
formGrid.setWidget(2, 1, mimeTypeListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.title() + ":"));
formGrid.setWidget(3, 1, titleTextBox);
formGrid.setWidget(4, 0, new Label("Subtitle:"));
formGrid.setWidget(4, 1, subtitleTextBox);
formGrid.setWidget(5, 0, new Label("Copyright:"));
formGrid.setWidget(5, 1, copyrightTextBox);
formGrid.setWidget(6, 0, new Label("Language:"));
formGrid.setWidget(6, 1, localeListBox);
formGrid.setWidget(7, 0, new Label("Tags:"));
formGrid.setWidget(7, 1, tagsListEditor);
formGrid.setWidget(8, 0, new Label("Video-Length (s):"));
formGrid.setWidget(8, 1, lengthIntegerBox);
formGrid.setWidget(9, 0, new Label("Thumbnail-URL:"));
formGrid.setWidget(9, 1, thumbnailURLAndUploadComposite);
return panel;
}
@Override
public void show() {
super.show();
videoURLAndUploadComposite.setFocus(true);
}
}
@@ -0,0 +1,28 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.media.VideoDTO;
public class VideoEditDialog extends VideoDialog {
public VideoEditDialog(VideoDTO video, StringMessages stringMessages, DialogCallback<VideoDTO> callback) {
super(new VideoParameterValidator(stringMessages), stringMessages, callback);
createdAtLabel = new Label(video.getCreatedAtDate().toString());
videoURLAndUploadComposite.setURL(video.getSourceRef());
titleTextBox = createTextBox(video.getTitle());
titleTextBox.setVisibleLength(50);
subtitleTextBox = createTextBox(video.getSubtitle());
subtitleTextBox.setVisibleLength(50);
copyrightTextBox = createTextBox(video.getCopyright());
copyrightTextBox.setVisibleLength(50);
lengthIntegerBox = createIntegerBox(video.getLengthInSeconds(), 10);
List<String> tags = new ArrayList<String>();
tags.addAll(video.getTags());
tagsListEditor.setValue(tags);
setSelectedMimeType(video.getMimeType());
setSelectedLocale(video.getLocale());
}
}
@@ -0,0 +1,286 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Comparator;
import java.util.List;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.domain.common.impl.NaturalComparator;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.media.VideoDTO;
/**
* /** A composite showing the list of media videos
*
* @author Frank Mittag (C5163974)
*/
public class VideosListComposite extends Composite {
private final StringMessages stringMessages;
private CellTable<VideoDTO> videoTable;
private SingleSelectionModel<VideoDTO> videoSelectionModel;
private ListDataProvider<VideoDTO> videoListDataProvider;
private final Label noVideosLabel;
private final SimplePanel mainPanel;
private final VerticalPanel panel;
public static class AnchorCell extends AbstractCell<SafeHtml> {
@Override
public void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml safeHtml, SafeHtmlBuilder sb) {
sb.append(safeHtml);
}
}
interface AnchorTemplates extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<a target=\"_blank\" href=\"{0}\">{1}</a>")
SafeHtml cell(String url, String displayName);
}
private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
public VideosListComposite(final StringMessages stringMessages) {
this.stringMessages = stringMessages;
mainPanel = new SimplePanel();
panel = new VerticalPanel();
mainPanel.setWidget(panel);
HorizontalPanel videosControlsPanel = new HorizontalPanel();
videosControlsPanel.setSpacing(5);
panel.add(videosControlsPanel);
Button createVideoBtn = new Button("Add video");
createVideoBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
openCreateVideoDialog();
}
});
videosControlsPanel.add(createVideoBtn);
videoSelectionModel = new SingleSelectionModel<VideoDTO>();
videoListDataProvider = new ListDataProvider<VideoDTO>();
videoTable = createVideosTable();
videoTable.ensureDebugId("VideosCellTable");
videoTable.setVisible(false);
videoSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
}
});
panel.add(videoTable);
noVideosLabel = new Label("No videos defined yet.");
noVideosLabel.ensureDebugId("NoVideosLabel");
noVideosLabel.setWordWrap(false);
panel.add(noVideosLabel);
initWidget(mainPanel);
}
private CellTable<VideoDTO> createVideosTable() {
CellTable<VideoDTO> table = new CellTable<VideoDTO>(/* pageSize */10000, tableRes);
videoListDataProvider.addDataDisplay(table);
table.setWidth("100%");
AnchorCell anchorCell = new AnchorCell();
Column<VideoDTO, SafeHtml> shortVideoNameColumn = new Column<VideoDTO, SafeHtml>(anchorCell) {
@Override
public SafeHtml getValue(VideoDTO video) {
String linkName = "";
int index = video.getSourceRef().lastIndexOf("/");
if(index > 0) {
linkName = video.getSourceRef().substring(index+1, video.getSourceRef().length());
}
return ANCHORTEMPLATE.cell(video.getSourceRef(), linkName);
}
};
TextColumn<VideoDTO> titleColumn = new TextColumn<VideoDTO>() {
@Override
public String getValue(VideoDTO image) {
return image.getTitle() != null ? image.getTitle() : "";
}
};
TextColumn<VideoDTO> createdAtDateColumn = new TextColumn<VideoDTO>() {
@Override
public String getValue(VideoDTO video) {
return DateAndTimeFormatterUtil.formatDateAndTime(video.getCreatedAtDate());
}
};
TextColumn<VideoDTO> mimeTypeColumn = new TextColumn<VideoDTO>() {
@Override
public String getValue(VideoDTO video) {
return video.getMimeType() != null ? video.getMimeType().name() : "";
}
};
TextColumn<VideoDTO> localeColumn = new TextColumn<VideoDTO>() {
@Override
public String getValue(VideoDTO video) {
return video.getLocale() != null ? video.getLocale() : "";
}
};
SafeHtmlCell tagsCell = new SafeHtmlCell();
Column<VideoDTO, SafeHtml> tagsColumn = new Column<VideoDTO, SafeHtml>(tagsCell) {
@Override
public SafeHtml getValue(VideoDTO video) {
SafeHtmlBuilder builder = new SafeHtmlBuilder();
int tagsCount = video.getTags().size();
int i = 1;
for (String tag : video.getTags()) {
builder.appendEscaped(tag);
if (i < tagsCount) {
builder.appendHtmlConstant(",&nbsp;");
// not more than 4 tags per line
if (i % 4 == 0) {
builder.appendHtmlConstant("<br>");
}
}
i++;
}
return builder.toSafeHtml();
}
};
ImagesBarColumn<VideoDTO, VideoConfigImagesBarCell> videoActionColumn = new ImagesBarColumn<VideoDTO, VideoConfigImagesBarCell>(
new VideoConfigImagesBarCell(stringMessages));
videoActionColumn.setFieldUpdater(new FieldUpdater<VideoDTO, String>() {
@Override
public void update(int index, VideoDTO video, String value) {
if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
videoListDataProvider.getList().remove(video);
updateTableVisisbilty();
} else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) {
openEditVideoDialog(video);
}
}
});
titleColumn.setSortable(true);
createdAtDateColumn.setSortable(true);
table.addColumn(shortVideoNameColumn, "Short name");
table.addColumn(titleColumn, stringMessages.title());
table.addColumn(createdAtDateColumn, "Created At");
table.addColumn(mimeTypeColumn, stringMessages.mimeType());
table.addColumn(localeColumn, "Lang");
table.addColumn(tagsColumn, "Tags");
table.addColumn(videoActionColumn, stringMessages.actions());
table.addColumnSortHandler(getVideoTableColumnSortHandler(videoListDataProvider.getList(), titleColumn, createdAtDateColumn));
table.getColumnSortList().push(createdAtDateColumn);
return table;
}
private ListHandler<VideoDTO> getVideoTableColumnSortHandler(List<VideoDTO> videoRecords,
TextColumn<VideoDTO> titleColumn, TextColumn<VideoDTO> createdAtDateColumn) {
ListHandler<VideoDTO> result = new ListHandler<VideoDTO>(videoRecords);
result.setComparator(titleColumn, new Comparator<VideoDTO>() {
@Override
public int compare(VideoDTO i1, VideoDTO i2) {
return new NaturalComparator().compare(i1.getTitle(), i2.getTitle());
}
});
result.setComparator(createdAtDateColumn, new Comparator<VideoDTO>() {
@Override
public int compare(VideoDTO e1, VideoDTO e2) {
int result;
if (e1.getCreatedAtDate() != null && e2.getCreatedAtDate() != null) {
result = e2.getCreatedAtDate().compareTo(e1.getCreatedAtDate());
} else if (e1.getCreatedAtDate() == null && e2.getCreatedAtDate() != null) {
result = 1;
} else if (e1.getCreatedAtDate() != null && e2.getCreatedAtDate() == null) {
result = -1;
} else {
result = 0;
}
return result;
}
});
return result;
}
private void openCreateVideoDialog() {
VideoCreateDialog dialog = new VideoCreateDialog(stringMessages, new DialogCallback<VideoDTO>() {
@Override
public void cancel() {
}
@Override
public void ok(VideoDTO newVideo) {
videoListDataProvider.getList().add(newVideo);
updateTableVisisbilty();
}
});
dialog.show();
}
private void openEditVideoDialog(final VideoDTO selectedVideo) {
VideoEditDialog dialog = new VideoEditDialog(selectedVideo, stringMessages, new DialogCallback<VideoDTO>() {
@Override
public void cancel() {
}
@Override
public void ok(VideoDTO updatedVideo) {
videoListDataProvider.getList().remove(selectedVideo);
videoListDataProvider.getList().add(updatedVideo);
updateTableVisisbilty();
}
});
dialog.show();
}
private void updateTableVisisbilty() {
if (videoListDataProvider.getList().isEmpty()) {
videoTable.setVisible(false);
noVideosLabel.setVisible(true);
} else {
videoTable.setVisible(true);
noVideosLabel.setVisible(false);
}
}
public void fillVideos(List<VideoDTO> videos) {
videoSelectionModel.clear();
videoListDataProvider.getList().clear();
videoListDataProvider.getList().addAll(videos);
updateTableVisisbilty();
}
public List<VideoDTO> getAllVideos() {
return videoListDataProvider.getList();
}
}
@@ -94,6 +94,8 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtService;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
/**
* The client side stub for the RPC service. Usually, when a <code>null</code> date is passed to
@@ -294,12 +296,10 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate,
VenueDTO venue, boolean isPublic, Iterable<UUID> leaderboardGroupIds, String officialWebsiteURL,
String logoImageURL, Iterable<String> imageURLs, Iterable<String> videoURLs,
Iterable<String> sponsorImageURLs) throws Exception;
Iterable<ImageDTO> images, Iterable<VideoDTO> videos) throws Exception;
EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue,
boolean isPublic, List<String> courseAreaNames, Iterable<String> imageURLs,
Iterable<String> videoURLs, Iterable<String> sponsorImageURLs, String logoImageURL, String officialWebsiteURL) throws Exception;
boolean isPublic, List<String> courseAreaNames, String officialWebsiteURL, Iterable<ImageDTO> images, Iterable<VideoDTO> videos) throws Exception;
void removeEvent(UUID eventId);
@@ -83,6 +83,8 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.gwt.client.BuildVersionRetriever;
import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
/**
* The async counterpart of {@link SailingService}
@@ -365,13 +367,12 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void removeEvents(Collection<UUID> eventIds, AsyncCallback<Void> asyncCallback);
void createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic,
List<String> courseAreaNames, Iterable<String> imageURLs, Iterable<String> videoURLs,
Iterable<String> sponsorImageURLs, String logoImageURL, String officialWebsiteURL, AsyncCallback<EventDTO> callback);
List<String> courseAreaNames, String officialWebsiteURL, Iterable<ImageDTO> images, Iterable<VideoDTO> videos,
AsyncCallback<EventDTO> callback);
void updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate,
VenueDTO venue, boolean isPublic, Iterable<UUID> leaderboardGroupIds, String officialWebsiteURL,
String logoImageURL, Iterable<String> imageURLs, Iterable<String> videoURLs,
Iterable<String> sponsorImageURLs, AsyncCallback<EventDTO> callback);
Iterable<ImageDTO> images, Iterable<VideoDTO> videos, AsyncCallback<EventDTO> callback);
void createCourseArea(UUID eventId, String courseAreaName, AsyncCallback<Void> callback);
@@ -1082,6 +1082,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String photos();
String videos();
String image();
String images();
String video();
String flagImageURL();
String imageURLs();
@@ -1056,6 +1056,7 @@ media=Media
photos=Photos
videos=Videos
image=Image
images=Images
video=Video
flagImageURL=Flag image URL (image renders with 18x12px)
imageURLs=Image URLs
@@ -1050,6 +1050,7 @@ media=Medien
photos=Fotos
videos=Videos
image=Bild
images=Bilder
video=Video
flagImageURL=Flaggenbild-URL (wird mit 18x12px Größe gezeigt)
imageURLs=Bilder-URLs
@@ -1010,6 +1010,7 @@ media=Media
photos=Photos
videos=Videos
image=Image
images=Images
video=Video
flagImageURL=Flag image URL (image renders with 18x12px)
imageURLs=Image URLs
@@ -431,10 +431,18 @@ import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.ImageDescriptorImpl;
import com.sap.sse.common.media.MediaUtils;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.media.VideoDescriptorImpl;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
import com.sap.sse.filestorage.FileStorageService;
import com.sap.sse.filestorage.InvalidPropertiesException;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
import com.sap.sse.gwt.server.filestorage.FileStorageServiceDTOUtils;
import com.sap.sse.gwt.shared.filestorage.FileStorageServiceDTO;
import com.sap.sse.gwt.shared.filestorage.FileStorageServicePropertyErrorsDTO;
@@ -3292,48 +3300,30 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate,
VenueDTO venue, boolean isPublic, Iterable<UUID> leaderboardGroupIds, String officialWebsiteURLString,
String logoImageURLString, Iterable<String> imageURLStrings, Iterable<String> videoURLStrings,
Iterable<String> sponsorImageURLStrings) throws MalformedURLException {
Iterable<ImageDTO> images, Iterable<VideoDTO> videos) throws MalformedURLException {
TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null;
TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null;
URL officialWebsiteURL = officialWebsiteURLString != null ? new URL(officialWebsiteURLString) : null;
URL logoImageURL = logoImageURLString != null ? new URL(logoImageURLString) : null;
List<URL> imageURLs = createURLsFromStrings(imageURLStrings);
List<URL> videoURLs = createURLsFromStrings(videoURLStrings);
List<URL> sponsorimagieURLs = createURLsFromStrings(sponsorImageURLStrings);
List<ImageDescriptor> eventImages = convertToImages(images);
List<VideoDescriptor> eventVideos = convertToVideos(videos);
getService().apply(
new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(),
isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, imageURLs, videoURLs,
sponsorimagieURLs));
isPublic, leaderboardGroupIds, officialWebsiteURL, eventImages, eventVideos));
return getEventById(eventId, false);
}
/**
* @param urlStrings
* @return
* @throws MalformedURLException
*/
private List<URL> createURLsFromStrings(Iterable<String> urlStrings) throws MalformedURLException {
List<URL> imageURLs = new ArrayList<>();
for (String imageURLString : urlStrings) {
imageURLs.add(new URL(imageURLString));
}
return imageURLs;
}
@Override
public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue,
boolean isPublic, List<String> courseAreaNames, Iterable<String> imageURLs,
Iterable<String> videoURLs, Iterable<String> sponsorImageURLs, String logoImageURLAsString, String officialWebsiteURLAsString)
boolean isPublic, List<String> courseAreaNames, String officialWebsiteURLAsString, Iterable<ImageDTO> images, Iterable<VideoDTO> videos)
throws MalformedURLException {
UUID eventUuid = UUID.randomUUID();
TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null;
TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null;
List<ImageDescriptor> eventImages = convertToImages(images);
List<VideoDescriptor> eventVideos = convertToVideos(videos);
getService().apply(
new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid,
createURLsFromStrings(imageURLs), createURLsFromStrings(videoURLs),
createURLsFromStrings(sponsorImageURLs),
logoImageURLAsString == null ? null : new URL(logoImageURLAsString), officialWebsiteURLAsString == null ? null : new URL(officialWebsiteURLAsString)));
officialWebsiteURLAsString == null ? null : new URL(officialWebsiteURLAsString), eventImages, eventVideos));
for (String courseAreaName : courseAreaNames) {
createCourseArea(eventUuid, courseAreaName);
}
@@ -3412,33 +3402,119 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
eventDTO.id = (UUID) event.getId();
eventDTO.setDescription(event.getDescription());
eventDTO.setOfficialWebsiteURL(event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null);
if (event.getLogoImageURL() == null) {
eventDTO.setLogoImageURL(null);
} else {
eventDTO.setLogoImageURL(event.getLogoImageURL().toString());
setImageSize(event, eventDTO, event.getLogoImageURL());
for(ImageDescriptor image: event.getImages()) {
eventDTO.addImage(convertToImageDTO(image));
}
for(URL url: event.getSponsorImageURLs()) {
eventDTO.addSponsorImageURL(url.toString());
setImageSize(event, eventDTO, url);
}
for(URL url: event.getImageURLs()) {
eventDTO.addImageURL(url.toString());
setImageSize(event, eventDTO, url);
}
for(URL url: event.getVideoURLs()) {
eventDTO.addVideoURL(url.toString());
for(VideoDescriptor video: event.getVideos()) {
eventDTO.addVideo(convertToVideoDTO(video));
}
}
private void setImageSize(EventBase event, EventBaseDTO eventDTO, URL imageURL) {
try {
eventDTO.setImageSize(imageURL.toString(), event.getImageSize(imageURL));
} catch (InterruptedException | ExecutionException e) {
logger.log(Level.FINE, "Was unable to obtain image size for "+imageURL+" earlier.", e);
private List<ImageDescriptor> convertToImages(Iterable<ImageDTO> images) throws MalformedURLException {
List<ImageDescriptor> eventImages = new ArrayList<ImageDescriptor>();
for (ImageDTO image : images) {
try {
eventImages.add(convertToImage(image));
} catch(Exception e) {
// broken URLs are not being stored
}
}
return eventImages;
}
private List<VideoDescriptor> convertToVideos(Iterable<VideoDTO> videos) throws MalformedURLException {
List<VideoDescriptor> eventVideos = new ArrayList<VideoDescriptor>();
for (VideoDTO video : videos) {
try {
eventVideos.add(convertToVideo(video));
} catch(Exception e) {
// broken URLs are not being stored
}
}
return eventVideos;
}
private ImageDescriptor convertToImage(ImageDTO image) throws MalformedURLException {
ImageDescriptor result = new ImageDescriptorImpl(new URL(image.getSourceRef()), new MillisecondsTimePoint(image.getCreatedAtDate()));
result.setCopyright(image.getCopyright());
result.setTitle(image.getTitle());
result.setSubtitle(image.getSubtitle());
result.setCopyright(image.getCopyright());
result.setSize(image.getWidthInPx(), image.getHeightInPx());
result.setLocale(toLocale(image.getLocale()));
for (String tag : image.getTags()) {
result.addTag(tag);
}
return result;
}
private VideoDescriptor convertToVideo(VideoDTO video) throws MalformedURLException {
MimeType mimeType = video.getMimeType();
if(mimeType == null || mimeType == MimeType.unknown) {
mimeType = MediaUtils.detectMimeTypeFromUrl(video.getSourceRef());
}
VideoDescriptor result = new VideoDescriptorImpl(new URL(video.getSourceRef()), mimeType, new MillisecondsTimePoint(video.getCreatedAtDate()));
result.setCopyright(video.getCopyright());
result.setTitle(video.getTitle());
result.setSubtitle(video.getSubtitle());
result.setCopyright(video.getCopyright());
result.setLengthInSeconds(video.getLengthInSeconds());
if(video.getThumbnailRef() != null && !video.getThumbnailRef().isEmpty())
result.setThumbnailURL(new URL(video.getThumbnailRef()));
result.setLocale(toLocale(video.getLocale()));
for (String tag : video.getTags()) {
result.addTag(tag);
}
return result;
}
private ImageDTO convertToImageDTO(ImageDescriptor image) {
ImageDTO result = new ImageDTO(image.getURL().toString(), image.getCreatedAtDate() != null ? image.getCreatedAtDate().asDate() : null);
result.setCopyright(image.getCopyright());
result.setTitle(image.getTitle());
result.setSubtitle(image.getSubtitle());
result.setMimeType(image.getMimeType());
result.setSizeInPx(image.getWidthInPx(), image.getHeightInPx());
result.setLocale(toLocaleName(image.getLocale()));
List<String> tags = new ArrayList<String>();
for(String tag: image.getTags()) {
tags.add(tag);
}
result.setTags(tags);
return result;
}
private VideoDTO convertToVideoDTO(VideoDescriptor video) {
VideoDTO result = new VideoDTO(video.getURL().toString(), video.getMimeType(),
video.getCreatedAtDate() != null ? video.getCreatedAtDate().asDate() : null);
result.setCopyright(video.getCopyright());
result.setTitle(video.getTitle());
result.setSubtitle(video.getSubtitle());
result.setThumbnailRef(video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null);
result.setLengthInSeconds(video.getLengthInSeconds());
result.setLocale(toLocaleName(video.getLocale()));
List<String> tags = new ArrayList<String>();
for(String tag: video.getTags()) {
tags.add(tag);
}
result.setTags(tags);
return result;
}
private Locale toLocale(String localeName) {
if(localeName == null || localeName.isEmpty()) {
return null;
}
return Locale.forLanguageTag(localeName);
}
private String toLocaleName(Locale locale) {
if(locale == null) {
return null;
}
return locale.toString();
}
private EventDTO convertToEventDTO(Event event, boolean withStatisticalData) {
EventDTO eventDTO = new EventDTO(event.getName());
copyEventBaseFieldsToDTO(event, eventDTO);
@@ -4066,9 +4142,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
eventLeaderboardGroupUUIDs.add(lg.getId());
}
updateEvent(newEvent.id, newEvent.getName(), description, newEvent.startDate, newEvent.endDate, newEvent.venue,
newEvent.isPublic, eventLeaderboardGroupUUIDs, newEvent.getLogoImageURL(),
newEvent.getOfficialWebsiteURL(), newEvent.getImageURLs(), newEvent.getVideoURLs(),
newEvent.getSponsorImageURLs());
newEvent.isPublic, eventLeaderboardGroupUUIDs, newEvent.getOfficialWebsiteURL(),
newEvent.getImages(), newEvent.getVideos());
}
@Override
@@ -10,6 +10,9 @@ import java.util.UUID;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.common.dto.NamedDTO;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
public class EventBaseDTO extends NamedDTO implements IsSerializable {
private static final long serialVersionUID = 818666323178097939L;
@@ -22,14 +25,9 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
private String description;
private List<? extends LeaderboardGroupBaseDTO> leaderboardGroups;
private List<String> imageURLs = new ArrayList<>();
private List<String> videoURLs = new ArrayList<>();
private List<String> sponsorImageURLs = new ArrayList<>();
private String logoImageURL;
private String officialWebsiteURL;
/** placeholder for social media URL's -> attributes will be implemented later on */
private String facebookURL;
private String twitterURL;
private List<ImageDTO> images = new ArrayList<>();
private List<VideoDTO> videos = new ArrayList<>();
/**
* For the image URL keys holds the sizes of these images if known. An image size is "known" by this object if it
@@ -65,6 +63,17 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
this.imageSizes = new HashMap<String, ImageSize>();
}
public ImageDTO getLogoImage() {
ImageDTO result = null;
for (ImageDTO image : images) {
if (image.hasTag(MediaTagConstants.LOGO)) {
result = image;
break;
}
}
return result;
}
public boolean isRunning() {
Date now = new Date();
if (startDate != null && endDate != null && (now.after(startDate) && now.before(endDate))) {
@@ -81,14 +90,6 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
this.description = description;
}
public String getLogoImageURL() {
return logoImageURL;
}
public void setLogoImageURL(String logoImageURL) {
this.logoImageURL = logoImageURL;
}
public String getOfficialWebsiteURL() {
return officialWebsiteURL;
}
@@ -110,30 +111,6 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
this.baseURL = baseURL;
}
public void addImageURL(String imageURL) {
imageURLs.add(imageURL);
}
public void addVideoURL(String videoURL) {
videoURLs.add(videoURL);
}
public void addSponsorImageURL(String sponsorImageURL) {
sponsorImageURLs.add(sponsorImageURL);
}
public List<String> getImageURLs() {
return imageURLs;
}
public List<String> getVideoURLs() {
return videoURLs;
}
public List<String> getSponsorImageURLs() {
return sponsorImageURLs;
}
public Iterable<? extends LeaderboardGroupBaseDTO> getLeaderboardGroups() {
return leaderboardGroups;
}
@@ -146,20 +123,20 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
this.isOnRemoteServer = isOnRemoteServer;
}
public String getFacebookURL() {
return facebookURL;
public void addImage(ImageDTO image) {
images.add(image);
}
public void setFacebookURL(String facebookURL) {
this.facebookURL = facebookURL;
public List<ImageDTO> getImages() {
return images;
}
public String getTwitterURL() {
return twitterURL;
public void addVideo(VideoDTO video) {
videos.add(video);
}
public void setTwitterURL(String twitterURL) {
this.twitterURL = twitterURL;
public List<VideoDTO> getVideos() {
return videos;
}
public void setImageSize(String imageURL, ImageSize imageSize) {
@@ -1,6 +1,7 @@
package com.sap.sailing.gwt.ui.shared.dispatch.event;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
@@ -10,12 +11,14 @@ import com.sap.sailing.gwt.ui.shared.dispatch.Action;
import com.sap.sailing.gwt.ui.shared.dispatch.DispatchContext;
import com.sap.sailing.gwt.ui.shared.dispatch.ResultWithTTL;
import com.sap.sailing.gwt.ui.shared.general.EventState;
import com.sap.sailing.gwt.ui.shared.media.MediaUtils;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.VideoDescriptor;
public class GetEventOverviewStageAction implements Action<ResultWithTTL<EventOverviewStageDTO>> {
private static final Collection<String> rankedTags = Arrays.asList(MediaTagConstants.LIVESTREAM, MediaTagConstants.FEATURED, MediaTagConstants.HIGHLIGHT);
private static final Collection<String> rankedTagsFinished = Arrays.asList(MediaTagConstants.FEATURED, MediaTagConstants.HIGHLIGHT);
private UUID eventId;
public GetEventOverviewStageAction() {
@@ -46,18 +49,14 @@ public class GetEventOverviewStageAction implements Action<ResultWithTTL<EventOv
@GwtIncompatible
public EventOverviewStageContentDTO getStageContent(DispatchContext context, Event event, EventState state, MillisecondsTimePoint now) {
// Simple solution:
// P1: Show the last video if available
// P1: Show the best matching video if available
// P2: Show Countdown for upcoming events
// P3: Show Stage image without Countdown
Iterable<URL> videoURLs = event.getVideoURLs();
for (int i = Util.size(videoURLs) - 1; i >= 0; i--) {
// TODO fmittag/pgt: implement locale specific live stream using context.getClientLocaleName() or context.getClientLocale()
String videoUrl = Util.get(videoURLs, i).toString();
MimeType type = MediaUtils.detectMimeTypeFromUrl(videoUrl);
if (type == MimeType.youtube || type == MimeType.vimeo || type == MimeType.mp4) {
return new EventOverviewVideoStageDTO(EventOverviewVideoStageDTO.Type.MEDIA, type, videoUrl);
}
Collection<String> tags = state == EventState.FINISHED ? rankedTagsFinished : rankedTags;
VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocale(), tags, true);
if(stageVideo != null) {
return new EventOverviewVideoStageDTO(EventOverviewVideoStageDTO.Type.MEDIA, stageVideo.getMimeType(), stageVideo.getURL().toString());
}
String stageImageUrl = HomeServiceUtil.getStageImageURLAsString(event);
if(state == EventState.UPCOMING || state == EventState.PLANNED) {
@@ -5,6 +5,7 @@ import java.util.List;
import com.sap.sailing.gwt.ui.shared.general.EventMetadataDTO;
import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO;
import com.sap.sse.gwt.client.media.ImageDTO;
public class EventViewDTO extends EventMetadataDTO {
@@ -19,7 +20,7 @@ public class EventViewDTO extends EventMetadataDTO {
private boolean hasMedia;
private boolean hasAnalytics;
private String seriesName;
private String logoImageURL;
private ImageDTO logoImage;
private String officialWebsiteURL;
private String sailorsInfoURL;
@@ -87,12 +88,12 @@ public class EventViewDTO extends EventMetadataDTO {
return false;
}
public void setLogoImageURL(String logoImageURL) {
this.logoImageURL = logoImageURL;
public void setLogoImage(ImageDTO logoImage) {
this.logoImage = logoImage;
}
public String getLogoImageURL() {
return logoImageURL;
public ImageDTO getLogoImage() {
return logoImage;
}
public void setOfficialWebsiteURL(String officialWebsiteURL) {
@@ -7,12 +7,13 @@ import java.util.UUID;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.gwt.ui.shared.general.EventMetadataDTO;
import com.sap.sailing.gwt.ui.shared.general.LabelType;
import com.sap.sse.gwt.client.media.ImageDTO;
public class EventSeriesViewDTO implements IsSerializable {
private UUID id;
private String displayName;
private ArrayList<EventMetadataDTO> events = new ArrayList<>();
private String logoImageURL;
private ImageDTO logoImage;
private boolean hasMedia;
private boolean hasAnalytics;
@@ -61,12 +62,12 @@ public class EventSeriesViewDTO implements IsSerializable {
this.events.add(event);
}
public String getLogoImageURL() {
return logoImageURL;
public ImageDTO getLogoImage() {
return logoImage;
}
public void setLogoImageURL(String logoImageURL) {
this.logoImageURL = logoImageURL;
public void setLogoImage(ImageDTO logoImage) {
this.logoImage = logoImage;
}
public boolean isHasMedia() {
@@ -0,0 +1,21 @@
package com.sap.sailing.gwt.ui.shared.media;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MimeType;
public final class MediaConstants {
public static final List<String> imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER,
MediaTagConstants.SPONSOR, MediaTagConstants.LOGO, MediaTagConstants.GALLERY });
public static final List<String> videoTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.LIVESTREAM, MediaTagConstants.HIGHLIGHT,MediaTagConstants.FEATURED });
public static final Set<MimeType> SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4));
private MediaConstants() {
}
}
@@ -1,52 +0,0 @@
package com.sap.sailing.gwt.ui.shared.media;
import java.util.regex.Pattern;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sse.common.media.MimeType;
/**
* Temporary solution for mimetype detection for current videos.
*
* @author pgtaboada
*
*/
public class MediaUtils {
/**
* Youtube regex detection from:
* http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url, mantish Mar 4
* at 15:33
*/
@GwtIncompatible
private static final Pattern YOUTUBE_ID_REGEX = Pattern
.compile("^.*(youtu.be/|v/|u/\\w/|embed/|watch\\?v=|\\&v=)([^#\\&\\?]+).*$");
@GwtIncompatible
private static final Pattern VIMEO_REGEX = Pattern.compile("^.*(vimeo\\.com\\/).*");
@GwtIncompatible
private static final Pattern MP4_REGEX = Pattern.compile(".*\\.mp4$");
/**
* Detect mimetype for given url.
*
* @param url
* the source pointing to the video mediafile
* @return mimetype detected or MimeType.unknown
*/
@GwtIncompatible
public static MimeType detectMimeTypeFromUrl(String url) {
if (YOUTUBE_ID_REGEX.matcher(url).matches()) {
return MimeType.youtube;
} else if (VIMEO_REGEX.matcher(url).matches()) {
return MimeType.vimeo;
} else if (MP4_REGEX.matcher(url).matches()) {
return MimeType.mp4;
} else {
return MimeType.unknown;
}
}
}
@@ -3,23 +3,19 @@ package com.sap.sailing.gwt.ui.shared.media;
import java.util.Date;
import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO;
import com.sap.sse.common.media.ImageMetadataDTO;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.gwt.client.media.ImageDTO;
public class SailingImageDTO extends ImageMetadataDTO {
public class SailingImageDTO extends ImageDTO {
private static final long serialVersionUID = 1L;
private EventReferenceDTO eventRef;
@SuppressWarnings("unused")
private SailingImageDTO() {
protected SailingImageDTO() {
super();
}
public SailingImageDTO(EventReferenceDTO eventRef, String imageURL, ImageSize size, Date createdAtDate) {
super(imageURL, size, createdAtDate);
public SailingImageDTO(EventReferenceDTO eventRef, String imageRef, Date createdAtDate) {
super(imageRef, createdAtDate);
this.eventRef = eventRef;
}
public EventReferenceDTO getEventRef() {
@@ -4,16 +4,14 @@ import java.util.Date;
import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoMetadataDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
public class SailingVideoDTO extends VideoMetadataDTO {
public class SailingVideoDTO extends VideoDTO {
private static final long serialVersionUID = 1L;
private EventReferenceDTO eventRef;
@SuppressWarnings("unused")
private SailingVideoDTO() {
/** for GWT */
protected SailingVideoDTO() {
}
public SailingVideoDTO(EventReferenceDTO eventRef, String srcReference, MimeType mimeType, Date createdAtDate) {
@@ -18,6 +18,7 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.logging.Logger;
@@ -89,6 +90,12 @@ import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.ImageDescriptorImpl;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.media.VideoDescriptorImpl;
public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest {
private static final Logger logger = Logger.getLogger(TestStoringAndLoadingEventsAndRegattas.class.getName());
@@ -137,14 +144,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
event.addLeaderboardGroup(lg1);
event.addLeaderboardGroup(lg2);
event.setDescription(eventDescription);
event.addImageURL(new URL("http://some.host/with/some/file1.jpg"));
event.addImageURL(new URL("http://some.host/with/some/file2.jpg"));
event.addVideoURL(new URL("http://some.host/with/some/file1.mp4"));
event.addVideoURL(new URL("http://some.host/with/some/file2.mp4"));
event.addSponsorImageURL(new URL("http://some.host/with/some/file4.mp4"));
event.addSponsorImageURL(new URL("http://some.host/with/some/file5.mp4"));
event.setOfficialWebsiteURL(new URL("http://official.website.com"));
event.setLogoImageURL(new URL("http://official.logo.com"));
mof.storeEvent(event);
DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
@@ -169,7 +169,6 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
assertEquals(eventName, loadedEvent.getName());
assertEquals(eventDescription, loadedEvent.getDescription());
assertEquals(event.getOfficialWebsiteURL(), loadedEvent.getOfficialWebsiteURL());
assertEquals(event.getLogoImageURL(), loadedEvent.getLogoImageURL());
assertEquals(2, Util.size(loadedEvent.getLeaderboardGroups()));
Iterator<LeaderboardGroup> lgIter = loadedEvent.getLeaderboardGroups().iterator();
assertSame(lg1, lgIter.next());
@@ -182,9 +181,6 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
for (CourseArea loadedCourseArea : loadedVenue.getCourseAreas()) {
assertEquals(courseAreaNames[i++], loadedCourseArea.getName());
}
assertTrue("image URLs "+loadedEvent.getImageURLs()+" but expected "+event.getImageURLs(), Util.equals(event.getImageURLs(), loadedEvent.getImageURLs()));
assertTrue("video URLs "+loadedEvent.getVideoURLs()+" but expected "+event.getVideoURLs(), Util.equals(event.getVideoURLs(), loadedEvent.getVideoURLs()));
assertTrue("sponsor image URLs "+loadedEvent.getSponsorImageURLs()+" but expected "+event.getSponsorImageURLs(), Util.equals(event.getSponsorImageURLs(), loadedEvent.getSponsorImageURLs()));
}
@Test
@@ -218,6 +214,155 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
assertEquals(loadedRegatta.getEndDate(), regattaEndDate);
}
@Test
public void testLoadStoreSimpleEventWithImages() throws MalformedURLException {
final URL imageURL = new URL("http://some.host/with/some/file2.jpg");
final String copyright = "copyright by Alex";
final String imageTitle = "My image title";
final String imageSubtitle = "My image subtitle";
final Integer imageWidth = 500;
final Integer imageHeight = 300;
final TimePoint createdAt = MillisecondsTimePoint.now();
final String eventName = "Event Name";
final String venueName = "Venue Name";
final String courseAreaName = "Alpha";
final Venue venue = new VenueImpl(venueName);
CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
venue.addCourseArea(courseArea);
MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt);
image1.setCopyright(copyright);
image1.setSize(imageWidth, imageHeight);
image1.setTitle(imageTitle);
image1.setSubtitle(imageSubtitle);
image1.addTag("Tag1");
image1.addTag("Tag2");
image1.addTag("Tag3");
event.addImage(image1);
ImageDescriptor image2 = new ImageDescriptorImpl(new URL("http://some.host/with/some/file2.jpg"), MillisecondsTimePoint.now());
image2.setCopyright("copyright");
event.addImage(image2);
mof.storeEvent(event);
DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
final Event loadedEvent = dof.loadEvent(eventName);
assertEquals(2, Util.size(loadedEvent.getImages()));
ImageDescriptor loadedImage1 = loadedEvent.getImages().iterator().next();
assertNotNull(loadedImage1);
assertEquals(imageURL, loadedImage1.getURL());
assertEquals(copyright, loadedImage1.getCopyright());
assertEquals(copyright, loadedImage1.getCopyright());
assertEquals(imageTitle, loadedImage1.getTitle());
assertEquals(imageSubtitle, loadedImage1.getSubtitle());
assertEquals(createdAt, loadedImage1.getCreatedAtDate());
assertEquals(imageWidth, loadedImage1.getWidthInPx());
assertEquals(imageHeight, loadedImage1.getHeightInPx());
assertEquals(3, Util.size(loadedImage1.getTags()));
}
@Test
public void testLoadStoreSimpleEventWithVideos() throws MalformedURLException {
final URL videoURL = new URL("http://some.host/with/some/video.mpg");
final URL videoThumbnailURL = new URL("http://some.host/with/some/video_thumbnail.jpg");
final Locale locale = Locale.GERMAN;
final Integer videoLengthInSeconds = 2 * 60 * 60 * 1000; // 2h
final MimeType mimeType = MimeType.mp4;
final String copyright = "copyright by Don";
final String videoTitle = "My video title";
final String videoSubtitle = "My video subtitle";
final TimePoint createdAt = MillisecondsTimePoint.now();
final String eventName = "Event Name";
final String venueName = "Venue Name";
final String courseAreaName = "Alpha";
final Venue venue = new VenueImpl(venueName);
CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
venue.addCourseArea(courseArea);
MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, mimeType, createdAt);
video1.setCopyright(copyright);
video1.setTitle(videoTitle);
video1.setLocale(locale);
video1.setSubtitle(videoSubtitle);
video1.setThumbnailURL(videoThumbnailURL);
video1.setLengthInSeconds(videoLengthInSeconds);
video1.addTag("Tag1");
video1.addTag("Tag2");
video1.addTag("Tag3");
event.addVideo(video1);
VideoDescriptor video2 = new VideoDescriptorImpl(new URL("http://some.host/with/some/file2.ogg"), MimeType.ogg, MillisecondsTimePoint.now());
video2.setCopyright("copyright");
event.addVideo(video2);
mof.storeEvent(event);
DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
final Event loadedEvent = dof.loadEvent(eventName);
assertEquals(2, Util.size(loadedEvent.getVideos()));
VideoDescriptor loadedVideo1 = loadedEvent.getVideos().iterator().next();
assertNotNull(loadedVideo1);
assertEquals(videoURL, loadedVideo1.getURL());
assertEquals(videoThumbnailURL, loadedVideo1.getThumbnailURL());
assertEquals(videoLengthInSeconds, loadedVideo1.getLengthInSeconds());
assertEquals(copyright, loadedVideo1.getCopyright());
assertEquals(locale, loadedVideo1.getLocale());
assertEquals(videoTitle, loadedVideo1.getTitle());
assertEquals(videoSubtitle, loadedVideo1.getSubtitle());
assertEquals(createdAt, loadedVideo1.getCreatedAtDate());
assertEquals(3, Util.size(loadedVideo1.getTags()));
}
@SuppressWarnings("deprecation")
@Test
/**
* We expected that the migration code creates also an image URL for each image we create.
* Images with the 'Sponsor' tag should create a corresponding sponsor image URL
* Videos should create a video URL.
*/
public void testLoadStoreSimpleEventWithImageAndVideoURLMigration() throws MalformedURLException {
final URL imageURL = new URL("http://some.host/with/some/bla.jpg");
final URL sponsorImageURL = new URL("http://some.host/with/some/sponsor.jpg");
final URL videoURL = new URL("http://some.host/with/some/video.mpg");
final TimePoint createdAt = MillisecondsTimePoint.now();
final String eventName = "Event Name";
final Venue venue = new VenueImpl("My Venue");
CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), "Alfa");
venue.addCourseArea(courseArea);
MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt);
image1.addTag(MediaTagConstants.GALLERY);
event.addImage(image1);
ImageDescriptor image2 = new ImageDescriptorImpl(sponsorImageURL, createdAt);
event.addImage(image2);
image2.addTag(MediaTagConstants.SPONSOR);
VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, MimeType.mp4, createdAt);
event.addVideo(video1);
mof.storeEvent(event);
DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
final Event loadedEvent = dof.loadEvent(eventName);
assertEquals(2, Util.size(loadedEvent.getImages()));
assertEquals(1, Util.size(loadedEvent.getVideos()));
assertEquals(1, Util.size(loadedEvent.getImageURLs()));
assertEquals(1, Util.size(loadedEvent.getSponsorImageURLs()));
assertEquals(1, Util.size(loadedEvent.getVideoURLs()));
}
@Test
public void testLoadStoreRegattaConfiguration() {
@@ -3,7 +3,10 @@ package com.sap.sailing.server.gateway.deserialization.impl;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import org.json.simple.JSONArray;
@@ -17,7 +20,15 @@ import com.sap.sailing.domain.common.impl.ImageSizeImpl;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.ImageDescriptorImpl;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.media.VideoDescriptorImpl;
public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
private final JsonDeserializer<Venue> venueDeserializer;
@@ -28,22 +39,21 @@ public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
this.leaderboardGroupDeserializer = leaderboardGroupDeserializer;
}
public EventBase deserialize(JSONObject object) throws JsonDeserializationException {
UUID id = UUID.fromString((String) object.get(EventBaseJsonSerializer.FIELD_ID));
String name = (String) object.get(EventBaseJsonSerializer.FIELD_NAME);
String description = (String) object.get(EventBaseJsonSerializer.FIELD_DESCRIPTION);
String officialWebsiteURLAsString = (String) object.get(EventBaseJsonSerializer.FIELD_OFFICIAL_WEBSITE_URL);
String logoImageURLAsString = (String) object.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL);
Number startDate = (Number) object.get(EventBaseJsonSerializer.FIELD_START_DATE);
Number endDate = (Number) object.get(EventBaseJsonSerializer.FIELD_END_DATE);
public EventBase deserialize(JSONObject eventJson) throws JsonDeserializationException {
UUID id = UUID.fromString((String) eventJson.get(EventBaseJsonSerializer.FIELD_ID));
String name = (String) eventJson.get(EventBaseJsonSerializer.FIELD_NAME);
String description = (String) eventJson.get(EventBaseJsonSerializer.FIELD_DESCRIPTION);
String officialWebsiteURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_OFFICIAL_WEBSITE_URL);
Number startDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_START_DATE);
Number endDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_END_DATE);
final Venue venue;
if (object.get(EventBaseJsonSerializer.FIELD_VENUE) != null) {
JSONObject venueObject = Helpers.getNestedObjectSafe(object, EventBaseJsonSerializer.FIELD_VENUE);
if (eventJson.get(EventBaseJsonSerializer.FIELD_VENUE) != null) {
JSONObject venueObject = Helpers.getNestedObjectSafe(eventJson, EventBaseJsonSerializer.FIELD_VENUE);
venue = venueDeserializer.deserialize(venueObject);
} else {
venue = null;
}
JSONArray leaderboardGroupsJson = (JSONArray) object.get(EventBaseJsonSerializer.FIELDS_LEADERBOARD_GROUPS);
JSONArray leaderboardGroupsJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELDS_LEADERBOARD_GROUPS);
List<LeaderboardGroupBase> leaderboardGroups = new ArrayList<LeaderboardGroupBase>();
if (leaderboardGroupsJson != null) {
for (Object lgJson : leaderboardGroupsJson) {
@@ -60,40 +70,75 @@ public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
throw new JsonDeserializationException("Error deserializing official website URL for event "+name, e);
}
}
JSONArray imagesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGES);
if (imagesJson != null) {
for (Object imageJson : imagesJson) {
ImageDescriptor imgaeDescriptor = loadImage((JSONObject) imageJson);
if (imgaeDescriptor != null) {
result.addImage(imgaeDescriptor);
}
}
}
JSONArray videosJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_VIDEOS);
if (videosJson != null) {
for (Object videoJson : videosJson) {
VideoDescriptor videoDescriptor = loadVideo((JSONObject) videoJson);
if (videoDescriptor != null) {
result.addVideo(videoDescriptor);
}
}
}
// if we read an event with data in the old image/video format we need migrate them
if(Util.size(result.getImages()) == 0 && Util.size(result.getVideos()) == 0) {
readImageAndVideoURLsFromLegacyServer(eventJson, result);
}
return result;
}
private void readImageAndVideoURLsFromLegacyServer(JSONObject eventJson, StrippedEventImpl event) throws JsonDeserializationException {
URL logoImageURL = null;
List<URL> imageURLs = new ArrayList<URL>();
List<URL> sponsorImageURLs = new ArrayList<URL>();
List<URL> videoURLs = new ArrayList<URL>();
String logoImageURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL);
if (logoImageURLAsString != null) {
try {
result.setLogoImageURL(new URL(logoImageURLAsString));
logoImageURL = new URL(logoImageURLAsString);
} catch (MalformedURLException e) {
throw new JsonDeserializationException("Error deserializing logo image URL for event "+name, e);
throw new JsonDeserializationException("Error deserializing logo image URL for event "+event.getName(), e);
}
}
if (object.get(EventBaseJsonSerializer.FIELD_IMAGE_URLS) != null) {
if (eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URLS) != null) {
try {
result.setImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(object, EventBaseJsonSerializer.FIELD_IMAGE_URLS)));
imageURLs = getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_IMAGE_URLS));
} catch (MalformedURLException e) {
throw new JsonDeserializationException("Error deserializing image URLs for event "+name, e);
throw new JsonDeserializationException("Error deserializing image URLs for event "+event.getName(), e);
}
}
if (object.get(EventBaseJsonSerializer.FIELD_VIDEO_URLS) != null) {
if (eventJson.get(EventBaseJsonSerializer.FIELD_VIDEO_URLS) != null) {
try {
result.setVideoURLs(getURLsFromStrings(Helpers.getNestedArraySafe(object, EventBaseJsonSerializer.FIELD_VIDEO_URLS)));
videoURLs = getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_VIDEO_URLS));
} catch (MalformedURLException e) {
throw new JsonDeserializationException("Error deserializing video URLs for event "+name, e);
throw new JsonDeserializationException("Error deserializing video URLs for event "+event.getName(), e);
}
}
if (object.get(EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS) != null) {
if (eventJson.get(EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS) != null) {
try {
result.setSponsorImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(object, EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS)));
sponsorImageURLs = getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS));
} catch (MalformedURLException e) {
throw new JsonDeserializationException("Error deserializing sponsor image URLs for event "+name, e);
throw new JsonDeserializationException("Error deserializing sponsor image URLs for event "+event.getName(), e);
}
}
JSONArray imageSizes = (JSONArray) object.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES);
if (imageSizes != null) {
for (Object imageURLAndSizeObject : imageSizes) {
}
// handle images sizes coming from an old server instance not having images and videos in the rich format
Map<URL, ImageSize> imageSizes = new HashMap<URL, ImageSize>();;
JSONArray imageSizesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES);
if (imageSizesJson != null) {
for (Object imageURLAndSizeObject : imageSizesJson) {
JSONObject imageURLAndSizeJson = (JSONObject) imageURLAndSizeObject;
try {
result.setImageSize(
imageSizes.put(
new URL((String) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URL)),
new ImageSizeImpl(
((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH)).intValue(),
@@ -103,10 +148,77 @@ public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
}
}
}
return result;
event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL, imageSizes);
}
private Iterable<URL> getURLsFromStrings(JSONArray strings) throws MalformedURLException {
private ImageDescriptor loadImage(JSONObject imageJson) {
ImageDescriptor image = null;
URL imageURL = Helpers.getURLField(imageJson, EventBaseJsonSerializer.FIELD_SOURCE_URL);
if (imageURL != null) {
String title = (String) imageJson.get(EventBaseJsonSerializer.FIELD_TITLE);
String subtitle = (String) imageJson.get(EventBaseJsonSerializer.FIELD_SUBTITLE);
String copyright = (String) imageJson.get(EventBaseJsonSerializer.FIELD_COPYRIGHT);
String localeRaw = (String) imageJson.get(EventBaseJsonSerializer.FIELD_LOCALE);
Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null;
Number imageWidth = (Number) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH_IN_PX);
Number imageHeight = (Number) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT_IN_PX);
Number createdAtDateInMs = (Number) imageJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE);
TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs.longValue()) : null;
JSONArray tags = (JSONArray) imageJson.get(EventBaseJsonSerializer.FIELD_TAGS);
List<String> imageTags = new ArrayList<String>();
if (tags != null) {
for (Object tagObject : tags) {
imageTags.add((String) tagObject);
}
}
image = new ImageDescriptorImpl(imageURL, createdAtDate);
image.setCopyright(copyright);
image.setLocale(locale);
image.setTitle(title);
image.setSubtitle(subtitle);
image.setTags(imageTags);
if (imageWidth != null && imageHeight != null) {
image.setSize(imageWidth.intValue(), imageHeight.intValue());
}
}
return image;
}
private VideoDescriptor loadVideo(JSONObject videoJson) {
VideoDescriptor video = null;
URL videoURL = Helpers.getURLField(videoJson, EventBaseJsonSerializer.FIELD_SOURCE_URL);
if(videoURL != null) {
String title = (String) videoJson.get(EventBaseJsonSerializer.FIELD_TITLE);
String subtitle = (String) videoJson.get(EventBaseJsonSerializer.FIELD_SUBTITLE);
String copyright = (String) videoJson.get(EventBaseJsonSerializer.FIELD_COPYRIGHT);
String localeRaw = (String) videoJson.get(EventBaseJsonSerializer.FIELD_LOCALE);
Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null;
Object mimeTypeRaw = videoJson.get(EventBaseJsonSerializer.FIELD_MIMETYPE);
MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw);
Number createdAtDateInMs = (Number) videoJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE);
TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs.longValue()) : null;
JSONArray tags = (JSONArray) videoJson.get(EventBaseJsonSerializer.FIELD_TAGS);
Integer lengthInSeconds = (Integer) videoJson.get(EventBaseJsonSerializer.FIELD_VIDEO_LENGTH_IN_SECONDS);
URL thumbnailURL = Helpers.getURLField(videoJson, EventBaseJsonSerializer.FIELD_VIDEO_THUMBNAIL_URL);
List<String> videoTags = new ArrayList<String>();
if (tags != null) {
for (Object tagObject : tags) {
videoTags.add((String) tagObject);
}
}
video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate);
video.setCopyright(copyright);
video.setLocale(locale);
video.setTitle(title);
video.setSubtitle(subtitle);
video.setTags(videoTags);
video.setLengthInSeconds(lengthInSeconds);
video.setThumbnailURL(thumbnailURL);
}
return video;
}
private List<URL> getURLsFromStrings(JSONArray strings) throws MalformedURLException {
List<URL> result = new ArrayList<URL>();
if (strings != null) {
for (Object string : strings) {
@@ -115,5 +227,4 @@ public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
}
return result;
}
}
@@ -1,6 +1,8 @@
package com.sap.sailing.server.gateway.deserialization.impl;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
import java.util.logging.Logger;
@@ -48,6 +50,19 @@ public class Helpers {
return (JSONArray) childObject;
}
public static URL getURLField(JSONObject parent, String fieldName) {
URL result = null;
String urlAsString = (String) parent.get(fieldName);
if (urlAsString != null) {
try {
result = new URL(urlAsString);
} catch (MalformedURLException e) {
logger.severe("Error deserializing URL " + urlAsString);
}
}
return result;
}
public static Serializable tryUuidConversion(Serializable serializableId) {
try {
return UUID.fromString(serializableId.toString());
@@ -1,9 +1,6 @@
package com.sap.sailing.server.gateway.serialization.impl;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
@@ -12,11 +9,10 @@ import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.LeaderboardGroupBase;
import com.sap.sailing.domain.base.Venue;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
private static final Logger logger = Logger.getLogger(EventBaseJsonSerializer.class.getName());
public static final String FIELD_ID = "id";
public static final String FIELD_NAME = "name";
public static final String FIELD_DESCRIPTION = "description";
@@ -31,9 +27,27 @@ public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
public static final String FIELD_IMAGE_URL = "imageURL";
public static final String FIELD_IMAGE_WIDTH = "imageWidth";
public static final String FIELD_IMAGE_HEIGHT = "imageHeight";
public static final String FIELD_VIDEO_URL = "videoURL";
public static final String FIELD_OFFICIAL_WEBSITE_URL = "officialWebsiteURL";
public static final String FIELDS_LEADERBOARD_GROUPS = "leaderboardGroups";
public static final String FIELD_SOURCE_URL = "sourceURL";
public static final String FIELD_TITLE = "title";
public static final String FIELD_SUBTITLE = "subtitle";
public static final String FIELD_MIMETYPE = "mimetype";
public static final String FIELD_COPYRIGHT = "copyright";
public static final String FIELD_CREATEDATDATE = "createdAtDate";
public static final String FIELD_LOCALE = "locale";
public static final String FIELD_TAGS = "tags";
// specific image fields
public static final String FIELD_IMAGES = "images";
public static final String FIELD_IMAGE_WIDTH_IN_PX = "widthInPixel";
public static final String FIELD_IMAGE_HEIGHT_IN_PX = "heightInPixel";
// specific video fields
public static final String FIELD_VIDEOS = "videos";
public static final String FIELD_VIDEO_THUMBNAIL_URL = "thumbnailURL";
public static final String FIELD_VIDEO_LENGTH_IN_SECONDS = "lengthInSeconds";
private final JsonSerializer<Venue> venueSerializer;
private final JsonSerializer<? super LeaderboardGroupBase> leaderboardGroupBaseSerializer;
@@ -42,16 +56,17 @@ public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
this.venueSerializer = venueSerializer;
}
@SuppressWarnings("deprecation")
public JSONObject serialize(EventBase event) {
JSONObject result = new JSONObject();
result.put(FIELD_ID, event.getId().toString());
result.put(FIELD_NAME, event.getName());
result.put(FIELD_DESCRIPTION, event.getDescription());
result.put(FIELD_OFFICIAL_WEBSITE_URL, event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null);
result.put(FIELD_LOGO_IMAGE_URL, event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null);
result.put(FIELD_START_DATE, event.getStartDate() != null ? event.getStartDate().asMillis() : null);
result.put(FIELD_END_DATE, event.getStartDate() != null ? event.getEndDate().asMillis() : null);
result.put(FIELD_VENUE, venueSerializer.serialize(event.getVenue()));
result.put(FIELD_LOGO_IMAGE_URL, event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null);
result.put(FIELD_IMAGE_URLS, getURLsAsStringArray(event.getImageURLs()));
result.put(FIELD_VIDEO_URLS, getURLsAsStringArray(event.getVideoURLs()));
result.put(FIELD_SPONSOR_IMAGE_URLS, getURLsAsStringArray(event.getSponsorImageURLs()));
@@ -62,37 +77,71 @@ public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
}
JSONArray imageSizes = new JSONArray();
result.put(FIELD_IMAGE_SIZES, imageSizes);
for (URL imageURL : event.getImageURLs()) {
addImageSize(imageURL, imageSizes, event);
for (ImageDescriptor image : event.getImages()) {
addImageSize(image, imageSizes);
}
if (event.getLogoImageURL() != null) {
addImageSize(event.getLogoImageURL(), imageSizes, event);
JSONArray jsonImages = new JSONArray();
for(ImageDescriptor imageDescriptor: event.getImages()) {
addImage(imageDescriptor, jsonImages);
}
for (URL sponsorImageURL : event.getSponsorImageURLs()) {
addImageSize(sponsorImageURL, imageSizes, event);
result.put(FIELD_IMAGES, jsonImages);
JSONArray jsonVideos = new JSONArray();
for(VideoDescriptor videoDescriptor: event.getVideos()) {
addVideo(videoDescriptor, jsonVideos);
}
result.put(FIELD_VIDEOS, jsonVideos);
return result;
}
private void addImage(ImageDescriptor image, JSONArray imagesJson) {
JSONObject imageJson = new JSONObject();
imageJson.put(FIELD_SOURCE_URL, image.getURL().toString());
imageJson.put(FIELD_LOCALE, image.getLocale() != null ? image.getLocale().toLanguageTag() : null);
imageJson.put(FIELD_TITLE, image.getTitle());
imageJson.put(FIELD_SUBTITLE, image.getSubtitle());
imageJson.put(FIELD_MIMETYPE, image.getMimeType().name());
imageJson.put(FIELD_COPYRIGHT, image.getCopyright());
imageJson.put(FIELD_IMAGE_WIDTH_IN_PX, image.getWidthInPx());
imageJson.put(FIELD_IMAGE_HEIGHT_IN_PX, image.getHeightInPx());
imageJson.put(FIELD_CREATEDATDATE, image.getCreatedAtDate().asMillis());
JSONArray tags = new JSONArray();
for (String tag : image.getTags()) {
tags.add(tag);
}
imageJson.put(FIELD_TAGS, tags);
imagesJson.add(imageJson);
}
private void addVideo(VideoDescriptor video, JSONArray videosJson) {
JSONObject videoJson = new JSONObject();
videoJson.put(FIELD_SOURCE_URL, video.getURL().toString());
videoJson.put(FIELD_LOCALE, video.getLocale() != null ? video.getLocale().toLanguageTag() : null);
videoJson.put(FIELD_VIDEO_THUMBNAIL_URL, video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null);
videoJson.put(FIELD_TITLE, video.getTitle());
videoJson.put(FIELD_SUBTITLE, video.getSubtitle());
videoJson.put(FIELD_MIMETYPE, video.getMimeType().name());
videoJson.put(FIELD_COPYRIGHT, video.getCopyright());
videoJson.put(FIELD_VIDEO_LENGTH_IN_SECONDS, video.getLengthInSeconds());
videoJson.put(FIELD_CREATEDATDATE, video.getCreatedAtDate().asMillis());
JSONArray tags = new JSONArray();
for (String tag : video.getTags()) {
tags.add(tag);
}
videoJson.put(FIELD_TAGS, tags);
videosJson.add(videoJson);
}
/**
* If <code>eventBase</code> knows the size of the image with URL <code>imageURL</code>, that size is serialized as
* For backward compatibility the size of an image is also serialized as
* JSON object to <code>imageSizes</code>
*/
private void addImageSize(URL imageURL, JSONArray imageSizes, EventBase eventBase) {
ImageSize imageSize;
try {
imageSize = eventBase.getImageSize(imageURL);
if (imageSize != null) {
JSONObject imageSizeJson = new JSONObject();
imageSizes.add(imageSizeJson);
imageSizeJson.put(FIELD_IMAGE_URL, imageURL.toString());
imageSizeJson.put(FIELD_IMAGE_WIDTH, imageSize.getWidth());
imageSizeJson.put(FIELD_IMAGE_HEIGHT, imageSize.getHeight());
}
} catch (InterruptedException e) {
logger.log(Level.FINE, "Couldn't retrieve image size for URL "+imageURL, e);
} catch (ExecutionException e) {
logger.log(Level.FINE, "Couldn't retrieve image size for URL "+imageURL, e);
private void addImageSize(ImageDescriptor image, JSONArray imageSizes) {
if(image.getHeightInPx() != null && image.getWidthInPx() != null) {
JSONObject imageSizeJson = new JSONObject();
imageSizes.add(imageSizeJson);
imageSizeJson.put(FIELD_IMAGE_URL, image.getURL().toString());
imageSizeJson.put(FIELD_IMAGE_WIDTH, image.getWidthInPx());
imageSizeJson.put(FIELD_IMAGE_HEIGHT, image.getHeightInPx());
}
}
@@ -32,6 +32,8 @@ import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJso
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class EventDataJsonSerializerTest {
protected final UUID expectedId = UUID.randomUUID();
@@ -55,6 +57,7 @@ public class EventDataJsonSerializerTest {
}
// see https://groups.google.com/forum/?fromgroups=#!topic/mockito/iMumB0_bpdo
@SuppressWarnings("deprecation")
@Before
public void setUp() {
// Event and its basic attributes ...
@@ -70,6 +73,8 @@ public class EventDataJsonSerializerTest {
when(event.getImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getVideoURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getSponsorImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getImages()).thenReturn(Collections.<ImageDescriptor>emptySet());
when(event.getVideos()).thenReturn(Collections.<VideoDescriptor>emptySet());
// ... and the serializer itself.
serializer = new EventBaseJsonSerializer(new VenueJsonSerializer(new CourseAreaJsonSerializer()), new LeaderboardGroupBaseJsonSerializer());
deserializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)), new LeaderboardGroupBaseJsonDeserializer());
@@ -0,0 +1,191 @@
package com.sap.sailing.server.gateway.serialization.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.Venue;
import com.sap.sailing.domain.base.impl.VenueImpl;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.CourseAreaJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.ImageDescriptorImpl;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.media.VideoDescriptorImpl;
public class EventDataJsonSerializerWithImagesAndVideosTest {
private final UUID expectedId = UUID.randomUUID();
private final String expectedName = "ab";
private final Locale locale = Locale.GERMAN;
private final TimePoint expectedStartDate = new MillisecondsTimePoint(new Date());
private final TimePoint expectedEndDate = new MillisecondsTimePoint(new Date());
private final Venue expectedVenue = new VenueImpl("Expected Venue");
private final LeaderboardGroup expectedLeaderboardGroup = mock(LeaderboardGroup.class);
private final URL imageURL;
private final String copyright = "copyright by Alex";
private final String imageTitle = "My image title";
private final String imageSubtitle = "My image subtitle";
private final Integer imageWidth = 500;
private final Integer imageHeight = 300;
private final URL videoURL;
private final URL videoThumbnailURL;
private final Locale locale2 = Locale.CANADA_FRENCH;
private final Integer videoLengthInSeconds = 2 * 60 * 60 * 1000; // 2h
private final MimeType mimeType = MimeType.mp4;
private final String copyright2 = "copyright by Don";
private final String videoTitle = "My video title";
private final String videoSubtitle = "My video subtitle";
private final TimePoint createdAt = MillisecondsTimePoint.now();
private List<ImageDescriptor> images = new ArrayList<ImageDescriptor>();
private List<VideoDescriptor> videos = new ArrayList<VideoDescriptor>();
private EventBaseJsonSerializer serializer;
private EventBaseJsonDeserializer deserializer;
private EventBase event;
public EventDataJsonSerializerWithImagesAndVideosTest() throws MalformedURLException {
imageURL = new URL("http://some.host/with/some/file2.jpg");
ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt);
image1.setCopyright(copyright);
image1.setLocale(locale);
image1.setSize(imageWidth, imageHeight);
image1.setTitle(imageTitle);
image1.setSubtitle(imageSubtitle);
image1.addTag("Tag1");
image1.addTag("Tag2");
image1.addTag("Tag3");
images.add(image1);
videoURL = new URL("http://some.host/with/some/video.mpg");
videoThumbnailURL = new URL("http://some.host/with/some/video_thumbnail.jpg");
VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, mimeType, createdAt);
video1.setCopyright(copyright2);
video1.setLocale(locale2);
video1.setTitle(videoTitle);
video1.setSubtitle(videoSubtitle);
video1.setThumbnailURL(videoThumbnailURL);
video1.setLengthInSeconds(videoLengthInSeconds);
video1.addTag("Tag1");
video1.addTag("Tag2");
video1.addTag("Tag3");
video1.addTag("Tag4");
videos.add(video1);
}
@SuppressWarnings("deprecation")
@Before
public void setUp() {
// Event and its basic attributes ...
event = mock(EventBase.class);
when(event.getId()).thenReturn(expectedId);
when(event.getName()).thenReturn(expectedName);
when(event.getStartDate()).thenReturn(expectedStartDate);
when(event.getEndDate()).thenReturn(expectedEndDate);
when(event.getVenue()).thenReturn(expectedVenue);
when(event.getImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getVideoURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getSponsorImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getImages()).thenReturn(images);
when(event.getVideos()).thenReturn(videos);
// ... and the serializer itself.
serializer = new EventBaseJsonSerializer(new VenueJsonSerializer(new CourseAreaJsonSerializer()), new LeaderboardGroupBaseJsonSerializer());
deserializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)), new LeaderboardGroupBaseJsonDeserializer());
when(expectedLeaderboardGroup.getId()).thenReturn(UUID.randomUUID());
when(expectedLeaderboardGroup.getName()).thenReturn("LG");
when(expectedLeaderboardGroup.getDescription()).thenReturn("LG Description");
when(expectedLeaderboardGroup.getDisplayName()).thenReturn("LG Display Name");
when(expectedLeaderboardGroup.hasOverallLeaderboard()).thenReturn(false);
doReturn(Collections.<LeaderboardGroup>singleton(expectedLeaderboardGroup)).when(event).getLeaderboardGroups();
}
@Test
public void testImageAndVideosAttributes() throws MalformedURLException {
JSONObject result = serializer.serialize(event);
JSONArray imagesJson = (JSONArray) result.get(EventBaseJsonSerializer.FIELD_IMAGES);
JSONObject image1Json = (JSONObject) imagesJson.get(0);
assertEquals(imageURL, new URL((String) image1Json.get(EventBaseJsonSerializer.FIELD_SOURCE_URL)));
assertEquals(createdAt, new MillisecondsTimePoint(((Number) image1Json.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE)).longValue()));
assertEquals(copyright, (String) image1Json.get(EventBaseJsonSerializer.FIELD_COPYRIGHT));
assertEquals(imageTitle, (String) image1Json.get(EventBaseJsonSerializer.FIELD_TITLE));
assertEquals(imageSubtitle, (String) image1Json.get(EventBaseJsonSerializer.FIELD_SUBTITLE));
assertEquals(imageWidth, (Integer) image1Json.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH_IN_PX));
assertEquals(imageHeight, (Integer) image1Json.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT_IN_PX));
JSONArray imageTagsJson = (JSONArray) image1Json.get(EventBaseJsonSerializer.FIELD_TAGS);
assertEquals(3, imageTagsJson.size());
JSONArray videosJson = (JSONArray) result.get(EventBaseJsonSerializer.FIELD_VIDEOS);
JSONObject video1Json = (JSONObject) videosJson.get(0);
assertEquals(videoURL, new URL((String) video1Json.get(EventBaseJsonSerializer.FIELD_SOURCE_URL)));
assertEquals(createdAt, new MillisecondsTimePoint(((Number) video1Json.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE)).longValue()));
assertEquals(copyright2, (String) video1Json.get(EventBaseJsonSerializer.FIELD_COPYRIGHT));
assertEquals(videoTitle, (String) video1Json.get(EventBaseJsonSerializer.FIELD_TITLE));
assertEquals(videoSubtitle, (String) video1Json.get(EventBaseJsonSerializer.FIELD_SUBTITLE));
assertEquals(videoThumbnailURL, new URL((String) video1Json.get(EventBaseJsonSerializer.FIELD_VIDEO_THUMBNAIL_URL)));
assertEquals(videoLengthInSeconds, (Integer) video1Json.get(EventBaseJsonSerializer.FIELD_VIDEO_LENGTH_IN_SECONDS));
JSONArray videoTagsJson = (JSONArray) video1Json.get(EventBaseJsonSerializer.FIELD_TAGS);
assertEquals(4, videoTagsJson.size());
}
@Test
public void testImageAndVideosAfterDeserialization() throws JsonDeserializationException {
final JSONObject result = serializer.serialize(event);
final EventBase deserializedEvent = deserializer.deserialize(result);
ImageDescriptor image1 = deserializedEvent.getImages().iterator().next();
assertEquals(createdAt, image1.getCreatedAtDate());
assertEquals(imageURL, image1.getURL());
assertEquals(locale, image1.getLocale());
assertEquals(copyright, image1.getCopyright());
assertEquals(imageTitle, image1.getTitle());
assertEquals(imageSubtitle, image1.getSubtitle());
assertEquals(imageWidth, image1.getWidthInPx());
assertEquals(imageHeight, image1.getHeightInPx());
assertEquals(3, Util.size(image1.getTags()));
VideoDescriptor video1 = deserializedEvent.getVideos().iterator().next();
assertEquals(createdAt, video1.getCreatedAtDate());
assertEquals(videoURL, video1.getURL());
assertEquals(mimeType, video1.getMimeType());
assertEquals(copyright2, video1.getCopyright());
assertEquals(locale2, video1.getLocale());
assertEquals(videoTitle, video1.getTitle());
assertEquals(videoSubtitle, video1.getSubtitle());
assertEquals(videoThumbnailURL, video1.getThumbnailURL());
assertEquals(videoLengthInSeconds, video1.getLengthInSeconds());
assertEquals(4, Util.size(video1.getTags()));
}
}
@@ -32,6 +32,8 @@ import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJso
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class EventDataJsonSerializerWithNullValuesTest {
protected final UUID expectedId = UUID.randomUUID();
@@ -50,6 +52,7 @@ public class EventDataJsonSerializerWithNullValuesTest {
protected EventBase event;
// see https://groups.google.com/forum/?fromgroups=#!topic/mockito/iMumB0_bpdo
@SuppressWarnings("deprecation")
@Before
public void setUp() {
// Event and its basic attributes ...
@@ -65,6 +68,8 @@ public class EventDataJsonSerializerWithNullValuesTest {
when(event.getImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getVideoURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getSponsorImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getImages()).thenReturn(Collections.<ImageDescriptor>emptySet());
when(event.getVideos()).thenReturn(Collections.<VideoDescriptor>emptySet());
// ... and the serializer itself.
serializer = new EventBaseJsonSerializer(new VenueJsonSerializer(new CourseAreaJsonSerializer()), new LeaderboardGroupBaseJsonSerializer());
deserializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)), new LeaderboardGroupBaseJsonDeserializer());
@@ -79,31 +84,23 @@ public class EventDataJsonSerializerWithNullValuesTest {
@Test
public void testBasicAttributes() throws MalformedURLException {
JSONObject result = serializer.serialize(event);
assertEquals(
expectedId,
assertEquals(expectedId,
UUID.fromString(result.get(EventBaseJsonSerializer.FIELD_ID).toString()));
assertEquals(
expectedName,
assertEquals(expectedName,
result.get(EventBaseJsonSerializer.FIELD_NAME));
assertEquals(
expectedDescription,
assertEquals(expectedDescription,
result.get(EventBaseJsonSerializer.FIELD_DESCRIPTION));
assertEquals(
expectedOfficialWebsiteURL,
assertEquals(expectedOfficialWebsiteURL,
result.get(EventBaseJsonSerializer.FIELD_OFFICIAL_WEBSITE_URL) == null ? null :
new URL((String) result.get(EventBaseJsonSerializer.FIELD_OFFICIAL_WEBSITE_URL)));
assertEquals(
expectedLogoImageURL,
assertEquals(expectedLogoImageURL,
result.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL) == null ? null :
new URL((String) result.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL)));
assertEquals(
expectedDescription,
assertEquals(expectedDescription,
result.get(EventBaseJsonSerializer.FIELD_DESCRIPTION));
assertEquals(
expectedStartDate,
assertEquals(expectedStartDate,
new MillisecondsTimePoint(((Number) result.get(EventBaseJsonSerializer.FIELD_START_DATE)).longValue()));
assertEquals(
expectedEndDate,
assertEquals(expectedEndDate,
new MillisecondsTimePoint(((Number) result.get(EventBaseJsonSerializer.FIELD_END_DATE)).longValue()));
}
@@ -31,6 +31,8 @@ import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer
import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class EventWithNullStartAndEndDataJsonSerializerTest {
@@ -55,6 +57,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest {
expectedLogoImageURL = new URL("http://official.logo.com/logo.png");
}
@SuppressWarnings("deprecation")
@Before
public void setUp() {
// Event and its basic attributes ...
@@ -74,6 +77,8 @@ public class EventWithNullStartAndEndDataJsonSerializerTest {
when(event.getImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getVideoURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getSponsorImageURLs()).thenReturn(Collections.<URL>emptySet());
when(event.getImages()).thenReturn(Collections.<ImageDescriptor>emptySet());
when(event.getVideos()).thenReturn(Collections.<VideoDescriptor>emptySet());
doReturn(expectedLeaderboardGroups).when(event).getLeaderboardGroups();
// ... and the serializer itself.
@@ -91,6 +96,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest {
assertNull(result.get(EventBaseJsonSerializer.FIELD_END_DATE));
}
@SuppressWarnings("deprecation")
@Test
public void testBasicAttributesAfterDeserialization() throws JsonDeserializationException {
final JSONObject result = serializer.serialize(event);
@@ -12,7 +12,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -127,7 +126,9 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.mongodb.MongoDBConfiguration;
import com.sap.sse.mongodb.MongoDBService;
@@ -1326,12 +1327,10 @@ public class MasterDataImportTest {
InterruptedException, ClassNotFoundException {
RacingEventService sourceService = new RacingEventServiceImpl();
Iterable<URL> imageURLs = new HashSet<>();
Iterable<URL> videoURLs = new HashSet<>();
Iterable<URL> sponsorImageURLs = new HashSet<>();
Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null,
new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), imageURLs,
videoURLs, sponsorImageURLs, /* logoImageURL */ null, /* officialWebsiteURL */ null);
new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(),
/* officialWebsiteURL */ null, /* images */Collections.<ImageDescriptor> emptyList(),
/* videos */Collections.<VideoDescriptor> emptyList());
CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID());
Regatta regatta = sourceService.createRegatta(
@@ -1393,12 +1392,10 @@ public class MasterDataImportTest {
// Setup source service
RacingEventService sourceService = new RacingEventServiceImpl();
Iterable<URL> imageURLs = new HashSet<>();
Iterable<URL> videoURLs = new HashSet<>();
Iterable<URL> sponsorImageURLs = new HashSet<>();
Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null,
new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), imageURLs,
videoURLs, sponsorImageURLs, /* logoImageURL */ null, /* officialWebsiteURL */ null);
new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(),
/* officialWebsiteURL */ null, /* images */Collections.<ImageDescriptor> emptyList(),
/* videos */Collections.<VideoDescriptor> emptyList());
CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID());
List<String> raceColumnNames = new ArrayList<String>();
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -73,6 +72,8 @@ import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
@@ -119,9 +120,7 @@ public class SearchServiceTest {
cal.set(2014, 5, 8, 16, 00);
final TimePoint pfingstbuschEndDate = new MillisecondsTimePoint(cal.getTime());
pfingstbusch = server.apply(new CreateEvent("Pfingsbusch", /* eventDescription */ null, pfingstbuschStartDate, pfingstbuschEndDate, /* isPublic */
"Kiel", true, UUID.randomUUID(), Collections.<URL>emptySet(),
Collections.<URL>emptySet(),
/* sponsorImageURLs */ Collections.<URL>emptySet(), /* logoImageURLAsString */ null, /* officialWebsiteURLAsString */ null));
"Kiel", true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList()));
kiel = pfingstbusch.getVenue();
final CourseAreaImpl kielAlpha = new CourseAreaImpl("Alpha", UUID.randomUUID());
kiel.addCourseArea(kielAlpha);
@@ -154,9 +153,8 @@ public class SearchServiceTest {
cal.set(2014, 5, 8, 18, 00);
final TimePoint aalEndDate = new MillisecondsTimePoint(cal.getTime());
aalEvent = server.apply(new CreateEvent("Aalregatta", /* eventDescription */ null, aalStartDate, aalEndDate, /* isPublic */
"Flensburg", true, UUID.randomUUID(), Collections.<URL>emptySet(),
Collections.<URL>emptySet(), /* sponsorImageURLs */ Collections.<URL>emptySet(),
/* logoimageURL */ null, /* officialWebsiteURLAsString */ null));
"Flensburg", true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null,
/* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList()));
flensburg = aalEvent.getVenue();
final CourseAreaImpl flensburgStandard = new CourseAreaImpl("Standard", UUID.randomUUID());
flensburg.addCourseArea(flensburgStandard);
@@ -74,6 +74,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
import com.sap.sse.common.search.Searchable;
@@ -369,7 +371,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
*/
void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL,
URL logoImageURL, Iterable<URL> imageURLs, Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs);
Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos);
/**
* Renames a sailing event. If a sailing event by the name <code>oldName</code> does not exist in {@link #getEvents()},
@@ -464,7 +466,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
ConcurrentHashMap<String, Regatta> getPersistentRegattasForRaceIDs();
Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue,
boolean isPublic, UUID id, Iterable<URL> imageURLs, Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL);
boolean isPublic, UUID id, URL officialWebsiteURL, Iterable<ImageDescriptor> images,
Iterable<VideoDescriptor> videos);
void setRegattaForRace(Regatta regatta, String raceIdAsString);
@@ -208,6 +208,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
import com.sap.sse.common.search.ResultImpl;
@@ -2572,13 +2574,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
public Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
String venue, boolean isPublic, UUID id) {
Event result = createEventWithoutReplication(eventName, eventDescription, startDate, endDate, venue, isPublic,
id, /* imageURLs */Collections.<URL> emptyList(),
/* videoURLs */Collections.<URL> emptyList(), /* sponsorImageURLs */Collections.<URL> emptyList(), /* logoImageURL */
null, /* officialWebsiteURL */null);
replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, /* imageURLs */
id, Collections.<URL> emptyList(),
/* videoURLs */Collections.<URL> emptyList(), /* sponsorImageURLs */Collections.<URL> emptyList(),
/* logoimageURL */null, /* officialWebsiteURLAsString */null));
id, /* officialWebsiteURL */null, /* images */Collections.<ImageDescriptor> emptyList(),
/* videos */Collections.<VideoDescriptor> emptyList());
replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id,
/* officialWebsiteURLAsString */null, /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList()));
return result;
}
@@ -2589,16 +2588,14 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override
public Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate,
TimePoint endDate, String venue, boolean isPublic, UUID id, Iterable<URL> imageURLs,
Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL) {
TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, Iterable<ImageDescriptor> images,
Iterable<VideoDescriptor> videos) {
Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id);
addEvent(result);
result.setDescription(eventDescription);
result.setImageURLs(imageURLs);
result.setVideoURLs(videoURLs);
result.setSponsorImageURLs(sponsorImageURLs);
result.setLogoImageURL(logoImageURL);
result.setOfficialWebsiteURL(officialWebsiteURL);
result.setImages(images);
result.setVideos(videos);
return result;
}
@@ -2614,7 +2611,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override
public void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL,
URL logoImageURL, Iterable<URL> imageURLs, Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs) {
Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
final Event event = eventsById.get(id);
if (event == null) {
throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist.");
@@ -2637,10 +2634,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
}
event.setLeaderboardGroups(leaderboardGroups);
event.setOfficialWebsiteURL(officialWebsiteURL);
event.setLogoImageURL(logoImageURL);
event.setImageURLs(imageURLs);
event.setVideoURLs(videoURLs);
event.setSponsorImageURLs(sponsorImageURLs);
event.setImages(images);
event.setVideos(videos);
// TODO consider use diffutils to compute diff between old and new leaderboard groups list and apply the patch
// to keep changes minimial
mongoObjectFactory.storeEvent(event);
@@ -7,6 +7,8 @@ import com.sap.sailing.domain.base.Event;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
/**
* Creates an {@link Event} in the server, with a new venue and an empty course area list.
@@ -23,14 +25,12 @@ public class CreateEvent extends AbstractEventOperation<Event> {
private final boolean isPublic;
private final String eventName;
private final String eventDescription;
private final Iterable<URL> videoURLs;
private final Iterable<URL> imageURLs;
private final Iterable<URL> sponsorImageURLs;
private final URL logoImageURL;
private final Iterable<ImageDescriptor> images;
private final Iterable<VideoDescriptor> videos;
private final URL officialWebsiteURL;
public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue,
boolean isPublic, UUID id, Iterable<URL> imageURLs, Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL) {
boolean isPublic, UUID id, URL officialWebsiteURL, Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
super(id);
this.eventName = eventName;
this.eventDescription = eventDescription;
@@ -38,11 +38,9 @@ public class CreateEvent extends AbstractEventOperation<Event> {
this.endDate = endDate;
this.venue = venue;
this.isPublic = isPublic;
this.imageURLs = imageURLs;
this.videoURLs = videoURLs;
this.sponsorImageURLs = sponsorImageURLs;
this.logoImageURL = logoImageURL;
this.officialWebsiteURL = officialWebsiteURL;
this.images = images;
this.videos = videos;
}
@Override
@@ -64,7 +62,7 @@ public class CreateEvent extends AbstractEventOperation<Event> {
@Override
public Event internalApplyTo(RacingEventService toState) {
return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic,
getId(), imageURLs, videoURLs, sponsorImageURLs, logoImageURL, officialWebsiteURL);
getId(), officialWebsiteURL, images, videos);
}
}
@@ -6,6 +6,8 @@ import java.util.UUID;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.media.ImageDescriptor;
import com.sap.sse.common.media.VideoDescriptor;
public class UpdateEvent extends AbstractEventOperation<Void> {
private static final long serialVersionUID = -8271559266421161532L;
@@ -17,14 +19,12 @@ public class UpdateEvent extends AbstractEventOperation<Void> {
private final String eventName;
private final String eventDescription;
private final URL officialWebsiteURL;
private final URL logoImageURL;
private final Iterable<URL> imageURLs;
private final Iterable<URL> videoURLs;
private final Iterable<URL> sponsorImageURLs;
private final Iterable<ImageDescriptor> images;
private final Iterable<VideoDescriptor> videos;
public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL logoImageURL,
URL officialWebsiteURL, Iterable<URL> imageURLs, Iterable<URL> videoURLs, Iterable<URL> sponsorImageURLs) {
String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL,
Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
super(id);
this.eventName = eventName;
this.eventDescription = eventDescription;
@@ -34,10 +34,8 @@ public class UpdateEvent extends AbstractEventOperation<Void> {
this.isPublic = isPublic;
this.leaderboardGroupIds = leaderboardGroupIds;
this.officialWebsiteURL = officialWebsiteURL;
this.logoImageURL = logoImageURL;
this.imageURLs = imageURLs;
this.videoURLs = videoURLs;
this.sponsorImageURLs = sponsorImageURLs;
this.images = images;
this.videos = videos;
}
@Override
@@ -55,7 +53,7 @@ public class UpdateEvent extends AbstractEventOperation<Void> {
@Override
public Void internalApplyTo(RacingEventService toState) {
toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic,
leaderboardGroupIds, officialWebsiteURL, logoImageURL, imageURLs, videoURLs, sponsorImageURLs);
leaderboardGroupIds, officialWebsiteURL, images, videos);
return null;
}
}
@@ -1,118 +0,0 @@
package com.sap.sse.common.media;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
/**
* Common media data for media items
*
* @author pgtaboada
*
*/
public class AbstractMediaDTO implements Serializable, Comparable<AbstractMediaDTO> {
private static final long serialVersionUID = 1L;
/**
* TODO: would "caption" be a better name?
*/
private String title;
/**
* TODO: should we provide a subtitle?
*/
protected String subtitle;
/**
* This information should be used for chronological ordering
* TODO: Must not be null. We need to find a way to
* migrate data!
*/
protected Date createdAtDate;
/**
* TODO: initially I though of "author", but I am not sure if we need the author name. But we probably will need
* some place to store copyright information...
*/
protected String copyright;
private MimeType mimeType;
/**
* TODO: tags will give us some way to categorize medias. If we pass this information to the frontend, we need some
* nice idea to show display this data. for now it should be something restricted to the backend domain modell
*/
private HashSet<String> tags = new HashSet<String>();
/**
* URL pointing to the media data.
*/
private String sourceRef;
/**
* Default constructor required for GWT serialization.
*/
protected AbstractMediaDTO() {
}
/**
* Media item with minimal set of information
*
* @param sourceRef
* @param mimeType
*/
public AbstractMediaDTO(String sourceRef, MimeType mimeType, Date createdAtDate) {
this.mimeType = mimeType;
this.sourceRef = sourceRef;
this.createdAtDate = createdAtDate;
}
public MimeType getMimeType() {
return mimeType;
}
public String getSourceRef() {
return sourceRef;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public HashSet<String> getTags() {
return tags;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public Date getCreatedAtDate() {
return createdAtDate;
}
public void setCreatedAtDate(Date createdAtDate) {
this.createdAtDate = createdAtDate;
}
public String getCopyright() {
return copyright;
}
public void setCopyright(String copyright) {
this.copyright = copyright;
}
@Override
public int compareTo(AbstractMediaDTO o) {
return createdAtDate.compareTo(o.createdAtDate);
}
}
@@ -0,0 +1,136 @@
package com.sap.sse.common.media;
import java.io.Serializable;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
/**
* Common media data for media items
*
* @author pgtaboada
*
*/
public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serializable {
private static final long serialVersionUID = -6671425870632517274L;
protected String title;
protected String subtitle;
protected TimePoint createdAtDate;
protected String copyright;
protected MimeType mimeType;
protected Set<String> tags = new LinkedHashSet<String>();
protected URL url;
protected Locale locale;
/**
* Media item with minimal set of information
* @param url
* @param mimeType
*/
public AbstractMediaDescriptor(URL url, MimeType mimeType, TimePoint createdAtDate) {
this.mimeType = mimeType;
this.url = url;
this.createdAtDate = createdAtDate;
}
@Override
public MimeType getMimeType() {
return mimeType;
}
@Override
public URL getURL() {
return url;
}
@Override
public String getTitle() {
return title;
}
@Override
public void setTitle(String title) {
this.title = title;
}
@Override
public Set<String> getTags() {
return tags;
}
@Override
public void setTags(Iterable<String> tags) {
this.tags.clear();
if (tags != null) {
Util.addAll(tags, this.tags);
}
}
@Override
public boolean addTag(String tagName) {
return tags.add(tagName);
}
@Override
public boolean removeTag(String tagName) {
return tags.remove(tagName);
}
@Override
public String getSubtitle() {
return subtitle;
}
@Override
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
@Override
public TimePoint getCreatedAtDate() {
return createdAtDate;
}
@Override
public void setCreatedAtDate(TimePoint createdAtDate) {
this.createdAtDate = createdAtDate;
}
@Override
public String getCopyright() {
return copyright;
}
@Override
public void setCopyright(String copyright) {
this.copyright = copyright;
}
@Override
public Locale getLocale() {
return locale;
}
@Override
public void setLocale(Locale locale) {
this.locale = locale;
}
@Override
public boolean hasTag(String tagName) {
return tags.contains(tagName);
}
}
@@ -0,0 +1,14 @@
package com.sap.sse.common.media;
import com.sap.sse.common.Util.Pair;
public interface ImageDescriptor extends MediaDescriptor {
void setSize(Pair<Integer, Integer> size);
void setSize(Integer widthInPx, Integer heightInPx);
Integer getWidthInPx();
Integer getHeightInPx();
boolean hasSize();
int getArea();
}
@@ -0,0 +1,62 @@
package com.sap.sse.common.media;
import java.net.URL;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
public class ImageDescriptorImpl extends AbstractMediaDescriptor implements ImageDescriptor {
private static final long serialVersionUID = -702731462768602331L;
private Integer widthInPx;
private Integer heightInPx;
/**
* @param imageURL
* @param size
*/
public ImageDescriptorImpl(URL imageURL, TimePoint createdAtDate) {
super(imageURL, MimeType.image, createdAtDate);
}
@Override
public Integer getWidthInPx() {
return widthInPx;
}
@Override
public Integer getHeightInPx() {
return heightInPx;
}
@Override
public void setSize(Pair<Integer, Integer> size) {
if (size != null) {
this.widthInPx = size.getA();
this.heightInPx = size.getB();
} else {
this.widthInPx = null;
this.heightInPx = null;
}
}
@Override
public void setSize(Integer widthInPx, Integer heightInPx) {
this.widthInPx = widthInPx;
this.heightInPx = heightInPx;
}
@Override
public boolean hasSize() {
return widthInPx != null && heightInPx != null;
}
@Override
public int getArea() {
if(hasSize()) {
return widthInPx * heightInPx;
}
return 0;
}
}
@@ -1,42 +0,0 @@
package com.sap.sse.common.media;
import java.util.Date;
public class ImageMetadataDTO extends AbstractMediaDTO {
private static final long serialVersionUID = 1L;
private int widthInPx;
private int heightInPx;
protected ImageMetadataDTO() {
}
/**
* TODO: should we use imagesize, or should we store height and width? For now, this is a convenience method...
*
* @param imageURL
* @param size
*/
public ImageMetadataDTO(String imageURL, ImageSize size, Date createdAtDate) {
super(imageURL, MimeType.image, createdAtDate);
this.widthInPx = size.getWidth();
this.heightInPx = size.getHeight();
}
public ImageMetadataDTO(String imageURL, int heightInPx, int widthInPx, Date createdAtDate) {
super(imageURL, MimeType.image, createdAtDate);
this.widthInPx = widthInPx;
this.heightInPx = heightInPx;
}
public int getWidthInPx() {
return widthInPx;
}
public int getHeightInPx() {
return heightInPx;
}
}
@@ -0,0 +1,36 @@
package com.sap.sse.common.media;
import java.io.Serializable;
import java.net.URL;
import java.util.Locale;
import com.sap.sse.common.TimePoint;
/**
* A common media interface for all kinds of media like images or videos.
*/
public interface MediaDescriptor extends Serializable {
MimeType getMimeType();
URL getURL();
String getTitle();
void setTitle(String title);
Iterable<String> getTags();
void setTags(Iterable<String> tags);
boolean addTag(String tagName);
boolean removeTag(String tagName);
boolean hasTag(String tagName);
String getSubtitle();
void setSubtitle(String subtitle);
TimePoint getCreatedAtDate();
void setCreatedAtDate(TimePoint createdAtDate);
String getCopyright();
void setCopyright(String copyright);
Locale getLocale();
void setLocale(Locale locale);
}
@@ -0,0 +1,12 @@
package com.sap.sse.common.media;
public interface MediaTagConstants {
static final String GALLERY = "Gallery";
static final String STAGE = "Stage";
static final String LOGO = "Logo";
static final String TEASER = "Teaser";
static final String SPONSOR = "Sponsor";
static final String HIGHLIGHT = "Highlight";
static final String LIVESTREAM = "Livestream";
static final String FEATURED = "Featured";
}
@@ -0,0 +1,99 @@
package com.sap.sse.common.media;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import com.sap.sse.common.Util.Pair;
public class MediaUtils {
private static final Logger logger = Logger.getLogger(MediaUtils.class.getName());
/**
* Youtube regex detection from:
* http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url, mantish Mar 4
* at 15:33
*/
private static final Pattern YOUTUBE_ID_REGEX = Pattern
.compile("^.*(youtu.be/|v/|u/\\w/|embed/|watch\\?v=|\\&v=)([^#\\&\\?]+).*$");
private static final Pattern VIMEO_REGEX = Pattern.compile("^.*(vimeo\\.com\\/).*");
private static final Pattern MP4_REGEX = Pattern.compile(".*\\.mp4$");
/**
* Detect mimetype for given url.
*
* @param url
* the source pointing to the video mediafile
* @return mimetype detected or MimeType.unknown
*/
public static MimeType detectMimeTypeFromUrl(String url) {
if (YOUTUBE_ID_REGEX.matcher(url).matches()) {
return MimeType.youtube;
} else if (VIMEO_REGEX.matcher(url).matches()) {
return MimeType.vimeo;
} else if (MP4_REGEX.matcher(url).matches()) {
return MimeType.mp4;
} else {
return MimeType.unknown;
}
}
public static Pair<Integer, Integer> getImageDimensions(URL imageURL) {
Future<Pair<Integer, Integer>> imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL);
try {
return imageSizeCalculator.get();
} catch (Exception e) {
return null;
}
}
private static final ExecutorService executor = Executors.newCachedThreadPool();
private static Future<Pair<Integer, Integer>> getOrCreateImageSizeCalculator(final URL imageURL) {
Future<Pair<Integer, Integer>> imageSizeFetcher = executor.submit(new Callable<Pair<Integer, Integer>>() {
@Override
public Pair<Integer, Integer> call() throws IOException {
Pair<Integer, Integer> result = null;
ImageInputStream in = null;
try {
URLConnection conn = imageURL.openConnection();
in = ImageIO.createImageInputStream(conn.getInputStream());
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
result = new Pair<>(reader.getWidth(0), reader.getHeight(0));
} finally {
reader.dispose();
}
}
} catch (IOException ioe) {
logger.log(Level.SEVERE, "Stale image URL: "+imageURL, ioe);
throw ioe;
} finally {
if (in != null) {
in.close();
}
}
return result;
}
});
return imageSizeFetcher;
}
}
@@ -0,0 +1,11 @@
package com.sap.sse.common.media;
import java.net.URL;
public interface VideoDescriptor extends MediaDescriptor {
Integer getLengthInSeconds();
void setLengthInSeconds(Integer lengthInSeconds);
URL getThumbnailURL();
void setThumbnailURL(URL thumbnailURL);
}
@@ -0,0 +1,40 @@
package com.sap.sse.common.media;
import java.net.URL;
import com.sap.sse.common.TimePoint;
public class VideoDescriptorImpl extends AbstractMediaDescriptor implements VideoDescriptor {
private static final long serialVersionUID = 2651747912466590862L;
private Integer lengthInSeconds;
/**
* URL to thumbnail image. This information works as override for youtube videos or as missing thumbnail
* information for other formats. It can be either a link to thumbnail or even be a data/url contaning the base64
* encoded image.
*/
private URL thumbnailURL;
public VideoDescriptorImpl(URL url, MimeType mimeType, TimePoint createdAtDate) {
super(url, mimeType, createdAtDate);
}
@Override
public Integer getLengthInSeconds() {
return lengthInSeconds;
}
public void setLengthInSeconds(Integer lengthInSeconds) {
this.lengthInSeconds = lengthInSeconds;
}
@Override
public URL getThumbnailURL() {
return thumbnailURL;
}
public void setThumbnailURL(URL thumbnailURL) {
this.thumbnailURL = thumbnailURL;
}
}
@@ -1,45 +0,0 @@
package com.sap.sse.common.media;
import java.util.Date;
public class VideoMetadataDTO extends AbstractMediaDTO {
private static final long serialVersionUID = 1L;
/**
* TODO: Do we really need video length? Should it be mandatory?
*/
private int lengthInSeconds;
/**
* URL Reference to thumbnail image. This information works as override for youtube videos or as missing thumbnail
* information for other formats. It can be either a link to thumbnail or even be a data/url contaning the base64
* encoded image.
*/
private String thumbnailRef;
protected VideoMetadataDTO() {
}
public VideoMetadataDTO(String url, MimeType mimeType, Date createdAtDate) {
super(url, mimeType, createdAtDate);
}
public int getLengthInSeconds() {
return lengthInSeconds;
}
public void setLengthInSeconds(int lengthInSeconds) {
this.lengthInSeconds = lengthInSeconds;
}
public void setThumbnailRef(String thumbnailRef) {
this.thumbnailRef = thumbnailRef;
}
public String getThumbnailRef() {
return thumbnailRef;
}
}
@@ -0,0 +1,25 @@
package com.sap.sse.common.media;
public interface WithImages {
/**
* Returns a non-<code>null</code> live but unmodifiable collection of image resources that can be
* used to represent the event, e.g., on a web page.
*
* @return a non-<code>null</code> value which may be empty
*/
Iterable<ImageDescriptor> getImages();
/**
* Replaces the {@link #getImages() current contents of the image sequence by the images in
* <code>images</code>.
*
* @param images
* if <code>null</code>, the internal sequence of images is cleared but remains valid (non-
* <code>null</code>)
*/
void setImages(Iterable<ImageDescriptor> images);
void addImage(ImageDescriptor image);
void removeImage(ImageDescriptor image);
}
@@ -0,0 +1,11 @@
package com.sap.sse.common.media;
import java.util.List;
public interface WithMedia extends WithImages, WithVideos {
ImageDescriptor findImageWithTag(String tagName);
List<ImageDescriptor> findImagesWithTag(String tagName);
VideoDescriptor findVideoWithTag(String tagName);
List<VideoDescriptor> findVideosWithTag(String tagName);
}
@@ -0,0 +1,26 @@
package com.sap.sse.common.media;
public interface WithVideos {
/**
* Returns a non-<code>null</code> live but unmodifiable collection of video resources that can be
* used to represent the event, e.g., on a web page.
*
* @return a non-<code>null</code> value which may be empty
*/
Iterable<VideoDescriptor> getVideos();
/**
* Replaces the {@link #getVideos() current contents of the video sequence by the videos in
* <code>videos</code>.
*
* @param videos
* if <code>null</code>, the internal sequence of videos is cleared but remains valid (non-
* <code>null</code>)
*/
void setVideos(Iterable<VideoDescriptor> videos);
void addVideo(VideoDescriptor video);
void removeVideo(VideoDescriptor video);
}
@@ -5,6 +5,9 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
@@ -15,6 +18,7 @@ import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
@@ -29,7 +33,7 @@ import com.google.gwt.user.client.ui.VerticalPanel;
* @author Axel Uhl (d043530)
*
*/
public class URLFieldWithFileUpload extends Composite {
public class URLFieldWithFileUpload extends Composite implements HasValue<String> {
private final TextBox urlTextBox;
private final FileUpload fileUploadField;
@@ -37,6 +41,8 @@ public class URLFieldWithFileUpload extends Composite {
private String uri;
private final Button removeButton;
private boolean valueChangeHandlerInitialized = false;
public URLFieldWithFileUpload(final StringMessages stringMessages) {
final VerticalPanel mainPanel = new VerticalPanel();
@@ -139,4 +145,43 @@ public class URLFieldWithFileUpload extends Composite {
removeButton.setEnabled(true);
}
}
public void setFocus(boolean focused) {
urlTextBox.setFocus(focused);
}
private HandlerRegistration addChangeHandler(ChangeHandler handler) {
return addDomHandler(handler, ChangeEvent.getType());
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
if (!valueChangeHandlerInitialized) {
valueChangeHandlerInitialized = true;
addChangeHandler(new ChangeHandler() {
public void onChange(ChangeEvent event) {
ValueChangeEvent.fire(URLFieldWithFileUpload.this, getValue());
}
});
}
return addHandler(handler, ValueChangeEvent.getType());
}
@Override
public String getValue() {
return getURL();
}
@Override
public void setValue(String value) {
setURL(value);
}
@Override
public void setValue(String value, boolean fireEvents) {
setValue(value);
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
}
@@ -29,6 +29,7 @@ Export-Package: com.google.gwt.user.client.rpc.core.java.util,
com.sap.sse.gwt.client.dialog,
com.sap.sse.gwt.client.event,
com.sap.sse.gwt.client.filestorage,
com.sap.sse.gwt.client.media,
com.sap.sse.gwt.client.mvp,
com.sap.sse.gwt.client.panels,
com.sap.sse.gwt.client.player,
@@ -15,7 +15,7 @@ import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.common.media.ImageMetadataDTO;
import com.sap.sse.gwt.client.media.ImageDTO;
/**
* Image carousel that uses the open source "slick carousel".
@@ -53,7 +53,7 @@ import com.sap.sse.common.media.ImageMetadataDTO;
*
* Created by pgtaboada on 10.11.14.
*/
public class ImageCarousel<TYPE extends ImageMetadataDTO> extends Widget {
public class ImageCarousel<TYPE extends ImageDTO> extends Widget {
private static SlickSliderUiBinder ourUiBinder = GWT.create(SlickSliderUiBinder.class);
@@ -316,4 +316,4 @@ public class ImageCarousel<TYPE extends ImageMetadataDTO> extends Widget {
public void show(TYPE selectedImage, List<TYPE> imageList);
}
}
}
@@ -0,0 +1,106 @@
package com.sap.sse.gwt.client.media;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sse.common.media.MimeType;
public abstract class AbstractMediaDTO implements IsSerializable {
protected String title;
protected String subtitle;
protected Date createdAtDate;
protected String copyright;
protected MimeType mimeType;
protected List<String> tags = new ArrayList<String>();
protected String sourceRef;
protected String locale;
/** for GWT */
protected AbstractMediaDTO() {
}
public AbstractMediaDTO(String sourceRef, MimeType mimeType, Date createdAtDate) {
this.sourceRef = sourceRef;
this.mimeType = mimeType;
this.createdAtDate = createdAtDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public Date getCreatedAtDate() {
return createdAtDate;
}
public void setCreatedAtDate(Date createdAtDate) {
this.createdAtDate = createdAtDate;
}
public String getCopyright() {
return copyright;
}
public void setCopyright(String copyright) {
this.copyright = copyright;
}
public MimeType getMimeType() {
return mimeType;
}
public void setMimeType(MimeType mimeType) {
this.mimeType = mimeType;
}
public List<String> getTags() {
return tags;
}
public boolean hasTag(String tagName) {
return tags.contains(tagName);
}
public void setTags(Iterable<String> tags) {
for(String tag: tags) {
this.tags.add(tag);
}
}
public String getSourceRef() {
return sourceRef;
}
public void setSourceRef(String sourceRef) {
this.sourceRef = sourceRef;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
}
@@ -0,0 +1,33 @@
package com.sap.sse.gwt.client.media;
import java.util.Date;
import com.sap.sse.common.media.MimeType;
public class ImageDTO extends AbstractMediaDTO {
/** for GWT */
protected ImageDTO() {
}
/** can be null if not known */
private Integer widthInPx;
private Integer heightInPx;
public ImageDTO(String imageRef, Date createdAtDate) {
super(imageRef, MimeType.image, createdAtDate);
}
public Integer getWidthInPx() {
return widthInPx;
}
public Integer getHeightInPx() {
return heightInPx;
}
public void setSizeInPx(Integer widthInPx, Integer heightInPx) {
this.widthInPx = widthInPx;
this.heightInPx = heightInPx;
}
}
@@ -0,0 +1,34 @@
package com.sap.sse.gwt.client.media;
import java.util.Date;
import com.sap.sse.common.media.MimeType;
public class VideoDTO extends AbstractMediaDTO {
private Integer lengthInSeconds;
private String thumbnailRef;
/** for GWT */
protected VideoDTO() {
}
public VideoDTO(String videoRef, MimeType mimeType, Date createdAtDate) {
super(videoRef, mimeType, createdAtDate);
}
public Integer getLengthInSeconds() {
return lengthInSeconds;
}
public void setLengthInSeconds(Integer lengthInSeconds) {
this.lengthInSeconds = lengthInSeconds;
}
public String getThumbnailRef() {
return thumbnailRef;
}
public void setThumbnailRef(String thumbnailRef) {
this.thumbnailRef = thumbnailRef;
}
}