From 08463853faa01bf33dc5b5a701328167f45878b1 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 15:01:53 +0200 Subject: [PATCH 001/117] First implementation of news Box with dummy content --- .../images/home/news-i.png | Bin 0 -> 2178 bytes .../event/overview/EventOverviewStage.java | 28 +++++ .../event/overview/EventOverviewStage.ui.xml | 5 +- .../event/partials/updatesBox/UpdatesBox.gss | 109 ++++++++++++++++++ .../event/partials/updatesBox/UpdatesBox.java | 39 +++++++ .../partials/updatesBox/UpdatesBox.ui.xml | 12 ++ .../partials/updatesBox/UpdatesBoxItem.java | 95 +++++++++++++++ .../partials/updatesBox/UpdatesBoxItem.ui.xml | 25 ++++ .../updatesBox/UpdatesBoxResources.java | 26 +++++ .../sailing/gwt/ui/client/StringMessages.java | 1 + .../gwt/ui/client/StringMessages.properties | 3 +- .../ui/client/StringMessages_cn.properties | 1 + .../ui/client/StringMessages_de.properties | 3 +- .../ui/client/StringMessages_ru.properties | 1 + .../dispatch/event/EventOverviewStageDTO.java | 14 ++- .../event/GetEventOverviewStageAction.java | 11 +- .../news/AbstractLeaderboardNewsEntryDTO.java | 47 ++++++++ .../news/AbstractRaceNewsEntryDTO.java | 42 +++++++ .../dispatch/news/InfoNewsEntryDTO.java | 34 ++++++ .../ui/shared/dispatch/news/NewsEntryDTO.java | 27 +++++ 20 files changed, 518 insertions(+), 5 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/images/home/news-i.png create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractLeaderboardNewsEntryDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java diff --git a/java/com.sap.sailing.gwt.ui/images/home/news-i.png b/java/com.sap.sailing.gwt.ui/images/home/news-i.png new file mode 100644 index 0000000000000000000000000000000000000000..eec304aa5167cf6ae0151ea30bebb5d5c5ef4765 GIT binary patch literal 2178 zcmaJ@dsGu=7Ec9{fCz{}LBw=GC~A^P$Xkd)LLj_E9`aVgWPk*c3CSqop%fHE>Z-+R zc~eEZ6hvK-M@pp#T8}GAEp9|?CAvsOP(b7uE#gj8-2UO|oHO%%-~I0I-rs$lGy6hA z{4C5I%y2lIh0vcLhOH#SYifdhqcm%o*kX_RMx)_KGMXt;!Z>d+k^~ckGEoW~28+a5 z8CPLX9L{K$BqAD(4i4f#h>RpM=#bPh1%}4qJU6HnA}9?;2}y8@MD7Jlbo>MmBw{Zh ziXIFGD|m3K#6MdJhi8XGK-p;!TMTUA5TK_M_`Bnk~=)7a|>RFDFaDO57ZBvL>Qoyh?yg!d1C zc~gp$IbnRkdtcbe3rIy#1&2(|%*-TZdXNxh3Yo%Yv&kTpOr;Vr4WcSbj*8SoxypIo z0v}dEN{IrMAaa7iq9_U3j(PzY({~}r6v4qC49ivT6NROWtQINA6cR|5$qaG5)mEWl z@c(IiR9h91rGUv{unO6(gs^%fJI{l$-2J^HgCfR;vq>qziXuwqBhYpkEJuZWF95qC zi6vqV=)nRh6ebO1Qb7ibLSeCZ3;_+~`3ij4ERaQ=xA8Ho4}k2RNzwBHlBhXTfTaC&28~GpOA80aJJ9ljw>8MJ-+niFX8aOqa*4N9< z8JVb}r)hgpeoRa`UZT-OKJ)zCcvHTceh$&uDHc{OsMh5u$U*;fb}UTEZ`(+$H*q%N zZomzCo2M?!GhTkkdU6`-GErFP;uaxd79qV6mHX#_U#=*v zTf}a_tj%PB!|2IeR)VWaYX2wW*0WJXcN#0k^R5oyxVfd6tNjmfiVMIr-!lzdmfZx=gDXG?G$d8-s4dlm6>m4hqMAlpcrs3IZKd@rP~v?)x1H z2tL?RBA~_4FS(3&*SGDp+I3`b>v!5U*4)6I-#YJkw33&5qI%E2mYCV)_!f2kRuN5N zkSv}aZ#j|zUVJhBhYPJ@P5)qkufD(GK@sF4X#=j_SY~>AaIU;+Q$xw0pLHiPzk#P- zmKbD8YA+-OW}_mVR*0HnYP7oSyJkh~G@ z$!sWLTibHuE<9aaE&lAetow|HTe+`P6c&fCw!kMJ*im}KEo0Vcx;QJB7gELz3O(Ph zJ!%|YpyAE{b9KfwXCmF(9V?$_7uu$Ed~JWsarNPf{o2R)Hv;1Kh1!t3_LKMMV`C#l zxvaR5;CttWq!Z6>SL*M7*A_!M*wv}>tlR2zZ6e!YrgUihp~G3c?n_gCY4YmW^Rnsn zR;AM=*^yh*kMzrCw3-{7x&t*&T*ko6|J2A9ny<=#R5*UO*-Lk*T71Vf?~btZ=s+j= z`h!1qUy!a^7pr{*?`^#*99^I&hc%UVYF*o`^B48%M#o|4Xdu6RfKGbzyL5Pi$5iu= zc=r;gUt1mFgJFj=mb8@d3v(>DROnlZYR)dL8IGr{#TPUWXk$Fo?UI3%lMd}0yDd~R z0cn=*nRF$N>~_vVnqivV)!)Ua=*^qR+i|w9l1H~1{^4xV(+8Oe>czQNcq=A;07p*J zTz9Q}RwbO?evDCGue{Yk+1If;=I0F~N&TzDefF1LX@+e*p!HIdGoA$lxY{N-?jPR# zj{W*KaB<}GYoonAZZ~}wCydy-4cbrE?R#V6Q)UxC-G(#5?TWNHugE&uX!t7-`iAgN I`y>|p4_72~3jhEB literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java index b01755611e0..b9b682a563d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java @@ -1,20 +1,28 @@ package com.sap.sailing.gwt.home.client.place.event.overview; +import java.util.List; + import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +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.SimplePanel; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.common.client.SharedResources; +import com.sap.sailing.gwt.common.client.SharedResources.MediaCss; import com.sap.sailing.gwt.home.client.place.event.EventView; import com.sap.sailing.gwt.home.client.place.event.partials.countdown.Countdown; import com.sap.sailing.gwt.home.client.place.event.partials.message.Message; +import com.sap.sailing.gwt.home.client.place.event.partials.updatesBox.UpdatesBox; import com.sap.sailing.gwt.home.client.place.event.partials.video.Video; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshableWidget; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageContentDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewTickerStageDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewVideoStageDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; public class EventOverviewStage extends Composite implements RefreshableWidget { @@ -23,8 +31,12 @@ public class EventOverviewStage extends Composite implements RefreshableWidget { } + private final MediaCss mediaCss = SharedResources.INSTANCE.mediaCss(); + @UiField SimplePanel stage; @UiField Message message; + @UiField DivElement updatesWrapperUi; + @UiField(provided = true) UpdatesBox updatesUi; private Widget lastContent; @@ -32,7 +44,11 @@ public class EventOverviewStage extends Composite implements RefreshableWidget news = stageData.getNews(); + if(news.isEmpty()) { + updatesWrapperUi.getStyle().setDisplay(Display.NONE); + stage.removeStyleName(mediaCss.medium7()); + stage.removeStyleName(mediaCss.large8()); + } else { + updatesWrapperUi.getStyle().clearDisplay(); + updatesUi.setData(news); + stage.addStyleName(mediaCss.medium7()); + stage.addStyleName(mediaCss.large8()); + } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml index 20710c7bc91..f4a558cdf59 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml @@ -1,5 +1,5 @@ - + @@ -8,6 +8,9 @@
+
+ +
\ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss new file mode 100644 index 00000000000..95d8107b3d8 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss @@ -0,0 +1,109 @@ +.box { + font-size: 1rem; + border: 1px solid #dedede; + border-radius: 0.333333333333333em; + overflow: hidden; +} +.box_header { + color: #333; + font-size: 1.2em; + font-weight: 700; + background: #f2f2f2; + padding: 1.111111111111111em; + border-bottom: 1px solid #dedede; +} +.box_content { + list-style: none; + margin: 0; + padding: 0; + max-height: 23.933333333333334em; + overflow-y: auto; +} +@media (max-width: 976px) { + .box_content { + height: 18em; + } +} +@media (max-width: 719px) { + .box_content { + height: 12em; + } +} +.box_content_item { + border-bottom: 1px solid #dedede; +} +.box_content_item:last-child { + border-bottom: none; +} +.updatesbox { + font-size: 1rem; +} +.updatesbox_item { + display: block; + height: 6em; + padding: 1.333333333333333em 2em 1.333333333333333em 1em; + position: relative; + color: #0a0a0a; +} +.updatesbox_itemlink { + background-image: url("../images/home/arrow-grey-right.png"); + background-repeat: no-repeat; + background-size: 9px 16px; + background-position: 95% 50%; +} +.updatesbox_itemlink:hover { + text-decoration: none; +} +.updatesbox_item_icon { + max-width: 4em; + height: auto; + position: absolute; + top: 50%; + left: 2.666666666666667em; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} +@media (max-width: 1190px) { + .updatesbox_item_icon { + display: none; + } +} +@media (max-width: 720px) { + .updatesbox_item_icon { + display: inherit; + } +} +.updatesbox_item_content { + margin-left: 4em; + padding-left: 0.8em; + border-left: 1px solid #dedede; + line-height: 1.2; +} +@media (max-width: 1190px) { + .updatesbox_item_content { + margin: 0; + border: none; + } +} +@media (max-width: 720px) { + .updatesbox_item_content { + margin-left: 4em; + border-left: 1px solid #dedede; + } +} +.updatesbox_item_content_text { + font-size: 1em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.updatesbox_item_content_text_boatclass { + display: none; +} +@media (max-width: 1190px) { + .updatesbox_item_content_text_boatclass { + display: inline; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.java new file mode 100644 index 00000000000..06f611225ad --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.java @@ -0,0 +1,39 @@ +package com.sap.sailing.gwt.home.client.place.event.partials.updatesBox; + +import java.util.Collection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.UListElement; +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.FlowPanel; +import com.google.gwt.user.client.ui.Widget; +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.ui.shared.dispatch.news.NewsEntryDTO; + +public class UpdatesBox extends Composite { + private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); + + interface MyUiBinder extends UiBinder { + } + + @UiField(provided = true) FlowPanel entries = new FlowPanel(UListElement.TAG); + private Presenter presenter; + + public UpdatesBox(EventView.Presenter presenter) { + this.presenter = presenter; + + UpdatesBoxResources.INSTANCE.css().ensureInjected(); + + initWidget(uiBinder.createAndBindUi(this)); + } + + public void setData(Collection newsEntries) { + entries.clear(); + for (NewsEntryDTO newsEntryDTO : newsEntries) { + entries.add(new UpdatesBoxItem(newsEntryDTO, presenter)); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.ui.xml new file mode 100644 index 00000000000..a26b60b8604 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.ui.xml @@ -0,0 +1,12 @@ + + + + + + +
+ +
+ +
+
\ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java new file mode 100644 index 00000000000..0f5313fb849 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -0,0 +1,95 @@ +package com.sap.sailing.gwt.home.client.place.event.partials.updatesBox; + +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.AnchorElement; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.EventListener; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.common.client.BoatClassImageResolver; +import com.sap.sailing.gwt.common.client.LinkUtil; +import com.sap.sailing.gwt.home.client.app.PlaceNavigation; +import com.sap.sailing.gwt.home.client.place.event.EventView; +import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractLeaderboardNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractRaceNewsEntryDTO; + +public class UpdatesBoxItem extends Widget { + private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); + + interface MyUiBinder extends UiBinder { + } + + @UiField AnchorElement link; + @UiField ImageElement icon; + @UiField SpanElement titleUi; + @UiField SpanElement boatClassUi; + @UiField DivElement messageUi; + @UiField DivElement timestampUi; + + public UpdatesBoxItem(NewsEntryDTO entry, EventView.Presenter presenter) { + setElement(uiBinder.createAndBindUi(this)); + + titleUi.setInnerText(entry.getTitle()); + messageUi.setInnerText(entry.getSubtitle()); + + String boatClass = entry.getBoatClass(); + if(boatClass != null && !boatClass.isEmpty()) { + icon.setSrc(BoatClassImageResolver.getBoatClassIconResource(boatClass).getSafeUri().asString()); + boatClassUi.setInnerText(boatClass); + } else { + boatClassUi.removeFromParent(); + } + if(boatClass != null && !boatClass.isEmpty()) { + + } + + Date timestamp = entry.getTimestamp(); + if(timestamp == null) { + timestampUi.removeFromParent(); + } else { + timestampUi.setInnerText(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_MEDIUM).format(timestamp)); + } + + String directLink = null; + PlaceNavigation placeNavigation = null; + if(entry instanceof AbstractLeaderboardNewsEntryDTO) { + directLink = ((AbstractLeaderboardNewsEntryDTO) entry).getExternalURL(); + placeNavigation = presenter.getRegattaNavigation(((AbstractLeaderboardNewsEntryDTO) entry).getLeaderboardName()); + } else if(entry instanceof AbstractRaceNewsEntryDTO) { + AbstractRaceNewsEntryDTO raceEntry = (AbstractRaceNewsEntryDTO) entry; + if(raceEntry.getTrackedRaceName() != null) { + directLink = presenter.getRaceViewerURL(raceEntry.getRegattaName(), raceEntry.getTrackedRaceName()); + } + } + if(directLink != null) { + link.setHref(directLink); + link.setTarget("_blank"); + } else if(placeNavigation != null) { + link.setHref(placeNavigation.getTargetUrl()); + Event.sinkEvents(link, Event.ONCLICK); + final PlaceNavigation pn = placeNavigation; + Event.setEventListener(link, new EventListener() { + @Override + public void onBrowserEvent(Event event) { + if(LinkUtil.handleLinkClick(event)) { + event.preventDefault(); + pn.goToPlace(); + } + } + }); + } else { + link.removeClassName(UpdatesBoxResources.INSTANCE.css().updatesbox_itemlink()); + } + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml new file mode 100644 index 00000000000..342b476bc99 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml @@ -0,0 +1,25 @@ + + + + +
  • + + + +
    + + + + +
    +
    +
    +
    +
    +
    + + +
  • +
    \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java new file mode 100644 index 00000000000..f0cf86a841c --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java @@ -0,0 +1,26 @@ +package com.sap.sailing.gwt.home.client.place.event.partials.updatesBox; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +public interface UpdatesBoxResources extends ClientBundle { + public static final UpdatesBoxResources INSTANCE = GWT.create(UpdatesBoxResources.class); + + @Source("UpdatesBox.gss") + LocalCss css(); + + public interface LocalCss extends CssResource { + String box(); + String box_header(); + String box_content(); + String box_content_item(); + String updatesbox(); + String updatesbox_item(); + String updatesbox_itemlink(); + String updatesbox_item_icon(); + String updatesbox_item_content(); + String updatesbox_item_content_text(); + String updatesbox_item_content_text_boatclass(); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 51ce0f7afe5..d18fee452ed 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1289,4 +1289,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String raceIsCanceled(); String raceIsPostponed(); String startingInMinutes(@PluralCount(DefaultRule_0_1_n.class) int minutes); + String latestNews(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 130b811d338..fe946edfabf 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1256,4 +1256,5 @@ raceIsPlanned=Planned raceIsCanceled=Canceled raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min -startingInMinutes[none]=Starting now \ No newline at end of file +startingInMinutes[none]=Starting now +latestNews=Latest News diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties index 9a81f4d9809..28cd7512313 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties @@ -1249,3 +1249,4 @@ raceIsCanceled=Canceled raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now +latestNews=最新消息 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 0b7478e0325..dfd1dec3140 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1246,4 +1246,5 @@ raceIsPlanned=Geplant raceIsCanceled=Abgebrochen raceIsPostponed=Verschoben startingInMinutes=Startet in {0,number} min -startingInMinutes[none]=Startet gleich \ No newline at end of file +startingInMinutes[none]=Startet gleich +latestNews=Neuigkeiten diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index fa57aca8c1e..2a749e44d86 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1195,3 +1195,4 @@ raceIsCanceled=Canceled raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now +latestNews=Последние Новости diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java index 0e7af6506f5..b3247407e19 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java @@ -1,13 +1,17 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; +import java.util.ArrayList; +import java.util.List; + import com.sap.sailing.gwt.ui.shared.dispatch.DTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; public class EventOverviewStageDTO implements DTO { private String eventMessage; private EventOverviewStageContentDTO stageContent; - // TODO news + private List news = new ArrayList<>(); @SuppressWarnings("unused") private EventOverviewStageDTO() { @@ -26,4 +30,12 @@ public class EventOverviewStageDTO implements DTO { public EventOverviewStageContentDTO getStageContent() { return stageContent; } + + public List getNews() { + return news; + } + + public void addNews(NewsEntryDTO newsEntry) { + news.add(newsEntry); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index d1009001f1d..24eaba7c588 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.net.URL; +import java.util.Date; import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; @@ -9,6 +10,7 @@ import com.sap.sailing.gwt.server.HomeServiceUtil; 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.dispatch.news.InfoNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; import com.sap.sse.common.Util; @@ -40,7 +42,9 @@ public class GetEventOverviewStageAction implements Action(ttl, new EventOverviewStageDTO(null, getStageContent(context, event, state, now))); + EventOverviewStageDTO stage = new EventOverviewStageDTO("foo", getStageContent(context, event, state, now)); + addNews(stage); + return new ResultWithTTL<>(ttl, stage); } @GwtIncompatible @@ -120,4 +124,9 @@ public class GetEventOverviewStageAction implements Action Date: Wed, 27 May 2015 16:11:35 +0200 Subject: [PATCH 002/117] Added more contents for the news box --- .../partials/updatesBox/UpdatesBoxItem.java | 10 ++--- .../event/GetEventOverviewStageAction.java | 13 +++++++ .../news/AbstractRaceNewsEntryDTO.java | 16 +++++--- .../dispatch/news/InfoNewsEntryDTO.java | 2 +- ...yDTO.java => LeaderboardNewsEntryDTO.java} | 22 +++++++++-- .../ui/shared/dispatch/news/NewsEntryDTO.java | 2 +- .../news/RaceCompetitorNewsEntryDTO.java | 37 +++++++++++++++++++ 7 files changed, 87 insertions(+), 15 deletions(-) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/{AbstractLeaderboardNewsEntryDTO.java => LeaderboardNewsEntryDTO.java} (62%) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index 0f5313fb849..a8917c83166 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -19,7 +19,7 @@ import com.sap.sailing.gwt.common.client.BoatClassImageResolver; import com.sap.sailing.gwt.common.client.LinkUtil; import com.sap.sailing.gwt.home.client.app.PlaceNavigation; import com.sap.sailing.gwt.home.client.place.event.EventView; -import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractLeaderboardNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractRaceNewsEntryDTO; @@ -40,7 +40,7 @@ public class UpdatesBoxItem extends Widget { setElement(uiBinder.createAndBindUi(this)); titleUi.setInnerText(entry.getTitle()); - messageUi.setInnerText(entry.getSubtitle()); + messageUi.setInnerText(entry.getMessage()); String boatClass = entry.getBoatClass(); if(boatClass != null && !boatClass.isEmpty()) { @@ -62,9 +62,9 @@ public class UpdatesBoxItem extends Widget { String directLink = null; PlaceNavigation placeNavigation = null; - if(entry instanceof AbstractLeaderboardNewsEntryDTO) { - directLink = ((AbstractLeaderboardNewsEntryDTO) entry).getExternalURL(); - placeNavigation = presenter.getRegattaNavigation(((AbstractLeaderboardNewsEntryDTO) entry).getLeaderboardName()); + if(entry instanceof LeaderboardNewsEntryDTO) { + directLink = ((LeaderboardNewsEntryDTO) entry).getExternalURL(); + placeNavigation = presenter.getRegattaNavigation(((LeaderboardNewsEntryDTO) entry).getLeaderboardName()); } else if(entry instanceof AbstractRaceNewsEntryDTO) { AbstractRaceNewsEntryDTO raceEntry = (AbstractRaceNewsEntryDTO) entry; if(raceEntry.getTrackedRaceName() != null) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 24eaba7c588..32ca544effc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -6,11 +6,15 @@ import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.CompetitorDTOImpl; import com.sap.sailing.gwt.server.HomeServiceUtil; 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.dispatch.news.InfoNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.RaceCompetitorNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; import com.sap.sse.common.Util; @@ -128,5 +132,14 @@ public class GetEventOverviewStageAction implements Action Date: Wed, 27 May 2015 16:15:16 +0200 Subject: [PATCH 003/117] Fixed news box arrow icon --- .../images/home/arrow-grey-right.png | Bin 0 -> 308 bytes .../event/partials/updatesBox/UpdatesBox.gss | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 java/com.sap.sailing.gwt.ui/images/home/arrow-grey-right.png diff --git a/java/com.sap.sailing.gwt.ui/images/home/arrow-grey-right.png b/java/com.sap.sailing.gwt.ui/images/home/arrow-grey-right.png new file mode 100644 index 0000000000000000000000000000000000000000..cb174da3416d277c0962be9a796a00c4b36de7c3 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^oIotV!3-onPg`0Dq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N$@?z$e5NNY5k@0JY@F zZ0ZD30wqCy!3@VwiJre8aqXh`rK^{(h@ENZ5!MFEF(!GtyD)UH%6b4foCO|{#S9GG zLLkg|>2BR0prE~{i(?4Kb>DNId<+U4%ns#up8j8d^$1tdtd@YRHJ_jPJ>XD##3T0T x*NwWerwr+jS$SVP$b0G(q!PJ5lR0xM<9Si08G_$8T?ZP);OXk;vd$@?2>``CYhVBX literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss index 95d8107b3d8..548e77328cb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss @@ -46,7 +46,7 @@ color: #0a0a0a; } .updatesbox_itemlink { - background-image: url("../images/home/arrow-grey-right.png"); + background-image: url("images/home/arrow-grey-right.png"); background-repeat: no-repeat; background-size: 9px 16px; background-position: 95% 50%; From d23b604e79476e25dd4832c4ca6dc3ad32a6672f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 16:19:54 +0200 Subject: [PATCH 004/117] Fixed news items that aren't linked to anything --- .../place/event/partials/updatesBox/UpdatesBoxItem.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index a8917c83166..bda28df7981 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -7,6 +7,7 @@ import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.SpanElement; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; @@ -88,7 +89,13 @@ public class UpdatesBoxItem extends Widget { } }); } else { - link.removeClassName(UpdatesBoxResources.INSTANCE.css().updatesbox_itemlink()); + link.removeFromParent(); + while(link.hasChildNodes()) { + Node firstChild = link.getChild(0); + firstChild.removeFromParent(); + getElement().appendChild(firstChild); + } + addStyleName(UpdatesBoxResources.INSTANCE.css().updatesbox_item()); } } From b9c6dd466b09c0d3bd60d517aa1d3540e0c0f30b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 17:30:17 +0200 Subject: [PATCH 005/117] Fixed usage of renamed pirate boat class --- .../ui/shared/dispatch/event/GetEventOverviewStageAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 32ca544effc..64f2575413a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -139,7 +139,7 @@ public class GetEventOverviewStageAction implements Action Date: Wed, 27 May 2015 17:33:29 +0200 Subject: [PATCH 006/117] Removed test message --- .../ui/shared/dispatch/event/GetEventOverviewStageAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 64f2575413a..3faadd8b23a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -46,7 +46,7 @@ public class GetEventOverviewStageAction implements Action(ttl, stage); } From 2b2bdbd63285007ec768bc777748132aba948e78 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 28 May 2015 09:06:28 +0200 Subject: [PATCH 007/117] Sorting by timestamp implemented for the news box --- .../shared/dispatch/event/EventOverviewStageDTO.java | 10 ++++++++++ .../dispatch/event/GetEventOverviewStageAction.java | 3 ++- .../gwt/ui/shared/dispatch/news/NewsEntryDTO.java | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java index b3247407e19..765b30f755f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.util.ArrayList; +import java.util.Date; import java.util.List; import com.sap.sailing.gwt.ui.shared.dispatch.DTO; @@ -36,6 +37,15 @@ public class EventOverviewStageDTO implements DTO { } public void addNews(NewsEntryDTO newsEntry) { + for(int i = 0; i < news.size(); i++) { + NewsEntryDTO foundEntry = news.get(i); + Date foundTimestamp = foundEntry.getTimestamp(); + Date timestamp = newsEntry.getTimestamp(); + if(timestamp == null || (foundTimestamp != null && timestamp.compareTo(foundTimestamp)>0)) { + news.add(i, newsEntry); + return; + } + } news.add(newsEntry); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 3faadd8b23a..6bf0cfbbcb4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -131,6 +131,7 @@ public class GetEventOverviewStageAction implements Action Date: Thu, 28 May 2015 15:10:57 +0200 Subject: [PATCH 008/117] Improved creation of test news --- .../event/GetEventOverviewStageAction.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 6bf0cfbbcb4..c7ddcbfad29 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -7,6 +7,7 @@ import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.dto.CompetitorDTOImpl; import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.gwt.ui.shared.dispatch.Action; @@ -47,7 +48,7 @@ public class GetEventOverviewStageAction implements Action(ttl, stage); } @@ -130,7 +131,10 @@ public class GetEventOverviewStageAction implements Action Date: Fri, 29 May 2015 08:34:58 +0200 Subject: [PATCH 009/117] Adapted current version of the UpdatesBox styling to fix some bugs / Added TODO for spacings to be added --- .../place/event/overview/EventOverviewStage.ui.xml | 1 + .../place/event/partials/updatesBox/UpdatesBox.gss | 9 +++++++-- .../place/event/partials/updatesBox/UpdatesBoxItem.java | 7 +++---- .../event/partials/updatesBox/UpdatesBoxItem.ui.xml | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml index f4a558cdf59..6d8b2c3fffd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml @@ -9,6 +9,7 @@
    +
    diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss index 548e77328cb..bd215238bec 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss @@ -55,8 +55,8 @@ text-decoration: none; } .updatesbox_item_icon { - max-width: 4em; - height: auto; + width: 3.333333333333333em; + height: 3.333333333333333em; position: absolute; top: 50%; left: 2.666666666666667em; @@ -64,6 +64,11 @@ -moz-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%); + background-size: contain; + background-position: center; + background-repeat: no-repeat; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); } @media (max-width: 1190px) { .updatesbox_item_icon { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index bda28df7981..d9f293e8129 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -6,7 +6,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.ImageElement; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.SpanElement; import com.google.gwt.i18n.client.DateTimeFormat; @@ -20,9 +19,9 @@ import com.sap.sailing.gwt.common.client.BoatClassImageResolver; import com.sap.sailing.gwt.common.client.LinkUtil; import com.sap.sailing.gwt.home.client.app.PlaceNavigation; import com.sap.sailing.gwt.home.client.place.event.EventView; +import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractRaceNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractRaceNewsEntryDTO; public class UpdatesBoxItem extends Widget { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @@ -31,7 +30,7 @@ public class UpdatesBoxItem extends Widget { } @UiField AnchorElement link; - @UiField ImageElement icon; + @UiField DivElement icon; @UiField SpanElement titleUi; @UiField SpanElement boatClassUi; @UiField DivElement messageUi; @@ -45,7 +44,7 @@ public class UpdatesBoxItem extends Widget { String boatClass = entry.getBoatClass(); if(boatClass != null && !boatClass.isEmpty()) { - icon.setSrc(BoatClassImageResolver.getBoatClassIconResource(boatClass).getSafeUri().asString()); + icon.getStyle().setBackgroundImage("url(\"" + BoatClassImageResolver.getBoatClassIconResource(boatClass).getSafeUri().asString() + "\")"); boatClassUi.setInnerText(boatClass); } else { boatClassUi.removeFromParent(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml index 342b476bc99..cdf86405d56 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml @@ -5,7 +5,7 @@
  • - +
    From 617a9d168e4f434f189a295b779c437297a84132 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 2 Jun 2015 11:57:36 +0300 Subject: [PATCH 010/117] some refactoring of getFlagStateOrNull method --- .../ui/shared/dispatch/event/RaceContext.java | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index 25ae2f4c1fe..9d106522ef0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -126,7 +126,7 @@ public class RaceContext { private FlagStateDTO getFlagStateOrNull() { // Code extracted from SailingServiceImpl.createRaceInfoDTO - // TODO extract to to util to be used from both places + // TODO: extract to to util to be used from both places TimePoint startTime = state.getStartTime(); Flags lastUpperFlag = null; @@ -150,30 +150,34 @@ public class RaceContext { } } - RaceLogRaceStatus lastStatus = state.getStatus(); - - AbortingFlagFinder abortingFlagFinder = new AbortingFlagFinder(raceLog); - - RaceLogFlagEvent abortingFlagEvent = abortingFlagFinder.analyze(); - if (abortingFlagEvent != null) { - if (lastStatus == RaceLogRaceStatus.UNSCHEDULED) { - lastUpperFlag = abortingFlagEvent.getUpperFlag(); - lastLowerFlag = abortingFlagEvent.getLowerFlag(); - lastFlagsAreDisplayed = abortingFlagEvent.isDisplayed(); - lastFlagsDisplayedStateChanged = true; - } - } - - - if (lastStatus == RaceLogRaceStatus.FINISHED) { - TimePoint protestStartTime = state.getProtestTime(); - if (protestStartTime != null) { - lastUpperFlag = Flags.BRAVO; - lastLowerFlag = Flags.NONE; - lastFlagsAreDisplayed = true; - lastFlagsDisplayedStateChanged = true; - } - } + switch(state.getStatus()) { + case FINISHED: + TimePoint protestStartTime = state.getProtestTime(); + if (protestStartTime != null) { + lastUpperFlag = Flags.BRAVO; + lastLowerFlag = Flags.NONE; + lastFlagsAreDisplayed = true; + lastFlagsDisplayedStateChanged = true; + } + break; + case UNSCHEDULED: + // search for race aborting in last pass + AbortingFlagFinder abortingFlagFinder = new AbortingFlagFinder(raceLog); + RaceLogFlagEvent abortingFlagEvent = abortingFlagFinder.analyze(); + if (abortingFlagEvent != null) { + lastUpperFlag = abortingFlagEvent.getUpperFlag(); + lastLowerFlag = abortingFlagEvent.getLowerFlag(); + lastFlagsAreDisplayed = abortingFlagEvent.isDisplayed(); + lastFlagsDisplayedStateChanged = true; + } + break; + case FINISHING: + case RUNNING: + case SCHEDULED: + case STARTPHASE: + case UNKNOWN: + break; + }; if(lastUpperFlag != null || lastLowerFlag != null) { return new FlagStateDTO(lastUpperFlag, lastLowerFlag, lastFlagsAreDisplayed, lastFlagsDisplayedStateChanged); @@ -279,7 +283,7 @@ public class RaceContext { if(isLiveOrOfPublicInterest(startTime, finishTime)) { // the start time is always given for live races LiveRaceDTO liveRaceDTO = new LiveRaceDTO(getRegattaName(), raceColumn.getName()); - liveRaceDTO.setViewState(getRaceViewState(startTime, finishTime)); + liveRaceDTO.setViewState(getLiveRaceViewState(startTime, finishTime)); liveRaceDTO.setRegattaDisplayName(getRegattaDisplayName()); liveRaceDTO.setTrackedRaceName(trackedRace != null ? trackedRace.getRaceIdentifier().getRaceName() : null); liveRaceDTO.setTrackingState(getRaceTrackingState()); @@ -337,7 +341,7 @@ public class RaceContext { return trackingState; } - private RaceViewState getRaceViewState(TimePoint startTime, TimePoint finishTime) { + private RaceViewState getLiveRaceViewState(TimePoint startTime, TimePoint finishTime) { RaceViewState raceState = RaceViewState.RUNNING; if (startTime != null && now.before(startTime)) { raceState = RaceViewState.SCHEDULED; From 69ab268bab469275bfe2083991769c8351671d4a Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 2 Jun 2015 12:09:42 +0300 Subject: [PATCH 011/117] added aborted and postponed state for live race state calculation --- .../gwt/ui/shared/dispatch/event/RaceContext.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index 9d106522ef0..11f26dcd2ae 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -347,8 +347,17 @@ public class RaceContext { raceState = RaceViewState.SCHEDULED; } else if (finishTime != null && now.after(finishTime)) { raceState = RaceViewState.FINISHED; - } else { - // TODO: Resolve ABORTED and POSTPONED states + } else if(raceLog != null) { + AbortingFlagFinder abortingFlagFinder = new AbortingFlagFinder(raceLog); + RaceLogFlagEvent abortingFlagEvent = abortingFlagFinder.analyze(); + if (abortingFlagEvent != null) { + Flags upperFlag = abortingFlagEvent.getUpperFlag(); + if(upperFlag.equals(Flags.AP)) { + raceState = RaceViewState.POSTPONED; + } else if(upperFlag.equals(Flags.NOVEMBER)) { + raceState = RaceViewState.CANCELED; + } + } } return raceState; } From 8ff9797d2921e10ff705d11e61b744142b760f55 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 2 Jun 2015 17:27:28 +0300 Subject: [PATCH 012/117] added some common interfaces for media data --- .../sap/sse/common/media/ImageMetadata.java | 7 ++++++ .../sap/sse/common/media/MediaMetadata.java | 23 +++++++++++++++++++ .../sap/sse/common/media/VideoMetadata.java | 7 ++++++ 3 files changed, 37 insertions(+) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java new file mode 100644 index 00000000000..3a0b4ce16f2 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java @@ -0,0 +1,7 @@ +package com.sap.sse.common.media; + +public interface ImageMetadata extends MediaMetadata { + public int getWidthInPx(); + + public int getHeightInPx(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java new file mode 100644 index 00000000000..e7d169d763e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java @@ -0,0 +1,23 @@ +package com.sap.sse.common.media; + +import java.net.URL; +import java.util.Date; + +/** + * A common media interface for all kinds of media like images or videos. + */ +public interface MediaMetadata { + public MimeType getMimeType(); + + public URL getURL(); + + public String getTitle(); + + public Iterable getTags(); + + public String getSubtitle(); + + public Date getCreatedAtDate(); + + public String getCopyright(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java new file mode 100644 index 00000000000..de53a3d9bac --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java @@ -0,0 +1,7 @@ +package com.sap.sse.common.media; + +public interface VideoMetadata extends MediaMetadata { + public int getLengthInSeconds(); + + public String getThumbnailRef(); +} From 3e87d32e52c6fc317a14bcd16fdcce27b038fb24 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 3 Jun 2015 14:30:17 +0300 Subject: [PATCH 013/117] separated media classes from media DTO's --- .../gwt/ui/shared/media/SailingImageDTO.java | 14 +-- .../gwt/ui/shared/media/SailingVideoDTO.java | 10 +- .../sse/common/media/AbstractMediaDTO.java | 118 ------------------ .../common/media/AbstractMediaMetadata.java | 92 ++++++++++++++ ...etadataDTO.java => ImageMetadataImpl.java} | 15 +-- .../sse/common/media/VideoMetadataDTO.java | 45 ------- .../sse/common/media/VideoMetadataImpl.java | 37 ++++++ java/com.sap.sse.gwt/META-INF/MANIFEST.MF | 1 + .../controls/carousel/ImageCarousel.java | 4 +- .../gwt/client/media/AbstractMediaDTO.java | 91 ++++++++++++++ .../sap/sse/gwt/client/media/ImageDTO.java | 36 ++++++ .../sap/sse/gwt/client/media/VideoDTO.java | 34 +++++ 12 files changed, 308 insertions(+), 189 deletions(-) delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java rename java/com.sap.sse.common/src/com/sap/sse/common/media/{ImageMetadataDTO.java => ImageMetadataImpl.java} (56%) delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java index 02da494bb86..088ff272cfe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java @@ -3,21 +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, ImageSize size, Date createdAtDate) { + super(imageRef, size, createdAtDate); this.eventRef = eventRef; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java index bbfc2ebe186..d4270438627 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java @@ -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) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java deleted file mode 100644 index 6e0ff8ba07b..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java +++ /dev/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 { - 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 tags = new HashSet(); - - /** - * 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 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); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java new file mode 100644 index 00000000000..bde8a7600f2 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java @@ -0,0 +1,92 @@ +package com.sap.sse.common.media; + +import java.io.Serializable; +import java.net.URL; +import java.util.Date; +import java.util.HashSet; + +/** + * Common media data for media items + * + * @author pgtaboada + * + */ +public abstract class AbstractMediaMetadata implements MediaMetadata, Serializable { + private static final long serialVersionUID = -6671425870632517274L; + + protected String title; + + protected String subtitle; + + protected Date createdAtDate; + + protected String copyright; + + protected MimeType mimeType; + + protected HashSet tags = new HashSet(); + + protected URL url; + + /** + * Media item with minimal set of information + * @param url + * @param mimeType + */ + public AbstractMediaMetadata(URL url, MimeType mimeType, Date 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; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public HashSet getTags() { + return tags; + } + + @Override + public String getSubtitle() { + return subtitle; + } + + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + @Override + public Date getCreatedAtDate() { + return createdAtDate; + } + + public void setCreatedAtDate(Date createdAtDate) { + this.createdAtDate = createdAtDate; + } + + @Override + public String getCopyright() { + return copyright; + } + + public void setCopyright(String copyright) { + this.copyright = copyright; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java similarity index 56% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java index ee72871c032..2f2961a3cdc 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java @@ -1,31 +1,26 @@ package com.sap.sse.common.media; +import java.net.URL; import java.util.Date; -public class ImageMetadataDTO extends AbstractMediaDTO { - - private static final long serialVersionUID = 1L; +public class ImageMetadataImpl extends AbstractMediaMetadata { + private static final long serialVersionUID = -702731462768602331L; 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) { + public ImageMetadataImpl(URL 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) { + public ImageMetadataImpl(URL imageURL, int heightInPx, int widthInPx, Date createdAtDate) { super(imageURL, MimeType.image, createdAtDate); this.widthInPx = widthInPx; this.heightInPx = heightInPx; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java deleted file mode 100644 index 72207aefd00..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java +++ /dev/null @@ -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; - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java new file mode 100644 index 00000000000..3f5c699612f --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java @@ -0,0 +1,37 @@ +package com.sap.sse.common.media; + +import java.net.URL; +import java.util.Date; + +public class VideoMetadataImpl extends AbstractMediaMetadata { + private static final long serialVersionUID = 2651747912466590862L; + + private int 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 VideoMetadataImpl(URL url, MimeType mimeType, Date createdAtDate) { + super(url, mimeType, createdAtDate); + } + + public int getLengthInSeconds() { + return lengthInSeconds; + } + + public void setLengthInSeconds(int lengthInSeconds) { + this.lengthInSeconds = lengthInSeconds; + } + + public URL getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(URL thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } +} diff --git a/java/com.sap.sse.gwt/META-INF/MANIFEST.MF b/java/com.sap.sse.gwt/META-INF/MANIFEST.MF index 787134236e9..9f582333b47 100644 --- a/java/com.sap.sse.gwt/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.gwt/META-INF/MANIFEST.MF @@ -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, diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java index 09c87896b97..8573ec18b09 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java @@ -14,7 +14,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". @@ -52,7 +52,7 @@ import com.sap.sse.common.media.ImageMetadataDTO; * * Created by pgtaboada on 10.11.14. */ -public class ImageCarousel extends Widget { +public class ImageCarousel extends Widget { private static SlickSliderUiBinder ourUiBinder = GWT.create(SlickSliderUiBinder.class); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java new file mode 100644 index 00000000000..8b5f0bc37d8 --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -0,0 +1,91 @@ +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 tags = new ArrayList(); + + protected String sourceRef; + + /** 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 getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public String getSourceRef() { + return sourceRef; + } + + public void setSourceRef(String sourceRef) { + this.sourceRef = sourceRef; + } + +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java new file mode 100644 index 00000000000..601491d158b --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java @@ -0,0 +1,36 @@ +package com.sap.sse.gwt.client.media; + +import java.util.Date; + +import com.sap.sse.common.media.ImageSize; +import com.sap.sse.common.media.MimeType; + +public class ImageDTO extends AbstractMediaDTO { + + /** for GWT */ + protected ImageDTO() { + } + + private int widthInPx; + private int heightInPx; + + public ImageDTO(String imageRef, ImageSize size, Date createdAtDate) { + super(imageRef, MimeType.image, createdAtDate); + this.widthInPx = size.getWidth(); + this.heightInPx = size.getHeight(); + } + + public ImageDTO(String imageRef, int heightInPx, int widthInPx, Date createdAtDate) { + super(imageRef, MimeType.image, createdAtDate); + this.widthInPx = widthInPx; + this.heightInPx = heightInPx; + } + + public int getWidthInPx() { + return widthInPx; + } + + public int getHeightInPx() { + return heightInPx; + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java new file mode 100644 index 00000000000..8c0d5d4e2ce --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java @@ -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 int lengthInSeconds; + private String thumbnailRef; + + /** for GWT */ + protected VideoDTO() { + } + + public VideoDTO(String videoRef, MimeType mimeType, Date createdAtDate) { + super(videoRef, mimeType, createdAtDate); + } + + public int getLengthInSeconds() { + return lengthInSeconds; + } + + public void setLengthInSeconds(int lengthInSeconds) { + this.lengthInSeconds = lengthInSeconds; + } + + public String getThumbnailRef() { + return thumbnailRef; + } + + public void setThumbnailRef(String thumbnailRef) { + this.thumbnailRef = thumbnailRef; + } +} From bc9dd55b88a5ec537637d12ca6db2e3745ef090c Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 3 Jun 2015 14:48:57 +0300 Subject: [PATCH 014/117] some name refactoring and cleanup of new image and video base classes --- ...ctMediaMetadata.java => AbstractMediaDescriptor.java} | 4 ++-- .../media/{ImageMetadata.java => ImageDescriptor.java} | 2 +- .../{ImageMetadataImpl.java => ImageDescriptorImpl.java} | 6 +++--- .../media/{MediaMetadata.java => MediaDescriptor.java} | 2 +- .../src/com/sap/sse/common/media/VideoDescriptor.java | 9 +++++++++ .../{VideoMetadataImpl.java => VideoDescriptorImpl.java} | 6 ++++-- .../src/com/sap/sse/common/media/VideoMetadata.java | 7 ------- 7 files changed, 20 insertions(+), 16 deletions(-) rename java/com.sap.sse.common/src/com/sap/sse/common/media/{AbstractMediaMetadata.java => AbstractMediaDescriptor.java} (90%) rename java/com.sap.sse.common/src/com/sap/sse/common/media/{ImageMetadata.java => ImageDescriptor.java} (63%) rename java/com.sap.sse.common/src/com/sap/sse/common/media/{ImageMetadataImpl.java => ImageDescriptorImpl.java} (71%) rename java/com.sap.sse.common/src/com/sap/sse/common/media/{MediaMetadata.java => MediaDescriptor.java} (92%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java rename java/com.sap.sse.common/src/com/sap/sse/common/media/{VideoMetadataImpl.java => VideoDescriptorImpl.java} (81%) delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java similarity index 90% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java index bde8a7600f2..1196d1d42ce 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaMetadata.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java @@ -11,7 +11,7 @@ import java.util.HashSet; * @author pgtaboada * */ -public abstract class AbstractMediaMetadata implements MediaMetadata, Serializable { +public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serializable { private static final long serialVersionUID = -6671425870632517274L; protected String title; @@ -33,7 +33,7 @@ public abstract class AbstractMediaMetadata implements MediaMetadata, Serializab * @param url * @param mimeType */ - public AbstractMediaMetadata(URL url, MimeType mimeType, Date createdAtDate) { + public AbstractMediaDescriptor(URL url, MimeType mimeType, Date createdAtDate) { this.mimeType = mimeType; this.url = url; this.createdAtDate = createdAtDate; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java similarity index 63% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java index 3a0b4ce16f2..a43eb583bcf 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadata.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java @@ -1,6 +1,6 @@ package com.sap.sse.common.media; -public interface ImageMetadata extends MediaMetadata { +public interface ImageDescriptor extends MediaDescriptor { public int getWidthInPx(); public int getHeightInPx(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java similarity index 71% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index 2f2961a3cdc..472089aecf6 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -4,7 +4,7 @@ import java.net.URL; import java.util.Date; -public class ImageMetadataImpl extends AbstractMediaMetadata { +public class ImageDescriptorImpl extends AbstractMediaDescriptor implements ImageDescriptor { private static final long serialVersionUID = -702731462768602331L; private int widthInPx; @@ -14,13 +14,13 @@ public class ImageMetadataImpl extends AbstractMediaMetadata { * @param imageURL * @param size */ - public ImageMetadataImpl(URL imageURL, ImageSize size, Date createdAtDate) { + public ImageDescriptorImpl(URL imageURL, ImageSize size, Date createdAtDate) { super(imageURL, MimeType.image, createdAtDate); this.widthInPx = size.getWidth(); this.heightInPx = size.getHeight(); } - public ImageMetadataImpl(URL imageURL, int heightInPx, int widthInPx, Date createdAtDate) { + public ImageDescriptorImpl(URL imageURL, int heightInPx, int widthInPx, Date createdAtDate) { super(imageURL, MimeType.image, createdAtDate); this.widthInPx = widthInPx; this.heightInPx = heightInPx; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java similarity index 92% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java index e7d169d763e..1a0572ed002 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaMetadata.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java @@ -6,7 +6,7 @@ import java.util.Date; /** * A common media interface for all kinds of media like images or videos. */ -public interface MediaMetadata { +public interface MediaDescriptor { public MimeType getMimeType(); public URL getURL(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java new file mode 100644 index 00000000000..171f095f77d --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java @@ -0,0 +1,9 @@ +package com.sap.sse.common.media; + +import java.net.URL; + +public interface VideoDescriptor extends MediaDescriptor { + public int getLengthInSeconds(); + + public URL getThumbnailURL(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java similarity index 81% rename from java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java index 3f5c699612f..bfbd2d9f539 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java @@ -3,7 +3,7 @@ package com.sap.sse.common.media; import java.net.URL; import java.util.Date; -public class VideoMetadataImpl extends AbstractMediaMetadata { +public class VideoDescriptorImpl extends AbstractMediaDescriptor implements VideoDescriptor { private static final long serialVersionUID = 2651747912466590862L; private int lengthInSeconds; @@ -15,10 +15,11 @@ public class VideoMetadataImpl extends AbstractMediaMetadata { */ private URL thumbnailURL; - public VideoMetadataImpl(URL url, MimeType mimeType, Date createdAtDate) { + public VideoDescriptorImpl(URL url, MimeType mimeType, Date createdAtDate) { super(url, mimeType, createdAtDate); } + @Override public int getLengthInSeconds() { return lengthInSeconds; } @@ -27,6 +28,7 @@ public class VideoMetadataImpl extends AbstractMediaMetadata { this.lengthInSeconds = lengthInSeconds; } + @Override public URL getThumbnailURL() { return thumbnailURL; } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java deleted file mode 100644 index de53a3d9bac..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadata.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sap.sse.common.media; - -public interface VideoMetadata extends MediaMetadata { - public int getLengthInSeconds(); - - public String getThumbnailRef(); -} From 4a78e194a2f20c1df48f0c6bd57043614afe54ed Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 3 Jun 2015 19:28:46 +0200 Subject: [PATCH 015/117] added loading and storing of the videos and load/store test --- .../impl/DomainObjectFactoryImpl.java | 101 ++++++++++++++++ .../domain/persistence/impl/FieldNames.java | 13 ++- .../impl/MongoObjectFactoryImpl.java | 52 ++++++++- .../sap/sailing/domain/base/EventBase.java | 3 +- .../domain/base/impl/EventBaseImpl.java | 61 ++++++++++ java/com.sap.sailing.gwt.ui/SailingGWT.launch | 2 +- ...estStoringAndLoadingEventsAndRegattas.java | 108 ++++++++++++++++++ .../common/media/AbstractMediaDescriptor.java | 42 +++++-- .../sap/sse/common/media/ImageDescriptor.java | 6 +- .../sse/common/media/ImageDescriptorImpl.java | 39 ++++--- .../sap/sse/common/media/MediaDescriptor.java | 28 +++-- .../sap/sse/common/media/VideoDescriptor.java | 6 +- .../sse/common/media/VideoDescriptorImpl.java | 11 +- .../com/sap/sse/common/media/WithImages.java | 25 ++++ .../com/sap/sse/common/media/WithMedia.java | 4 + .../com/sap/sse/common/media/WithVideos.java | 26 +++++ 16 files changed, 482 insertions(+), 45 deletions(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/WithImages.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/WithVideos.java diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 7e442fd7e4b..59cfced777e 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -189,6 +189,11 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.RGBColor; import com.sap.sse.common.impl.TimeRangeImpl; +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 DomainObjectFactoryImpl implements DomainObjectFactory { private static final Logger logger = Logger.getLogger(DomainObjectFactoryImpl.class.getName()); @@ -1072,6 +1077,24 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } } } + BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); + if (images != null) { + for (Object imageObject : images) { + ImageDescriptor image = loadImage((DBObject) imageObject); + if (image != null) { + result.addImage(image); + } + } + } + BasicDBList videos = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEOS.name()); + if (videos != null) { + for (Object videoObject : videos) { + VideoDescriptor video = loadVideo((DBObject) videoObject); + if (video != null) { + result.addVideo(video); + } + } + } return result; } @@ -2062,4 +2085,82 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } return resultUrls; } + + private ImageDescriptor loadImage(DBObject dbObject) { + ImageDescriptor image = null; + URL imageURL = loadURL(dbObject, FieldNames.IMAGE_URL); + if (imageURL != null) { + String title = (String) dbObject.get(FieldNames.IMAGE_TITLE.name()); + String subtitle = (String) dbObject.get(FieldNames.IMAGE_SUBTITLE.name()); + String copyright = (String) dbObject.get(FieldNames.IMAGE_COPYRIGHT.name()); + //Object mimeTypeRaw = dbObject.get(FieldNames.IMAGE_MIMETYPE.name()); + //MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + Integer imageWidth = (Integer) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); + Integer imageHeight = (Integer) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); + TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.IMAGE_CREATEDATDATE); + BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.IMAGE_TAGS.name()); + List imageTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + imageTags.add((String) tagObject); + } + } + image = new ImageDescriptorImpl(imageURL, createdAtDate); + image.setCopyright(copyright); + image.setTitle(title); + image.setSubtitle(subtitle); + image.setTags(imageTags); + if (imageWidth != null && imageHeight != null) { + image.setSize(imageWidth, imageHeight); + } + } + return image; + } + + private VideoDescriptor loadVideo(DBObject dbObject) { + VideoDescriptor video = null; + URL videoURL = loadURL(dbObject, FieldNames.VIDEO_URL); + if(videoURL != null) { + String title = (String) dbObject.get(FieldNames.VIDEO_TITLE.name()); + String subtitle = (String) dbObject.get(FieldNames.VIDEO_SUBTITLE.name()); + String copyright = (String) dbObject.get(FieldNames.VIDEO_COPYRIGHT.name()); + Object mimeTypeRaw = dbObject.get(FieldNames.VIDEO_MIMETYPE.name()); + MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.VIDEO_CREATEDATDATE); + BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.VIDEO_TAGS.name()); + Integer lengthInSeconds = (Integer) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); + URL thumbnailURL = loadURL(dbObject, FieldNames.VIDEO_THUMBNAIL_URL); + List videoTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + videoTags.add((String) tagObject); + } + } + video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate); + video.setCopyright(copyright); + video.setTitle(title); + video.setSubtitle(subtitle); + video.setTags(videoTags); + video.setLengthInSeconds(lengthInSeconds); + video.setThumbnailURL(thumbnailURL); + } + return video; + } + + private URL loadURL(DBObject dbObject, FieldNames field) { + URL result = null; + String urlAsString = (String) dbObject.get(field.name()); + if(urlAsString != null) { + try { + result = new URL(urlAsString); + } catch (MalformedURLException e) { + logger.severe("Error parsing URL '"+urlAsString+"' in field "+field.name()+"."); + } + } + return result; + } + + private void migrateImageAndVideoURLsOfEvent(Event event) { + // TODO: convert imageURLs, sponsorImageURLs and videoURLs collections of event to new image and video descriptor classes + } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java index 6db7c33016c..c31c87c3318 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -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_TITLE, IMAGE_SUBTITLE, IMAGE_MIMETYPE, IMAGE_COPYRIGHT, IMAGE_CREATEDATDATE, + IMAGE_WIDTH_IN_PX, IMAGE_HEIGHT_IN_PX, IMAGE_TAGS, + + // video fields + VIDEO_URL, VIDEO_TITLE, VIDEO_SUBTITLE, VIDEO_MIMETYPE, VIDEO_COPYRIGHT, VIDEO_CREATEDATDATE, + VIDEO_TAGS, VIDEO_THUMBNAIL_URL, VIDEO_LENGTH_IN_SECONDS; } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index b5b2f52ee59..98dfdcef926 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -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()); @@ -546,6 +548,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 +1222,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 +1417,40 @@ 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_TITLE.name(), image.getTitle()); + result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle()); + //result.put(FieldNames.IMAGE_MIMETYPE.name(), image.getMimeType().name()); + 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_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().name()); + 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; + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index ec8dd8ea3b1..a151375553a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -8,12 +8,13 @@ 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); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index 3376fbcdbee..da81953006a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -11,6 +11,8 @@ 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.media.ImageDescriptor; +import com.sap.sse.common.media.VideoDescriptor; public abstract class EventBaseImpl implements EventBase { private static final long serialVersionUID = -5749964088848611074L; @@ -27,6 +29,8 @@ public abstract class EventBaseImpl implements EventBase { private ConcurrentLinkedQueue sponsorImageURLs; private URL logoImageURL; private URL officialWebsiteURL; + private ConcurrentLinkedQueue images; + private ConcurrentLinkedQueue videos; protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id) { this(name, startDate, endDate, new VenueImpl(venueName), isPublic, id); @@ -46,6 +50,8 @@ public abstract class EventBaseImpl implements EventBase { this.imageURLs = new ConcurrentLinkedQueue(); this.videoURLs = new ConcurrentLinkedQueue(); this.sponsorImageURLs = new ConcurrentLinkedQueue(); + this.images = new ConcurrentLinkedQueue(); + this.videos = new ConcurrentLinkedQueue(); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { @@ -59,6 +65,12 @@ public abstract class EventBaseImpl implements EventBase { if (sponsorImageURLs == null) { sponsorImageURLs = new ConcurrentLinkedQueue(); } + if (images == null) { + images = new ConcurrentLinkedQueue(); + } + if (videos == null) { + videos = new ConcurrentLinkedQueue(); + } } @Override @@ -221,4 +233,53 @@ public abstract class EventBaseImpl implements EventBase { this.officialWebsiteURL = officialWebsiteURL; } + @Override + public Iterable 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 images) { + this.images.clear(); + if (images != null) { + Util.addAll(images, this.images); + } + } + + @Override + public Iterable 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 videos) { + this.videos.clear(); + if (videos != null) { + Util.addAll(videos, this.videos); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 2bbffe904de..a4ecbb468c0 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -69,7 +69,7 @@ - + diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 0149848272f..2eed6cf4c57 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -89,6 +89,11 @@ 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.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()); @@ -218,6 +223,109 @@ 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 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.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(videoTitle, loadedVideo1.getTitle()); + assertEquals(videoSubtitle, loadedVideo1.getSubtitle()); + assertEquals(createdAt, loadedVideo1.getCreatedAtDate()); + assertEquals(3, Util.size(loadedVideo1.getTags())); + } + @Test public void testLoadStoreRegattaConfiguration() { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java index 1196d1d42ce..7862e2b2a69 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java @@ -2,8 +2,11 @@ package com.sap.sse.common.media; import java.io.Serializable; import java.net.URL; -import java.util.Date; -import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; /** * Common media data for media items @@ -18,13 +21,13 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial protected String subtitle; - protected Date createdAtDate; + protected TimePoint createdAtDate; protected String copyright; protected MimeType mimeType; - protected HashSet tags = new HashSet(); + protected Set tags = new LinkedHashSet(); protected URL url; @@ -33,7 +36,7 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial * @param url * @param mimeType */ - public AbstractMediaDescriptor(URL url, MimeType mimeType, Date createdAtDate) { + public AbstractMediaDescriptor(URL url, MimeType mimeType, TimePoint createdAtDate) { this.mimeType = mimeType; this.url = url; this.createdAtDate = createdAtDate; @@ -54,30 +57,52 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial return title; } + @Override public void setTitle(String title) { this.title = title; } @Override - public HashSet getTags() { + public Set getTags() { return tags; } + @Override + public void setTags(Iterable 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 Date getCreatedAtDate() { + public TimePoint getCreatedAtDate() { return createdAtDate; } - public void setCreatedAtDate(Date createdAtDate) { + @Override + public void setCreatedAtDate(TimePoint createdAtDate) { this.createdAtDate = createdAtDate; } @@ -86,6 +111,7 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial return copyright; } + @Override public void setCopyright(String copyright) { this.copyright = copyright; } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java index a43eb583bcf..1dd147bbaf7 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java @@ -1,7 +1,9 @@ package com.sap.sse.common.media; public interface ImageDescriptor extends MediaDescriptor { - public int getWidthInPx(); + void setSize(ImageSize size); + void setSize(int widthInPx, int heightInPx); - public int getHeightInPx(); + Integer getWidthInPx(); + Integer getHeightInPx(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index 472089aecf6..522215f6dd6 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -1,37 +1,48 @@ package com.sap.sse.common.media; import java.net.URL; -import java.util.Date; + +import com.sap.sse.common.TimePoint; public class ImageDescriptorImpl extends AbstractMediaDescriptor implements ImageDescriptor { private static final long serialVersionUID = -702731462768602331L; - private int widthInPx; - private int heightInPx; + private Integer widthInPx; + private Integer heightInPx; /** * @param imageURL * @param size */ - public ImageDescriptorImpl(URL imageURL, ImageSize size, Date createdAtDate) { + public ImageDescriptorImpl(URL imageURL, TimePoint createdAtDate) { super(imageURL, MimeType.image, createdAtDate); - this.widthInPx = size.getWidth(); - this.heightInPx = size.getHeight(); } - public ImageDescriptorImpl(URL imageURL, int heightInPx, int widthInPx, Date createdAtDate) { - super(imageURL, MimeType.image, createdAtDate); - this.widthInPx = widthInPx; - this.heightInPx = heightInPx; - } - - public int getWidthInPx() { + @Override + public Integer getWidthInPx() { return widthInPx; } - public int getHeightInPx() { + @Override + public Integer getHeightInPx() { return heightInPx; } + @Override + public void setSize(ImageSize size) { + if (size != null) { + this.widthInPx = size.getWidth(); + this.heightInPx = size.getHeight(); + } else { + this.widthInPx = null; + this.heightInPx = null; + } + } + + @Override + public void setSize(int widthInPx, int heightInPx) { + this.widthInPx = widthInPx; + this.heightInPx = heightInPx; + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java index 1a0572ed002..afe6c8d43ce 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java @@ -1,23 +1,31 @@ package com.sap.sse.common.media; +import java.io.Serializable; import java.net.URL; -import java.util.Date; + +import com.sap.sse.common.TimePoint; /** * A common media interface for all kinds of media like images or videos. */ -public interface MediaDescriptor { - public MimeType getMimeType(); +public interface MediaDescriptor extends Serializable { + MimeType getMimeType(); + URL getURL(); - public URL getURL(); + String getTitle(); + void setTitle(String title); - public String getTitle(); + Iterable getTags(); + void setTags(Iterable tags); + boolean addTag(String tagName); + boolean removeTag(String tagName); - public Iterable getTags(); + String getSubtitle(); + void setSubtitle(String subtitle); - public String getSubtitle(); + TimePoint getCreatedAtDate(); + void setCreatedAtDate(TimePoint createdAtDate); - public Date getCreatedAtDate(); - - public String getCopyright(); + String getCopyright(); + void setCopyright(String copyright); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java index 171f095f77d..1f21c990afa 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java @@ -3,7 +3,9 @@ package com.sap.sse.common.media; import java.net.URL; public interface VideoDescriptor extends MediaDescriptor { - public int getLengthInSeconds(); + Integer getLengthInSeconds(); + void setLengthInSeconds(Integer lengthInSeconds); - public URL getThumbnailURL(); + URL getThumbnailURL(); + void setThumbnailURL(URL thumbnailURL); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java index bfbd2d9f539..ce8d112252e 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java @@ -1,12 +1,13 @@ package com.sap.sse.common.media; import java.net.URL; -import java.util.Date; + +import com.sap.sse.common.TimePoint; public class VideoDescriptorImpl extends AbstractMediaDescriptor implements VideoDescriptor { private static final long serialVersionUID = 2651747912466590862L; - private int lengthInSeconds; + private Integer lengthInSeconds; /** * URL to thumbnail image. This information works as override for youtube videos or as missing thumbnail @@ -15,16 +16,16 @@ public class VideoDescriptorImpl extends AbstractMediaDescriptor implements Vide */ private URL thumbnailURL; - public VideoDescriptorImpl(URL url, MimeType mimeType, Date createdAtDate) { + public VideoDescriptorImpl(URL url, MimeType mimeType, TimePoint createdAtDate) { super(url, mimeType, createdAtDate); } @Override - public int getLengthInSeconds() { + public Integer getLengthInSeconds() { return lengthInSeconds; } - public void setLengthInSeconds(int lengthInSeconds) { + public void setLengthInSeconds(Integer lengthInSeconds) { this.lengthInSeconds = lengthInSeconds; } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithImages.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithImages.java new file mode 100644 index 00000000000..ade9f8c6791 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithImages.java @@ -0,0 +1,25 @@ +package com.sap.sse.common.media; + +public interface WithImages { + /** + * Returns a non-null live but unmodifiable collection of image resources that can be + * used to represent the event, e.g., on a web page. + * + * @return a non-null value which may be empty + */ + Iterable getImages(); + + /** + * Replaces the {@link #getImages() current contents of the image sequence by the images in + * images. + * + * @param images + * if null, the internal sequence of images is cleared but remains valid (non- + * null) + */ + void setImages(Iterable images); + + void addImage(ImageDescriptor image); + + void removeImage(ImageDescriptor image); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java new file mode 100644 index 00000000000..6887f3eb8ae --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java @@ -0,0 +1,4 @@ +package com.sap.sse.common.media; + +public interface WithMedia extends WithImages, WithVideos { +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithVideos.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithVideos.java new file mode 100644 index 00000000000..5706f49757b --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithVideos.java @@ -0,0 +1,26 @@ +package com.sap.sse.common.media; + +public interface WithVideos { + + /** + * Returns a non-null live but unmodifiable collection of video resources that can be + * used to represent the event, e.g., on a web page. + * + * @return a non-null value which may be empty + */ + Iterable getVideos(); + + /** + * Replaces the {@link #getVideos() current contents of the video sequence by the videos in + * videos. + * + * @param videos + * if null, the internal sequence of videos is cleared but remains valid (non- + * null) + */ + void setVideos(Iterable videos); + + void addVideo(VideoDescriptor video); + + void removeVideo(VideoDescriptor video); +} From 60b84ee007a6fa8e6889db37c67130f60860f6a0 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 13:23:07 +0200 Subject: [PATCH 016/117] added ImageDTO and VideoDTO collections to EventDTO --- .../gwt/ui/server/SailingServiceImpl.java | 43 ++++++++++++++++++- .../sailing/gwt/ui/shared/EventBaseDTO.java | 23 +++++----- .../sap/sse/gwt/client/media/ImageDTO.java | 11 ++--- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index ff69e52db27..bd188c08d9d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -431,10 +431,14 @@ 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.VideoDescriptor; 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; @@ -3429,6 +3433,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for(URL url: event.getVideoURLs()) { eventDTO.addVideoURL(url.toString()); } + for(ImageDescriptor image: event.getImages()) { + eventDTO.addImage(convertToImageDTO(image)); + } + for(VideoDescriptor video: event.getVideos()) { + eventDTO.addVideo(convertToVideoDTO(video)); + } } private void setImageSize(EventBase event, EventBaseDTO eventDTO, URL imageURL) { @@ -3438,7 +3448,38 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S logger.log(Level.FINE, "Was unable to obtain image size for "+imageURL+" earlier.", e); } } - + + private ImageDTO convertToImageDTO(ImageDescriptor image) { + ImageDTO result = new ImageDTO(image.getURL().toString(), image.getWidthInPx(), image.getHeightInPx(), + image.getCreatedAtDate() != null ? image.getCreatedAtDate().asDate() : null); + result.setCopyright(image.getCopyright()); + result.setTitle(image.getTitle()); + result.setSubtitle(image.getSubtitle()); + result.setMimeType(image.getMimeType()); + List tags = new ArrayList(); + 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()); + List tags = new ArrayList(); + for(String tag: video.getTags()) { + tags.add(tag); + } + result.setTags(tags); + return result; + } + private EventDTO convertToEventDTO(Event event, boolean withStatisticalData) { EventDTO eventDTO = new EventDTO(event.getName()); copyEventBaseFieldsToDTO(event, eventDTO); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index cd88ab3025c..479333387e3 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -10,6 +10,8 @@ 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.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; @@ -27,9 +29,8 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { private List 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 images = new ArrayList<>(); + private List 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 @@ -146,20 +147,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 getImage() { + 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 getVideos() { + return videos; } public void setImageSize(String imageURL, ImageSize imageSize) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java index 601491d158b..e661ddfa424 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java @@ -11,8 +11,9 @@ public class ImageDTO extends AbstractMediaDTO { protected ImageDTO() { } - private int widthInPx; - private int heightInPx; + /** can be null if not known */ + private Integer widthInPx; + private Integer heightInPx; public ImageDTO(String imageRef, ImageSize size, Date createdAtDate) { super(imageRef, MimeType.image, createdAtDate); @@ -20,17 +21,17 @@ public class ImageDTO extends AbstractMediaDTO { this.heightInPx = size.getHeight(); } - public ImageDTO(String imageRef, int heightInPx, int widthInPx, Date createdAtDate) { + public ImageDTO(String imageRef, Integer widthInPx, Integer heightInPx, Date createdAtDate) { super(imageRef, MimeType.image, createdAtDate); this.widthInPx = widthInPx; this.heightInPx = heightInPx; } - public int getWidthInPx() { + public Integer getWidthInPx() { return widthInPx; } - public int getHeightInPx() { + public Integer getHeightInPx() { return heightInPx; } } From a456785d03a1b7431f07d49bb2c88cc030e9d7c2 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 16:50:24 +0200 Subject: [PATCH 017/117] first attempt to show the list of images in the adminconsole --- .../ui/adminconsole/EventCreateDialog.java | 2 + .../gwt/ui/adminconsole/EventDialog.java | 6 +- .../gwt/ui/adminconsole/EventEditDialog.java | 3 + .../ImageConfigImagesBarCell.java | 34 +++ .../ui/adminconsole/ImagesListComposite.java | 264 ++++++++++++++++++ .../sailing/gwt/ui/shared/EventBaseDTO.java | 2 +- 6 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageConfigImagesBarCell.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index fe79a48ff9b..0d01b9e47e1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -8,6 +8,7 @@ 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; public class EventCreateDialog extends EventDialog { @@ -33,5 +34,6 @@ public class EventCreateDialog extends EventDialog { logoImageURLEntryField.setVisibleLength(50); isPublicCheckBox = createCheckbox(""); isPublicCheckBox.setValue(false); + imagesListComposite.fillImages(Collections.emptyList()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 74d0956b7bc..02a675f19c9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -48,7 +48,8 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected StringListInlineEditorComposite sponsorImageURLList; protected StringConstantsListEditorComposite leaderboardGroupList; protected List availableLeaderboardGroups; - + protected ImagesListComposite imagesListComposite; + protected static class EventParameterValidator implements Validator { private StringMessages stringMessages; @@ -156,6 +157,8 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap new StringConstantsListEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), leaderboardGroupNames, "Select a leaderboard group...")); leaderboardGroupList.addValueChangeHandler(valueChangeHandler); + + imagesListComposite = new ImagesListComposite(stringMessages); } @Override @@ -232,6 +235,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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"); return panel; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 97a25711eab..2b8d38ab00b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -9,6 +10,7 @@ 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.media.ImageDTO; public class EventEditDialog extends EventDialog { public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, StringMessages stringMessages, DialogCallback callback) { @@ -54,5 +56,6 @@ public class EventEditDialog extends EventDialog { leaderboardGroupNames.add(leaderboardGroupDTO.getName()); } leaderboardGroupList.setValue(leaderboardGroupNames); + imagesListComposite.fillImages(event.getImages()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageConfigImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageConfigImagesBarCell.java new file mode 100644 index 00000000000..be162a0fd4e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageConfigImagesBarCell.java @@ -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 renderer, StringMessages stringMessages) { + super(); + this.stringMessages = stringMessages; + } + + @Override + protected Iterable getImageSpecs() { + return Arrays.asList( + new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())), + new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(IconResources.INSTANCE.removeIcon())) + ); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java new file mode 100644 index 00000000000..eb41e11ba36 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -0,0 +1,264 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +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.sse.gwt.client.media.ImageDTO; + +/** + * /** A composite showing the list of all images + * + * @author Frank Mittag (C5163974) + */ +public class ImagesListComposite extends Composite { + private final StringMessages stringMessages; + + private CellTable imageTable; + private SingleSelectionModel imageSelectionModel; + private ListDataProvider imageListDataProvider; + private List allImages; + private final Label noImagesLabel; + + private final SimplePanel mainPanel; + private final VerticalPanel panel; + + public static class AnchorCell extends AbstractCell { + @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("{1}") + 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; + allImages = new ArrayList(); + + mainPanel = new SimplePanel(); + panel = new VerticalPanel(); + mainPanel.setWidget(panel); + + HorizontalPanel eventControlsPanel = new HorizontalPanel(); + eventControlsPanel.setSpacing(5); + panel.add(eventControlsPanel); + + Button createEventBtn = new Button(stringMessages.actionAddEvent()); + createEventBtn.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + openCreateEventDialog(); + } + }); + eventControlsPanel.add(createEventBtn); + + imageListDataProvider = new ListDataProvider(); + imageTable = createEventTable(); + imageTable.ensureDebugId("ImagesCellTable"); + imageTable.setVisible(false); + + @SuppressWarnings("unchecked") + SingleSelectionModel multiSelectionModel = (SingleSelectionModel) imageTable.getSelectionModel(); + imageSelectionModel = multiSelectionModel; + + 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 createEventTable() { + CellTable table = new CellTable(/* pageSize */10000, tableRes); + imageListDataProvider.addDataDisplay(table); + table.setWidth("100%"); + + TextColumn titleColumn = new TextColumn() { + @Override + public String getValue(ImageDTO image) { + return image.getTitle() != null ? image.getTitle() : ""; + } + }; + + TextColumn createdAtDateColumn = new TextColumn() { + @Override + public String getValue(ImageDTO image) { + return image.getCreatedAtDate().toString(); + } + }; + + SafeHtmlCell tagsCell = new SafeHtmlCell(); + Column tagsColumn = new Column(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(", "); + // not more than 4 tags per line + if (i % 4 == 0) { + builder.appendHtmlConstant("
    "); + } + } + i++; + } + return builder.toSafeHtml(); + } + }; + + ImagesBarColumn imageActionColumn = new ImagesBarColumn( + new ImageConfigImagesBarCell(stringMessages)); + imageActionColumn.setFieldUpdater(new FieldUpdater() { + @Override + public void update(int index, ImageDTO image, String value) { + if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) { + removeImage(image); + } else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) { + openEditImageDialog(image); + } + } + }); + + titleColumn.setSortable(true); + createdAtDateColumn.setSortable(true); + + table.addColumn(titleColumn, stringMessages.title()); + table.addColumn(createdAtDateColumn, "Created At"); + table.addColumn(tagsColumn, "tags"); + table.addColumn(imageActionColumn, stringMessages.actions()); +// table.setSelectionModel(eventSelectionCheckboxColumn.getSelectionModel(), +// eventSelectionCheckboxColumn.getSelectionManager()); + + table.addColumnSortHandler(getEventTableColumnSortHandler(imageListDataProvider.getList(), titleColumn, createdAtDateColumn)); + table.getColumnSortList().push(createdAtDateColumn); + + return table; + } + + private ListHandler getEventTableColumnSortHandler(List eventRecords, + TextColumn titleColumn, TextColumn createdAtDateColumn) { + ListHandler result = new ListHandler(eventRecords); + result.setComparator(titleColumn, new Comparator() { + @Override + public int compare(ImageDTO i1, ImageDTO i2) { + return new NaturalComparator().compare(i1.getTitle(), i2.getTitle()); + } + }); + result.setComparator(createdAtDateColumn, new Comparator() { + @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 removeImage(ImageDTO event) { + } + + private void openCreateEventDialog() { +// EventCreateDialog dialog = new EventCreateDialog(Collections.unmodifiableCollection(existingEvents), +// existingLeaderboardGroups, stringMessages, new DialogCallback() { +// @Override +// public void cancel() { +// } +// +// @Override +// public void ok(ImageDTO newEvent) { +// createNewEvent(newEvent); +// } +// }); +// dialog.show(); + } + + private void openEditImageDialog(final ImageDTO selectedEvent) { +// List existingEvents = new ArrayList(eventListDataProvider.getList()); +// existingEvents.remove(selectedEvent); +// List existingLeaderboardGroups = new ArrayList(); +// Util.addAll(availableLeaderboardGroups, existingLeaderboardGroups); +// EventEditDialog dialog = new EventEditDialog(selectedEvent, Collections.unmodifiableCollection(existingEvents), +// existingLeaderboardGroups, stringMessages, new DialogCallback() { +// @Override +// public void cancel() { +// } +// +// @Override +// public void ok(ImageDTO updatedEvent) { +// updateEvent(selectedEvent, updatedEvent); +// } +// }); +// dialog.show(); + } + + public void fillImages(List images) { + if (images.isEmpty()) { + imageTable.setVisible(false); + noImagesLabel.setVisible(true); + } else { + imageTable.setVisible(true); + noImagesLabel.setVisible(false); + } + + imageSelectionModel.clear(); + allImages.clear(); + allImages.addAll(images); + } + + public List getAllEvents() { + return allImages; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 479333387e3..418699ecd20 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -151,7 +151,7 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { images.add(image); } - public List getImage() { + public List getImages() { return images; } From ab73fc2b3dfdd7c86cc737b2a3c1643524f28fb5 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 17:14:33 +0200 Subject: [PATCH 018/117] fixed some little bugs in ImagesListComposite --- .../ui/adminconsole/ImagesListComposite.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index eb41e11ba36..04fc924a678 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -31,7 +31,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.gwt.client.media.ImageDTO; /** - * /** A composite showing the list of all images + * /** A composite showing the list of media images * * @author Frank Mittag (C5163974) */ @@ -71,28 +71,25 @@ public class ImagesListComposite extends Composite { panel = new VerticalPanel(); mainPanel.setWidget(panel); - HorizontalPanel eventControlsPanel = new HorizontalPanel(); - eventControlsPanel.setSpacing(5); - panel.add(eventControlsPanel); + HorizontalPanel imagesControlsPanel = new HorizontalPanel(); + imagesControlsPanel.setSpacing(5); + panel.add(imagesControlsPanel); - Button createEventBtn = new Button(stringMessages.actionAddEvent()); - createEventBtn.addClickHandler(new ClickHandler() { + Button createImageBtn = new Button("Add image"); + createImageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateEventDialog(); + openCreateImageDialog(); } }); - eventControlsPanel.add(createEventBtn); + imagesControlsPanel.add(createImageBtn); + imageSelectionModel = new SingleSelectionModel(); imageListDataProvider = new ListDataProvider(); - imageTable = createEventTable(); + imageTable = createImagesTable(); imageTable.ensureDebugId("ImagesCellTable"); imageTable.setVisible(false); - @SuppressWarnings("unchecked") - SingleSelectionModel multiSelectionModel = (SingleSelectionModel) imageTable.getSelectionModel(); - imageSelectionModel = multiSelectionModel; - imageSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { @@ -109,7 +106,7 @@ public class ImagesListComposite extends Composite { initWidget(mainPanel); } - private CellTable createEventTable() { + private CellTable createImagesTable() { CellTable table = new CellTable(/* pageSize */10000, tableRes); imageListDataProvider.addDataDisplay(table); table.setWidth("100%"); @@ -120,6 +117,16 @@ public class ImagesListComposite extends Composite { return image.getTitle() != null ? image.getTitle() : ""; } }; + TextColumn sizeColumn = new TextColumn() { + @Override + public String getValue(ImageDTO image) { + String imageSize = ""; + if (image.getWidthInPx() != null && image.getHeightInPx() != null) { + imageSize = image.getWidthInPx() + " x " + image.getHeightInPx(); + } + return imageSize; + } + }; TextColumn createdAtDateColumn = new TextColumn() { @Override @@ -168,11 +175,9 @@ public class ImagesListComposite extends Composite { table.addColumn(titleColumn, stringMessages.title()); table.addColumn(createdAtDateColumn, "Created At"); - table.addColumn(tagsColumn, "tags"); + table.addColumn(sizeColumn, "Size"); + table.addColumn(tagsColumn, "Tags"); table.addColumn(imageActionColumn, stringMessages.actions()); -// table.setSelectionModel(eventSelectionCheckboxColumn.getSelectionModel(), -// eventSelectionCheckboxColumn.getSelectionManager()); - table.addColumnSortHandler(getEventTableColumnSortHandler(imageListDataProvider.getList(), titleColumn, createdAtDateColumn)); table.getColumnSortList().push(createdAtDateColumn); @@ -210,7 +215,7 @@ public class ImagesListComposite extends Composite { private void removeImage(ImageDTO event) { } - private void openCreateEventDialog() { + private void openCreateImageDialog() { // EventCreateDialog dialog = new EventCreateDialog(Collections.unmodifiableCollection(existingEvents), // existingLeaderboardGroups, stringMessages, new DialogCallback() { // @Override @@ -258,7 +263,7 @@ public class ImagesListComposite extends Composite { allImages.addAll(images); } - public List getAllEvents() { + public List getAllImages() { return allImages; } } From 96e5628ac255039238dbeeff28e4b024c74f0d58 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 18:56:48 +0200 Subject: [PATCH 019/117] added image create and image edit editors --- .../sailing/gwt/server/HomeServiceImpl.java | 15 ++- .../gwt/ui/adminconsole/EventEditDialog.java | 2 - .../ui/adminconsole/ImageCreateDialog.java | 24 ++++ .../gwt/ui/adminconsole/ImageDialog.java | 125 ++++++++++++++++++ .../gwt/ui/adminconsole/ImageEditDialog.java | 27 ++++ .../ui/adminconsole/ImagesListComposite.java | 69 +++++----- .../gwt/ui/server/SailingServiceImpl.java | 3 +- .../gwt/ui/shared/media/SailingImageDTO.java | 6 +- .../adminconsole/URLFieldWithFileUpload.java | 4 + .../sap/sse/gwt/client/media/ImageDTO.java | 16 +-- 10 files changed, 236 insertions(+), 55 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 2b471316693..7ad06be51e6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -221,8 +221,11 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home try { ImageSize imageSize = event.getImageSize(url); if(imageSize != null) { - // TODO: do we habe a title? - photoGalleryUrls.add(new SailingImageDTO(eventRef, url.toString(), imageSize, null)); + SailingImageDTO sailingImageDTO = new SailingImageDTO(eventRef, url.toString(), null); + if (imageSize != null) { + sailingImageDTO.setSizeInPx(imageSize.getWidth(), imageSize.getHeight()); + photoGalleryUrls.add(sailingImageDTO); + } } } catch (Exception e) { } @@ -434,9 +437,11 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } 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 - ); + // FIXME: using the event end date for 'createdAtDate' for now, we need a better solution for migration + SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), event.getEndDate().asDate()); + if (imageSize != null) { + entry.setSizeInPx(imageSize.getWidth(), imageSize.getHeight()); + } entry.setTitle(eventName); media.addPhoto(entry); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 2b8d38ab00b..d4ac1a1e384 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -2,7 +2,6 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -10,7 +9,6 @@ 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.media.ImageDTO; public class EventEditDialog extends EventDialog { public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, StringMessages stringMessages, DialogCallback callback) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java new file mode 100644 index 00000000000..2b98b8c85c2 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java @@ -0,0 +1,24 @@ +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.gwt.client.media.ImageDTO; + +public class ImageCreateDialog extends ImageDialog { + + public ImageCreateDialog(StringMessages stringMessages, DialogCallback 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); + tagsListEditor.setValue(Collections.emptyList()); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java new file mode 100644 index 00000000000..0620b1c53d7 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -0,0 +1,125 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +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.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.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 { + 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; + + protected static class ImageParameterValidator implements Validator { + private StringMessages stringMessages; + + public ImageParameterValidator(StringMessages stringMessages) { + this.stringMessages = stringMessages; + } + + @Override + public String getErrorMessage(ImageDTO eventToValidate) { + String errorMessage = null; + return errorMessage; + } + } + + public ImageDialog(ImageParameterValidator validator, StringMessages stringMessages, DialogCallback callback) { + super(stringMessages.image(), null, stringMessages.ok(), stringMessages.cancel(), validator, + callback); + this.stringMessages = stringMessages; + this.creationDate = new Date(); + getDialogBox().getWidget().setWidth("730px"); + final ValueChangeHandler> valueChangeHandler = new ValueChangeHandler>() { + @Override + public void onValueChange(ValueChangeEvent> event) { + validate(); + } + }; + + imageURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + final List tagSuggestions = Arrays.asList(new String[] { "Stage", "Eventteaser", "Sponsor", "Logo" }); + tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), + new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ + tagSuggestions, "Enter tags for the image", 50)); + tagsListEditor.addValueChangeHandler(valueChangeHandler); + } + + @Override + protected ImageDTO getResult() { + ImageDTO result = new ImageDTO(imageURLAndUploadComposite.getURL(), new Date()); + 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 tags = new ArrayList(); + 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); + + return panel; + } + + @Override + public void show() { + super.show(); + imageURLAndUploadComposite.setFocus(true); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java new file mode 100644 index 00000000000..45fb0194bc7 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java @@ -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 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 tags = new ArrayList(); + tags.addAll(image.getTags()); + tagsListEditor.setValue(tags); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index 04fc924a678..a81a48e1cf0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -28,6 +28,7 @@ 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.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.media.ImageDTO; /** @@ -216,51 +217,55 @@ public class ImagesListComposite extends Composite { } private void openCreateImageDialog() { -// EventCreateDialog dialog = new EventCreateDialog(Collections.unmodifiableCollection(existingEvents), -// existingLeaderboardGroups, stringMessages, new DialogCallback() { -// @Override -// public void cancel() { -// } -// -// @Override -// public void ok(ImageDTO newEvent) { -// createNewEvent(newEvent); -// } -// }); -// dialog.show(); + ImageCreateDialog dialog = new ImageCreateDialog(stringMessages, new DialogCallback() { + @Override + public void cancel() { + } + + @Override + public void ok(ImageDTO newImage) { + allImages.add(newImage); + imageListDataProvider.getList().add(newImage); + updateTableVisisbilty(); + } + }); + dialog.show(); } - private void openEditImageDialog(final ImageDTO selectedEvent) { -// List existingEvents = new ArrayList(eventListDataProvider.getList()); -// existingEvents.remove(selectedEvent); -// List existingLeaderboardGroups = new ArrayList(); -// Util.addAll(availableLeaderboardGroups, existingLeaderboardGroups); -// EventEditDialog dialog = new EventEditDialog(selectedEvent, Collections.unmodifiableCollection(existingEvents), -// existingLeaderboardGroups, stringMessages, new DialogCallback() { -// @Override -// public void cancel() { -// } -// -// @Override -// public void ok(ImageDTO updatedEvent) { -// updateEvent(selectedEvent, updatedEvent); -// } -// }); -// dialog.show(); + private void openEditImageDialog(final ImageDTO selectedImage) { + ImageEditDialog dialog = new ImageEditDialog(selectedImage, stringMessages, new DialogCallback() { + @Override + public void cancel() { + } + + @Override + public void ok(ImageDTO updatedImage) { + allImages.remove(selectedImage); + allImages.add(updatedImage); + imageListDataProvider.getList().remove(selectedImage); + imageListDataProvider.getList().add(updatedImage); + updateTableVisisbilty(); + } + }); + dialog.show(); } - public void fillImages(List images) { - if (images.isEmpty()) { + private void updateTableVisisbilty() { + if (allImages.isEmpty()) { imageTable.setVisible(false); noImagesLabel.setVisible(true); } else { imageTable.setVisible(true); noImagesLabel.setVisible(false); } - + } + + public void fillImages(List images) { imageSelectionModel.clear(); allImages.clear(); allImages.addAll(images); + + updateTableVisisbilty(); } public List getAllImages() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index bd188c08d9d..079109f73da 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3450,8 +3450,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } private ImageDTO convertToImageDTO(ImageDescriptor image) { - ImageDTO result = new ImageDTO(image.getURL().toString(), image.getWidthInPx(), image.getHeightInPx(), - image.getCreatedAtDate() != null ? image.getCreatedAtDate().asDate() : null); + 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()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java index 088ff272cfe..cd501f548cf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java @@ -3,7 +3,6 @@ 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.ImageSize; import com.sap.sse.gwt.client.media.ImageDTO; public class SailingImageDTO extends ImageDTO { @@ -14,10 +13,9 @@ public class SailingImageDTO extends ImageDTO { super(); } - public SailingImageDTO(EventReferenceDTO eventRef, String imageRef, ImageSize size, Date createdAtDate) { - super(imageRef, size, createdAtDate); + public SailingImageDTO(EventReferenceDTO eventRef, String imageRef, Date createdAtDate) { + super(imageRef, createdAtDate); this.eventRef = eventRef; - } public EventReferenceDTO getEventRef() { diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java index 0f5f9d68ece..193f89feeb2 100755 --- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java +++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java @@ -139,4 +139,8 @@ public class URLFieldWithFileUpload extends Composite { removeButton.setEnabled(true); } } + + public void setFocus(boolean focused) { + urlTextBox.setFocus(focused); + } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java index e661ddfa424..7e299d743db 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/ImageDTO.java @@ -2,7 +2,6 @@ package com.sap.sse.gwt.client.media; import java.util.Date; -import com.sap.sse.common.media.ImageSize; import com.sap.sse.common.media.MimeType; public class ImageDTO extends AbstractMediaDTO { @@ -15,16 +14,8 @@ public class ImageDTO extends AbstractMediaDTO { private Integer widthInPx; private Integer heightInPx; - public ImageDTO(String imageRef, ImageSize size, Date createdAtDate) { + public ImageDTO(String imageRef, Date createdAtDate) { super(imageRef, MimeType.image, createdAtDate); - this.widthInPx = size.getWidth(); - this.heightInPx = size.getHeight(); - } - - public ImageDTO(String imageRef, Integer widthInPx, Integer heightInPx, Date createdAtDate) { - super(imageRef, MimeType.image, createdAtDate); - this.widthInPx = widthInPx; - this.heightInPx = heightInPx; } public Integer getWidthInPx() { @@ -34,4 +25,9 @@ public class ImageDTO extends AbstractMediaDTO { public Integer getHeightInPx() { return heightInPx; } + + public void setSizeInPx(Integer widthInPx, Integer heightInPx) { + this.widthInPx = widthInPx; + this.heightInPx = heightInPx; + } } From 35330e35d74e41b2e8a055edcfe2e6fab6bde0fe Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 19:06:09 +0200 Subject: [PATCH 020/117] some optimizations in ImageListComposite --- .../ui/adminconsole/ImagesListComposite.java | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index a81a48e1cf0..d214ce6df8b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -1,6 +1,5 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -10,7 +9,6 @@ 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; @@ -28,6 +26,7 @@ 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.ImageDTO; @@ -42,7 +41,6 @@ public class ImagesListComposite extends Composite { private CellTable imageTable; private SingleSelectionModel imageSelectionModel; private ListDataProvider imageListDataProvider; - private List allImages; private final Label noImagesLabel; private final SimplePanel mainPanel; @@ -55,18 +53,10 @@ public class ImagesListComposite extends Composite { } } - interface AnchorTemplates extends SafeHtmlTemplates { - @SafeHtmlTemplates.Template("{1}") - 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; - allImages = new ArrayList(); mainPanel = new SimplePanel(); panel = new VerticalPanel(); @@ -132,7 +122,7 @@ public class ImagesListComposite extends Composite { TextColumn createdAtDateColumn = new TextColumn() { @Override public String getValue(ImageDTO image) { - return image.getCreatedAtDate().toString(); + return DateAndTimeFormatterUtil.formatDateAndTime(image.getCreatedAtDate()); } }; @@ -224,7 +214,6 @@ public class ImagesListComposite extends Composite { @Override public void ok(ImageDTO newImage) { - allImages.add(newImage); imageListDataProvider.getList().add(newImage); updateTableVisisbilty(); } @@ -240,8 +229,6 @@ public class ImagesListComposite extends Composite { @Override public void ok(ImageDTO updatedImage) { - allImages.remove(selectedImage); - allImages.add(updatedImage); imageListDataProvider.getList().remove(selectedImage); imageListDataProvider.getList().add(updatedImage); updateTableVisisbilty(); @@ -251,7 +238,7 @@ public class ImagesListComposite extends Composite { } private void updateTableVisisbilty() { - if (allImages.isEmpty()) { + if (imageListDataProvider.getList().isEmpty()) { imageTable.setVisible(false); noImagesLabel.setVisible(true); } else { @@ -262,13 +249,13 @@ public class ImagesListComposite extends Composite { public void fillImages(List images) { imageSelectionModel.clear(); - allImages.clear(); - allImages.addAll(images); + imageListDataProvider.getList().clear(); + imageListDataProvider.getList().addAll(images); updateTableVisisbilty(); } public List getAllImages() { - return allImages; + return imageListDataProvider.getList(); } } From 3c480c3836b83d045cf2e77bcbeb098b9ad76f1f Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 4 Jun 2015 19:12:54 +0200 Subject: [PATCH 021/117] added the short image name to the list view --- .../ui/adminconsole/ImagesListComposite.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index d214ce6df8b..37dfc0b0e4b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -102,6 +102,17 @@ public class ImagesListComposite extends Composite { imageListDataProvider.addDataDisplay(table); table.setWidth("100%"); + TextColumn shortImageNameColumn = new TextColumn() { + @Override + public String getValue(ImageDTO image) { + String result = ""; + int index = image.getSourceRef().lastIndexOf("/"); + if(index > 0) { + result = image.getSourceRef().substring(index+1, image.getSourceRef().length()); + } + return result; + } + }; TextColumn titleColumn = new TextColumn() { @Override public String getValue(ImageDTO image) { @@ -154,7 +165,8 @@ public class ImagesListComposite extends Composite { @Override public void update(int index, ImageDTO image, String value) { if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) { - removeImage(image); + imageListDataProvider.getList().remove(image); + updateTableVisisbilty(); } else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) { openEditImageDialog(image); } @@ -164,6 +176,7 @@ public class ImagesListComposite extends Composite { 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"); @@ -203,9 +216,6 @@ public class ImagesListComposite extends Composite { return result; } - private void removeImage(ImageDTO event) { - } - private void openCreateImageDialog() { ImageCreateDialog dialog = new ImageCreateDialog(stringMessages, new DialogCallback() { @Override From 508dc7550adfb142e1bf08d4288001a865e4651d Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 5 Jun 2015 13:45:24 +0200 Subject: [PATCH 022/117] Integrated images and video collections of 'Event' into the CreateEvent and UpdateEvent operations --- .../gwt/ui/adminconsole/EventDialog.java | 4 ++ .../ui/adminconsole/EventListComposite.java | 5 +- .../ui/adminconsole/ImagesListComposite.java | 20 +++++-- .../StructureImportManagementPanel.java | 2 +- .../sailing/gwt/ui/client/SailingService.java | 7 ++- .../gwt/ui/client/SailingServiceAsync.java | 6 +- .../gwt/ui/server/SailingServiceImpl.java | 59 +++++++++++++++++-- .../server/test/MasterDataImportTest.java | 10 +++- .../server/test/SearchServiceTest.java | 8 ++- .../sailing/server/RacingEventService.java | 8 ++- .../server/impl/RacingEventServiceImpl.java | 18 ++++-- .../CreateEvent.java | 11 +++- .../UpdateEvent.java | 11 +++- .../sap/sse/common/media/ImageDescriptor.java | 2 +- .../sse/common/media/ImageDescriptorImpl.java | 2 +- 15 files changed, 140 insertions(+), 33 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 02a675f19c9..1d39761ec2c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -30,6 +30,7 @@ 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; public abstract class EventDialog extends DataEntryDialogWithBootstrap { protected StringMessages stringMessages; @@ -194,6 +195,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap for (String sponsorImageURL : sponsorImageURLList.getValue()) { result.addSponsorImageURL(sponsorImageURL); } + for(ImageDTO image: imagesListComposite.getAllImages()) { + result.addImage(image); + } result.venue = new VenueDTO(venueEntryField.getText(), courseAreas); return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index f1c6cc289bf..ce9635be3c5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -509,6 +509,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le updatedEvent.isPublic, updatedEventLeaderboardGroupIds, updatedEvent.getOfficialWebsiteURL(), updatedEvent.getLogoImageURL(), updatedEvent.getImageURLs(), updatedEvent.getVideoURLs(), updatedEvent.getSponsorImageURLs(), + updatedEvent.getImages(), updatedEvent.getVideos(), new AsyncCallback() { @Override public void onFailure(Throwable t) { @@ -580,8 +581,8 @@ public class EventListComposite extends Composite implements EventsRefresher, Le } 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() { + newEvent.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getImages(), newEvent.getVideos(), + newEvent.getLogoImageURL(), newEvent.getOfficialWebsiteURL(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index 37dfc0b0e4b..eeea9ed25c3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -9,6 +9,7 @@ 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; @@ -53,6 +54,13 @@ public class ImagesListComposite extends Composite { } } + interface AnchorTemplates extends SafeHtmlTemplates { + @SafeHtmlTemplates.Template("{1}") + 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) { @@ -102,17 +110,19 @@ public class ImagesListComposite extends Composite { imageListDataProvider.addDataDisplay(table); table.setWidth("100%"); - TextColumn shortImageNameColumn = new TextColumn() { + AnchorCell anchorCell = new AnchorCell(); + Column shortImageNameColumn = new Column(anchorCell) { @Override - public String getValue(ImageDTO image) { - String result = ""; + public SafeHtml getValue(ImageDTO image) { + String linkName = ""; int index = image.getSourceRef().lastIndexOf("/"); if(index > 0) { - result = image.getSourceRef().substring(index+1, image.getSourceRef().length()); + linkName = image.getSourceRef().substring(index+1, image.getSourceRef().length()); } - return result; + return ANCHORTEMPLATE.cell(image.getSourceRef(), linkName); } }; + TextColumn titleColumn = new TextColumn() { @Override public String getValue(ImageDTO image) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java index 65d0a11e75c..e9fa6391bb4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java @@ -247,7 +247,7 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta } 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.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getImages(), newEvent.getVideos(), newEvent.getLogoImageURL(), newEvent.getOfficialWebsiteURL(), new AsyncCallback() { @Override public void onFailure(Throwable t) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index d41a0374f8b..5f9b628e507 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -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 null date is passed to @@ -295,11 +297,12 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, String logoImageURL, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs) throws Exception; + Iterable sponsorImageURLs, Iterable images, Iterable videos) throws Exception; EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, List courseAreaNames, Iterable imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, String logoImageURL, String officialWebsiteURL) throws Exception; + Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + String logoImageURL, String officialWebsiteURL) throws Exception; void removeEvent(UUID eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 17b7ada94e8..7fa37e45a6d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -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} @@ -366,12 +368,12 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM void createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, List courseAreaNames, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs, String logoImageURL, String officialWebsiteURL, AsyncCallback callback); + Iterable sponsorImageURLs, Iterable images, Iterable videos, String logoImageURL, String officialWebsiteURL, AsyncCallback callback); void updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, String logoImageURL, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs, AsyncCallback callback); + Iterable sponsorImageURLs, Iterable images, Iterable videos, AsyncCallback callback); void createCourseArea(UUID eventId, String courseAreaName, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 079109f73da..0667a8d717f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -432,7 +432,9 @@ 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.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; @@ -3297,7 +3299,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S public EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURLString, String logoImageURLString, Iterable imageURLStrings, Iterable videoURLStrings, - Iterable sponsorImageURLStrings) throws MalformedURLException { + Iterable sponsorImageURLStrings, Iterable images, Iterable 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; @@ -3305,10 +3307,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List imageURLs = createURLsFromStrings(imageURLStrings); List videoURLs = createURLsFromStrings(videoURLStrings); List sponsorimagieURLs = createURLsFromStrings(sponsorImageURLStrings); + List eventImages = new ArrayList(); + for (ImageDTO image : images) { + eventImages.add(convertToImage(image)); + } + List eventVideos = new ArrayList(); + for (VideoDTO video : videos) { + eventVideos.add(convertToVideo(video)); + } getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, imageURLs, videoURLs, - sponsorimagieURLs)); + sponsorimagieURLs, eventImages, eventVideos)); return getEventById(eventId, false); } @@ -3328,16 +3338,27 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, List courseAreaNames, Iterable imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, String logoImageURLAsString, String officialWebsiteURLAsString) + Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + String logoImageURLAsString, String officialWebsiteURLAsString) throws MalformedURLException { UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; + List eventImages = new ArrayList(); + for (ImageDTO image : images) { + eventImages.add(convertToImage(image)); + } + List eventVideos = new ArrayList(); + for (VideoDTO video : videos) { + eventVideos.add(convertToVideo(video)); + } 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))); + eventImages, eventVideos, + logoImageURLAsString == null ? null : new URL(logoImageURLAsString), + officialWebsiteURLAsString == null ? null : new URL(officialWebsiteURLAsString))); for (String courseAreaName : courseAreaNames) { createCourseArea(eventUuid, courseAreaName); } @@ -3449,6 +3470,34 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } + 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()); + for (String tag : image.getTags()) { + result.addTag(tag); + } + return result; + } + + private VideoDescriptor convertToVideo(VideoDTO video) throws MalformedURLException { + VideoDescriptor result = new VideoDescriptorImpl(new URL(video.getSourceRef()), video.getMimeType(), 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())); + 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()); @@ -4108,7 +4157,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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.getSponsorImageURLs(), newEvent.getImages(), newEvent.getVideos()); } @Override diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index 4bf9378e56b..879448b4f33 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -127,7 +127,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; @@ -1331,7 +1333,9 @@ public class MasterDataImportTest { Iterable 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); + videoURLs, sponsorImageURLs, + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + /* logoImageURL */ null, /* officialWebsiteURL */ null); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); Regatta regatta = sourceService.createRegatta( @@ -1398,7 +1402,9 @@ public class MasterDataImportTest { Iterable 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); + videoURLs, sponsorImageURLs, + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + /* logoImageURL */ null, /* officialWebsiteURL */ null); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); List raceColumnNames = new ArrayList(); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java index 3235fccba05..a1751a5fa21 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java @@ -73,6 +73,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; @@ -120,8 +122,9 @@ public class SearchServiceTest { final TimePoint pfingstbuschEndDate = new MillisecondsTimePoint(cal.getTime()); pfingstbusch = server.apply(new CreateEvent("Pfingsbusch", /* eventDescription */ null, pfingstbuschStartDate, pfingstbuschEndDate, /* isPublic */ "Kiel", true, UUID.randomUUID(), Collections.emptySet(), - Collections.emptySet(), - /* sponsorImageURLs */ Collections.emptySet(), /* logoImageURLAsString */ null, /* officialWebsiteURLAsString */ null)); + Collections.emptySet(), /* sponsorImageURLs */ Collections.emptySet(), + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + /* logoImageURLAsString */ null, /* officialWebsiteURLAsString */ null)); kiel = pfingstbusch.getVenue(); final CourseAreaImpl kielAlpha = new CourseAreaImpl("Alpha", UUID.randomUUID()); kiel.addCourseArea(kielAlpha); @@ -156,6 +159,7 @@ public class SearchServiceTest { aalEvent = server.apply(new CreateEvent("Aalregatta", /* eventDescription */ null, aalStartDate, aalEndDate, /* isPublic */ "Flensburg", true, UUID.randomUUID(), Collections.emptySet(), Collections.emptySet(), /* sponsorImageURLs */ Collections.emptySet(), + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoimageURL */ null, /* officialWebsiteURLAsString */ null)); flensburg = aalEvent.getVenue(); final CourseAreaImpl flensburgStandard = new CourseAreaImpl("Standard", UUID.randomUUID()); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index f0aa9d9f5d6..55b20ed8323 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -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,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch */ void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs); + URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, + Iterable images, Iterable videos); /** * Renames a sailing event. If a sailing event by the name oldName does not exist in {@link #getEvents()}, @@ -464,7 +467,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch ConcurrentHashMap getPersistentRegattasForRaceIDs(); Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL); + boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, + Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL); void setRegattaForRace(Regatta regatta, String raceIdAsString); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 657e50f24b8..94af6175092 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -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; @@ -2573,11 +2575,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes String venue, boolean isPublic, UUID id) { Event result = createEventWithoutReplication(eventName, eventDescription, startDate, endDate, venue, isPublic, id, /* imageURLs */Collections. emptyList(), - /* videoURLs */Collections. emptyList(), /* sponsorImageURLs */Collections. emptyList(), /* logoImageURL */ - null, /* officialWebsiteURL */null); + /* videoURLs */Collections. emptyList(), /* sponsorImageURLs */Collections. emptyList(), + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + /* logoImageURL */ null, /* officialWebsiteURL */null); replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, /* imageURLs */ id, Collections. emptyList(), /* videoURLs */Collections. emptyList(), /* sponsorImageURLs */Collections. emptyList(), + /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoimageURL */null, /* officialWebsiteURLAsString */null)); return result; } @@ -2590,7 +2594,8 @@ 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 imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL) { + Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + URL logoImageURL, URL officialWebsiteURL) { Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id); addEvent(result); result.setDescription(eventDescription); @@ -2599,6 +2604,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes result.setSponsorImageURLs(sponsorImageURLs); result.setLogoImageURL(logoImageURL); result.setOfficialWebsiteURL(officialWebsiteURL); + result.setImages(images); + result.setVideos(videos); return result; } @@ -2614,7 +2621,8 @@ 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 leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs) { + URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, + Iterable images, Iterable videos) { final Event event = eventsById.get(id); if (event == null) { throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist."); @@ -2641,6 +2649,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes 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); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java index f69739ad775..7490157d029 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java @@ -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. @@ -26,11 +28,14 @@ public class CreateEvent extends AbstractEventOperation { private final Iterable videoURLs; private final Iterable imageURLs; private final Iterable sponsorImageURLs; + private final Iterable images; + private final Iterable videos; private final URL logoImageURL; private final URL officialWebsiteURL; public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, URL logoImageURL, URL officialWebsiteURL) { + boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, + Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -41,6 +46,8 @@ public class CreateEvent extends AbstractEventOperation { this.imageURLs = imageURLs; this.videoURLs = videoURLs; this.sponsorImageURLs = sponsorImageURLs; + this.images = images; + this.videos = videos; this.logoImageURL = logoImageURL; this.officialWebsiteURL = officialWebsiteURL; } @@ -64,7 +71,7 @@ public class CreateEvent extends AbstractEventOperation { @Override public Event internalApplyTo(RacingEventService toState) { return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic, - getId(), imageURLs, videoURLs, sponsorImageURLs, logoImageURL, officialWebsiteURL); + getId(), imageURLs, videoURLs, sponsorImageURLs, images, videos, logoImageURL, officialWebsiteURL); } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java index 4b839e6a943..c8c17174f0f 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java @@ -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 { private static final long serialVersionUID = -8271559266421161532L; @@ -21,10 +23,13 @@ public class UpdateEvent extends AbstractEventOperation { private final Iterable imageURLs; private final Iterable videoURLs; private final Iterable sponsorImageURLs; + private final Iterable images; + private final Iterable videos; public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL logoImageURL, - URL officialWebsiteURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs) { + URL officialWebsiteURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, + Iterable images, Iterable videos) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -38,6 +43,8 @@ public class UpdateEvent extends AbstractEventOperation { this.imageURLs = imageURLs; this.videoURLs = videoURLs; this.sponsorImageURLs = sponsorImageURLs; + this.images = images; + this.videos = videos; } @Override @@ -55,7 +62,7 @@ public class UpdateEvent extends AbstractEventOperation { @Override public Void internalApplyTo(RacingEventService toState) { toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic, - leaderboardGroupIds, officialWebsiteURL, logoImageURL, imageURLs, videoURLs, sponsorImageURLs); + leaderboardGroupIds, officialWebsiteURL, logoImageURL, imageURLs, videoURLs, sponsorImageURLs, images, videos); return null; } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java index 1dd147bbaf7..240b2b46fa2 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java @@ -2,7 +2,7 @@ package com.sap.sse.common.media; public interface ImageDescriptor extends MediaDescriptor { void setSize(ImageSize size); - void setSize(int widthInPx, int heightInPx); + void setSize(Integer widthInPx, Integer heightInPx); Integer getWidthInPx(); Integer getHeightInPx(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index 522215f6dd6..424cd995dce 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -41,7 +41,7 @@ public class ImageDescriptorImpl extends AbstractMediaDescriptor implements Imag } @Override - public void setSize(int widthInPx, int heightInPx) { + public void setSize(Integer widthInPx, Integer heightInPx) { this.widthInPx = widthInPx; this.heightInPx = heightInPx; } From 05c7d89cdd8fd41fa4561b7e62679346fc3b9dae Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 5 Jun 2015 17:35:29 +0200 Subject: [PATCH 023/117] added a created and edit editor for videos of an event --- .../impl/DomainObjectFactoryImpl.java | 4 - .../gwt/ui/adminconsole/EventDialog.java | 3 + .../gwt/ui/adminconsole/EventEditDialog.java | 1 + .../gwt/ui/adminconsole/ImageDialog.java | 8 +- .../ui/adminconsole/ImagesListComposite.java | 6 +- .../VideoConfigImagesBarCell.java | 34 +++ .../ui/adminconsole/VideoCreateDialog.java | 23 ++ .../gwt/ui/adminconsole/VideoDialog.java | 154 ++++++++++ .../gwt/ui/adminconsole/VideoEditDialog.java | 26 ++ .../ui/adminconsole/VideosListComposite.java | 270 ++++++++++++++++++ .../sap/sse/gwt/client/media/VideoDTO.java | 6 +- 11 files changed, 523 insertions(+), 12 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoConfigImagesBarCell.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 59cfced777e..d99a07a25e0 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -2159,8 +2159,4 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } return result; } - - private void migrateImageAndVideoURLsOfEvent(Event event) { - // TODO: convert imageURLs, sponsorImageURLs and videoURLs collections of event to new image and video descriptor classes - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 1d39761ec2c..76a6325dd1b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -50,6 +50,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected StringConstantsListEditorComposite leaderboardGroupList; protected List availableLeaderboardGroups; protected ImagesListComposite imagesListComposite; + protected VideosListComposite videosListComposite; protected static class EventParameterValidator implements Validator { @@ -160,6 +161,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap leaderboardGroupList.addValueChangeHandler(valueChangeHandler); imagesListComposite = new ImagesListComposite(stringMessages); + videosListComposite = new VideosListComposite(stringMessages); } @Override @@ -240,6 +242,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index d4ac1a1e384..e875e941820 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -55,5 +55,6 @@ public class EventEditDialog extends EventDialog { } leaderboardGroupList.setValue(leaderboardGroupNames); imagesListComposite.fillImages(event.getImages()); + videosListComposite.fillVideos(event.getVideos()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index 0620b1c53d7..5661d1f6068 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -41,8 +41,12 @@ public abstract class ImageDialog extends DataEntryDialog { } @Override - public String getErrorMessage(ImageDTO eventToValidate) { + public String getErrorMessage(ImageDTO imageToValidate) { String errorMessage = null; + + if(imageToValidate.getSourceRef() == null || imageToValidate.getSourceRef().isEmpty()) { + errorMessage = "You must provide a valid URL for the image"; + } return errorMessage; } } @@ -70,7 +74,7 @@ public abstract class ImageDialog extends DataEntryDialog { @Override protected ImageDTO getResult() { - ImageDTO result = new ImageDTO(imageURLAndUploadComposite.getURL(), new Date()); + ImageDTO result = new ImageDTO(imageURLAndUploadComposite.getURL(), creationDate); result.setTitle(titleTextBox.getValue()); result.setSubtitle(subtitleTextBox.getValue()); result.setCopyright(copyrightTextBox.getValue()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index eeea9ed25c3..6d353240cd8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -192,15 +192,15 @@ public class ImagesListComposite extends Composite { table.addColumn(sizeColumn, "Size"); table.addColumn(tagsColumn, "Tags"); table.addColumn(imageActionColumn, stringMessages.actions()); - table.addColumnSortHandler(getEventTableColumnSortHandler(imageListDataProvider.getList(), titleColumn, createdAtDateColumn)); + table.addColumnSortHandler(getImageTableColumnSortHandler(imageListDataProvider.getList(), titleColumn, createdAtDateColumn)); table.getColumnSortList().push(createdAtDateColumn); return table; } - private ListHandler getEventTableColumnSortHandler(List eventRecords, + private ListHandler getImageTableColumnSortHandler(List imageRecords, TextColumn titleColumn, TextColumn createdAtDateColumn) { - ListHandler result = new ListHandler(eventRecords); + ListHandler result = new ListHandler(imageRecords); result.setComparator(titleColumn, new Comparator() { @Override public int compare(ImageDTO i1, ImageDTO i2) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoConfigImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoConfigImagesBarCell.java new file mode 100644 index 00000000000..ba8665c8697 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoConfigImagesBarCell.java @@ -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 renderer, StringMessages stringMessages) { + super(); + this.stringMessages = stringMessages; + } + + @Override + protected Iterable getImageSpecs() { + return Arrays.asList( + new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())), + new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(IconResources.INSTANCE.removeIcon())) + ); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java new file mode 100644 index 00000000000..48743d9268f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java @@ -0,0 +1,23 @@ +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.gwt.client.media.VideoDTO; + +public class VideoCreateDialog extends VideoDialog { + + public VideoCreateDialog(StringMessages stringMessages, DialogCallback 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.emptyList()); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java new file mode 100644 index 00000000000..ae8a928cc73 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -0,0 +1,154 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +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.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 { + 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 IntegerBox lengthIntegerBox; + protected final URLFieldWithFileUpload thumbnailURLAndUploadComposite; + protected StringListInlineEditorComposite tagsListEditor; + + protected static class VideoParameterValidator implements Validator { + 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 = "You must provide a valid URL for the video."; + } else if (videoToValidate.getMimeType() == null) { + errorMessage = "You must select the mime type for the video."; + } + return errorMessage; + } + } + + public VideoDialog(VideoParameterValidator validator, StringMessages stringMessages, DialogCallback callback) { + super(stringMessages.video(), null, stringMessages.ok(), stringMessages.cancel(), validator, + callback); + this.stringMessages = stringMessages; + this.creationDate = new Date(); + getDialogBox().getWidget().setWidth("730px"); + final ValueChangeHandler> valueChangeHandler = new ValueChangeHandler>() { + @Override + public void onValueChange(ValueChangeEvent> event) { + validate(); + } + }; + + mimeTypeListBox = createListBox(false); + mimeTypeListBox.addItem("Select a mime type"); + 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()); + + videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured" }); + tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), + new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ + tagSuggestions, "Enter tags for the video", 50)); + tagsListEditor.addValueChangeHandler(valueChangeHandler); + } + + @Override + protected VideoDTO getResult() { + VideoDTO result = new VideoDTO(videoURLAndUploadComposite.getURL(), getSelectedMimeType(), creationDate); + result.setTitle(titleTextBox.getValue()); + result.setSubtitle(subtitleTextBox.getValue()); + result.setCopyright(copyrightTextBox.getValue()); + List tags = new ArrayList(); + for (String tag: tagsListEditor.getValue()) { + tags.add(tag); + } + result.setTags(tags); + return result; + } + + private MimeType getSelectedMimeType() { + MimeType result = null; + int selectedIndex = mimeTypeListBox.getSelectedIndex(); + if(selectedIndex > 0) { + result = MimeType.valueOf(mimeTypeListBox.getSelectedValue()); + } + 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(9, 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("Tags:")); + formGrid.setWidget(6, 1, tagsListEditor); + + formGrid.setWidget(7, 0, new Label("Video-Length (s):")); + formGrid.setWidget(7, 1, lengthIntegerBox); + formGrid.setWidget(8, 0, new Label("Thumbnail-URL:")); + formGrid.setWidget(8, 1, thumbnailURLAndUploadComposite); + + return panel; + } + + @Override + public void show() { + super.show(); + videoURLAndUploadComposite.setFocus(true); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java new file mode 100644 index 00000000000..c528d410fa0 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java @@ -0,0 +1,26 @@ +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 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 tags = new ArrayList(); + tags.addAll(video.getTags()); + tagsListEditor.setValue(tags); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java new file mode 100644 index 00000000000..a2280a71863 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java @@ -0,0 +1,270 @@ +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 videoTable; + private SingleSelectionModel videoSelectionModel; + private ListDataProvider videoListDataProvider; + private final Label noVideosLabel; + + private final SimplePanel mainPanel; + private final VerticalPanel panel; + + public static class AnchorCell extends AbstractCell { + @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("{1}") + 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(); + videoListDataProvider = new ListDataProvider(); + videoTable = createImagesTable(); + videoTable.ensureDebugId("ImagesCellTable"); + 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 createImagesTable() { + CellTable table = new CellTable(/* pageSize */10000, tableRes); + videoListDataProvider.addDataDisplay(table); + table.setWidth("100%"); + + AnchorCell anchorCell = new AnchorCell(); + Column shortVideoNameColumn = new Column(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 titleColumn = new TextColumn() { + @Override + public String getValue(VideoDTO image) { + return image.getTitle() != null ? image.getTitle() : ""; + } + }; + + TextColumn createdAtDateColumn = new TextColumn() { + @Override + public String getValue(VideoDTO image) { + return DateAndTimeFormatterUtil.formatDateAndTime(image.getCreatedAtDate()); + } + }; + + SafeHtmlCell tagsCell = new SafeHtmlCell(); + Column tagsColumn = new Column(tagsCell) { + @Override + public SafeHtml getValue(VideoDTO 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(", "); + // not more than 4 tags per line + if (i % 4 == 0) { + builder.appendHtmlConstant("
    "); + } + } + i++; + } + return builder.toSafeHtml(); + } + }; + + ImagesBarColumn videoActionColumn = new ImagesBarColumn( + new VideoConfigImagesBarCell(stringMessages)); + videoActionColumn.setFieldUpdater(new FieldUpdater() { + @Override + public void update(int index, VideoDTO image, String value) { + if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) { + videoListDataProvider.getList().remove(image); + updateTableVisisbilty(); + } else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) { + openEditVideoDialog(image); + } + } + }); + + titleColumn.setSortable(true); + createdAtDateColumn.setSortable(true); + + table.addColumn(shortVideoNameColumn, "Short name"); + table.addColumn(titleColumn, stringMessages.title()); + table.addColumn(createdAtDateColumn, "Created At"); + table.addColumn(tagsColumn, "Tags"); + table.addColumn(videoActionColumn, stringMessages.actions()); + table.addColumnSortHandler(getVideoTableColumnSortHandler(videoListDataProvider.getList(), titleColumn, createdAtDateColumn)); + table.getColumnSortList().push(createdAtDateColumn); + + return table; + } + + private ListHandler getVideoTableColumnSortHandler(List videoRecords, + TextColumn titleColumn, TextColumn createdAtDateColumn) { + ListHandler result = new ListHandler(videoRecords); + result.setComparator(titleColumn, new Comparator() { + @Override + public int compare(VideoDTO i1, VideoDTO i2) { + return new NaturalComparator().compare(i1.getTitle(), i2.getTitle()); + } + }); + result.setComparator(createdAtDateColumn, new Comparator() { + @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() { + @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() { + @Override + public void cancel() { + } + + @Override + public void ok(VideoDTO updatedImage) { + videoListDataProvider.getList().remove(selectedVideo); + videoListDataProvider.getList().add(updatedImage); + 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 videos) { + videoSelectionModel.clear(); + videoListDataProvider.getList().clear(); + videoListDataProvider.getList().addAll(videos); + + updateTableVisisbilty(); + } + + public List getAllVideos() { + return videoListDataProvider.getList(); + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java index 8c0d5d4e2ce..53fbd533cf1 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java @@ -5,7 +5,7 @@ import java.util.Date; import com.sap.sse.common.media.MimeType; public class VideoDTO extends AbstractMediaDTO { - private int lengthInSeconds; + private Integer lengthInSeconds; private String thumbnailRef; /** for GWT */ @@ -16,11 +16,11 @@ public class VideoDTO extends AbstractMediaDTO { super(videoRef, mimeType, createdAtDate); } - public int getLengthInSeconds() { + public Integer getLengthInSeconds() { return lengthInSeconds; } - public void setLengthInSeconds(int lengthInSeconds) { + public void setLengthInSeconds(Integer lengthInSeconds) { this.lengthInSeconds = lengthInSeconds; } From 8c564fcc4cda8cb995f3416d5685f0c42c80b361 Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 5 Jun 2015 18:09:53 +0200 Subject: [PATCH 024/117] added 'onvaluechange' logic to URLFieldWithFileUpload to trigger validation in the dialog where such a composite is used --- .../gwt/ui/adminconsole/ImageDialog.java | 14 +++--- .../gwt/ui/adminconsole/VideoDialog.java | 13 +++--- .../adminconsole/URLFieldWithFileUpload.java | 43 ++++++++++++++++++- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index 5661d1f6068..28342490e5d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -57,19 +57,19 @@ public abstract class ImageDialog extends DataEntryDialog { this.stringMessages = stringMessages; this.creationDate = new Date(); getDialogBox().getWidget().setWidth("730px"); - final ValueChangeHandler> valueChangeHandler = new ValueChangeHandler>() { - @Override - public void onValueChange(ValueChangeEvent> event) { - validate(); - } - }; imageURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + imageURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + validate(); + } + }); + final List tagSuggestions = Arrays.asList(new String[] { "Stage", "Eventteaser", "Sponsor", "Logo" }); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ tagSuggestions, "Enter tags for the image", 50)); - tagsListEditor.addValueChangeHandler(valueChangeHandler); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index ae8a928cc73..1e9ea296723 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -62,12 +62,6 @@ public abstract class VideoDialog extends DataEntryDialog { this.stringMessages = stringMessages; this.creationDate = new Date(); getDialogBox().getWidget().setWidth("730px"); - final ValueChangeHandler> valueChangeHandler = new ValueChangeHandler>() { - @Override - public void onValueChange(ValueChangeEvent> event) { - validate(); - } - }; mimeTypeListBox = createListBox(false); mimeTypeListBox.addItem("Select a mime type"); @@ -78,12 +72,17 @@ public abstract class VideoDialog extends DataEntryDialog { mimeTypeListBox.addItem(MimeType.qt.name()); videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + validate(); + } + }); thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured" }); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ tagSuggestions, "Enter tags for the video", 50)); - tagsListEditor.addValueChangeHandler(valueChangeHandler); } @Override diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java index 193f89feeb2..bdcd673bb77 100755 --- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java +++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java @@ -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 { 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(); @@ -143,4 +149,39 @@ public class URLFieldWithFileUpload extends Composite { public void setFocus(boolean focused) { urlTextBox.setFocus(focused); } + + private HandlerRegistration addChangeHandler(ChangeHandler handler) { + return addDomHandler(handler, ChangeEvent.getType()); + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler 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); + } + } } From a19bbf1e64a8abc426169c1c9df71a9ba1179173 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 15:03:31 +0200 Subject: [PATCH 025/117] little UI improvements --- .../com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java | 4 ++-- .../com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index 28342490e5d..04861e14a6c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -45,7 +45,7 @@ public abstract class ImageDialog extends DataEntryDialog { String errorMessage = null; if(imageToValidate.getSourceRef() == null || imageToValidate.getSourceRef().isEmpty()) { - errorMessage = "You must provide a valid URL for the image"; + errorMessage = stringMessages.pleaseEnterNonEmptyUrl(); } return errorMessage; } @@ -66,7 +66,7 @@ public abstract class ImageDialog extends DataEntryDialog { } }); - final List tagSuggestions = Arrays.asList(new String[] { "Stage", "Eventteaser", "Sponsor", "Logo" }); + final List tagSuggestions = Arrays.asList(new String[] { "Stage", "Teaser", "Sponsor", "Logo" }); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ tagSuggestions, "Enter tags for the image", 50)); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index 1e9ea296723..caf6d7b76bf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -48,7 +48,7 @@ public abstract class VideoDialog extends DataEntryDialog { String errorMessage = null; if(videoToValidate.getSourceRef() == null || videoToValidate.getSourceRef().isEmpty()) { - errorMessage = "You must provide a valid URL for the video."; + errorMessage = stringMessages.pleaseEnterNonEmptyUrl(); } else if (videoToValidate.getMimeType() == null) { errorMessage = "You must select the mime type for the video."; } @@ -64,12 +64,13 @@ public abstract class VideoDialog extends DataEntryDialog { getDialogBox().getWidget().setWidth("730px"); mimeTypeListBox = createListBox(false); - mimeTypeListBox.addItem("Select a mime type"); + 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.setSelectedIndex(0); videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { @@ -79,7 +80,7 @@ public abstract class VideoDialog extends DataEntryDialog { } }); thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); - final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured" }); + final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured", "Locale_de, Locale_en" }); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ tagSuggestions, "Enter tags for the video", 50)); @@ -102,7 +103,7 @@ public abstract class VideoDialog extends DataEntryDialog { private MimeType getSelectedMimeType() { MimeType result = null; int selectedIndex = mimeTypeListBox.getSelectedIndex(); - if(selectedIndex > 0) { + if(selectedIndex >= 0) { result = MimeType.valueOf(mimeTypeListBox.getSelectedValue()); } return result; From c85430d8ade1816a866cda44b852169e96906fb7 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 16:17:05 +0200 Subject: [PATCH 026/117] added table columns for (migrated )images and videos in EventListComposite --- .../ui/adminconsole/EventListComposite.java | 37 +++++++++++++++---- .../sailing/gwt/ui/client/StringMessages.java | 1 + .../gwt/ui/client/StringMessages.properties | 1 + .../ui/client/StringMessages_cn.properties | 1 + .../ui/client/StringMessages_de.properties | 1 + .../ui/client/StringMessages_ru.properties | 1 + 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index ce9635be3c5..0d1518c644f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -283,7 +283,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le return builder.toSafeHtml(); } }; - +/* TextColumn imageURLsColumn = new TextColumn() { @Override public String getValue(EventDTO event) { @@ -319,6 +319,30 @@ public class EventListComposite extends Composite implements EventsRefresher, Le return result; } }; +*/ + TextColumn imagesColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + String result = ""; + int imageCount = Util.size(event.getImages()); + if(imageCount > 0) { + result = imageCount + " image(s)"; + } + return result; + } + }; + + TextColumn videosColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + String result = ""; + int videoCount = Util.size(event.getVideos()); + if(videoCount > 0) { + result = videoCount + " video(s)"; + } + return result; + } + }; SafeHtmlCell associatedRegattasCell = new SafeHtmlCell(); Column associatedRegattasColumn = new Column(associatedRegattasCell) { @@ -358,9 +382,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 +391,11 @@ 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(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()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 503696829dd..22aff1f6452 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -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(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 8fc95b51639..06c4a76bfe0 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -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 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties index 6a65e50fde4..6c5e89e1dee 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties @@ -1136,6 +1136,7 @@ windImport_Upload=Upload no=否 polarSheetSplitByWindGauges=Split Windsources image=Image +images=Images currentPass=Current pass beatAngle=迎风航行角度 ratioBetweenTimeSinceLastPositionFixAndAverageSamplingInterval=GPS Lag diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index f35de4ba917..0e86cbb09e0 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -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 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 83bc6022fd8..ec379f3eb10 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -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 From 03525a353c211a057d38501618e95c3502a941f7 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 16:18:44 +0200 Subject: [PATCH 027/117] removed unused code --- .../ui/adminconsole/EventListComposite.java | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index 0d1518c644f..edcba5bcfc1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -283,43 +283,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le return builder.toSafeHtml(); } }; -/* - TextColumn imageURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int imageCount = Util.size(event.getImageURLs()); - if(imageCount > 0) { - result = imageCount + " image(s)"; - } - return result; - } - }; - - TextColumn videoURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int videoCount = Util.size(event.getVideoURLs()); - if(videoCount > 0) { - result = videoCount + " video(s)"; - } - return result; - } - }; - - TextColumn sponsorImageURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int sponsorImageCount = Util.size(event.getSponsorImageURLs()); - if(sponsorImageCount > 0) { - result = sponsorImageCount + " sponsor image(s)"; - } - return result; - } - }; -*/ + TextColumn imagesColumn = new TextColumn() { @Override public String getValue(EventDTO event) { @@ -391,9 +355,6 @@ 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()); From 08de42813304f39344c8023db8fc8a87856053dd Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 16:29:49 +0200 Subject: [PATCH 028/117] added a backend migration function which takes all existing imageURL, sponsorImageURLs and videoURLs and migrates them to the new rich format --- .../impl/DomainObjectFactoryImpl.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index d99a07a25e0..087bfa2f380 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -975,8 +975,10 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); try { - for (DBObject o : eventCollection.find()) { - result.add(loadEvent(o)); + for (DBObject object : eventCollection.find()) { + Event event = loadEvent(object); + migrateImagesAndVideosOfEvent(event); + result.add(event); } } catch (Exception e) { logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load events."); @@ -2159,4 +2161,36 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } return result; } + + /** + * Migrates images and videos stored as pure URLs to the new richer format once + * @param event the event to migrate + */ + private void migrateImagesAndVideosOfEvent(Event event) { + int amountOfURLbasedImagesAndVideos = Util.size(event.getImageURLs()) + Util.size(event.getSponsorImageURLs()) + Util.size(event.getVideoURLs()); + int amountOfImagesAndVideos = Util.size(event.getImages()) + Util.size(event.getVideos()); + boolean migrationRequired = amountOfURLbasedImagesAndVideos > 0 && amountOfImagesAndVideos == 0; + if(migrationRequired) { + for(URL url: event.getImageURLs()) { + String urlAsString = url.toString(); + ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); + if(urlAsString.indexOf("stage") > 0) { + image.addTag("Stage"); + } else if(urlAsString.indexOf("eventteaser") > 0) { + image.addTag("Teaser"); + } + event.addImage(image); + } + for(URL url: event.getSponsorImageURLs()) { + ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); + image.addTag("Sponsor"); + event.addImage(image); + } + for(URL url: event.getVideoURLs()) { + VideoDescriptor video = new VideoDescriptorImpl(url, MimeType.unknown, MillisecondsTimePoint.now()); + event.addVideo(video); + } + new MongoObjectFactoryImpl(database).storeEvent(event); + } + } } From f36e050f854d29eb19c894ffd2d76dd13c69e51f Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 16:33:31 +0200 Subject: [PATCH 029/117] added videos to result of edited event --- .../java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 76a6325dd1b..a5f382be601 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -31,6 +31,7 @@ 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 { protected StringMessages stringMessages; @@ -200,6 +201,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap for(ImageDTO image: imagesListComposite.getAllImages()) { result.addImage(image); } + for(VideoDTO video: videosListComposite.getAllVideos()) { + result.addVideo(video); + } result.venue = new VenueDTO(venueEntryField.getText(), courseAreas); return result; } From d5385983472a62cc5c6ceb9e946de24a48adf641 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 16:47:42 +0200 Subject: [PATCH 030/117] fixed display of mime type in VideosListComposite --- .../ui/adminconsole/VideoCreateDialog.java | 2 ++ .../gwt/ui/adminconsole/VideoDialog.java | 10 +++++- .../gwt/ui/adminconsole/VideoEditDialog.java | 1 + .../ui/adminconsole/VideosListComposite.java | 34 ++++++++++++------- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java index 48743d9268f..ef66b5843d4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java @@ -4,6 +4,7 @@ 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 { @@ -19,5 +20,6 @@ public class VideoCreateDialog extends VideoDialog { copyrightTextBox.setVisibleLength(50); lengthIntegerBox = createIntegerBox(null, 10); tagsListEditor.setValue(Collections.emptyList()); + setSelectedMimeType(MimeType.unknown); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index caf6d7b76bf..a091018b7b8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -70,7 +70,6 @@ public abstract class VideoDialog extends DataEntryDialog { mimeTypeListBox.addItem(MimeType.ogg.name()); mimeTypeListBox.addItem(MimeType.ogv.name()); mimeTypeListBox.addItem(MimeType.qt.name()); - mimeTypeListBox.setSelectedIndex(0); videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { @@ -100,6 +99,15 @@ public abstract class VideoDialog extends DataEntryDialog { return result; } + protected void setSelectedMimeType(MimeType mimeType) { + for(int i = 0; i < mimeTypeListBox.getVisibleItemCount(); i++) { + if(mimeTypeListBox.getItemText(0).equals(mimeType.name())) { + mimeTypeListBox.setSelectedIndex(i); + break; + } + } + } + private MimeType getSelectedMimeType() { MimeType result = null; int selectedIndex = mimeTypeListBox.getSelectedIndex(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java index c528d410fa0..b8e63113d73 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java @@ -22,5 +22,6 @@ public class VideoEditDialog extends VideoDialog { List tags = new ArrayList(); tags.addAll(video.getTags()); tagsListEditor.setValue(tags); + setSelectedMimeType(video.getMimeType()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java index a2280a71863..b9ed5d13892 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java @@ -85,8 +85,8 @@ public class VideosListComposite extends Composite { videoSelectionModel = new SingleSelectionModel(); videoListDataProvider = new ListDataProvider(); - videoTable = createImagesTable(); - videoTable.ensureDebugId("ImagesCellTable"); + videoTable = createVideosTable(); + videoTable.ensureDebugId("VideosCellTable"); videoTable.setVisible(false); videoSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @@ -105,7 +105,7 @@ public class VideosListComposite extends Composite { initWidget(mainPanel); } - private CellTable createImagesTable() { + private CellTable createVideosTable() { CellTable table = new CellTable(/* pageSize */10000, tableRes); videoListDataProvider.addDataDisplay(table); table.setWidth("100%"); @@ -132,19 +132,26 @@ public class VideosListComposite extends Composite { TextColumn createdAtDateColumn = new TextColumn() { @Override - public String getValue(VideoDTO image) { - return DateAndTimeFormatterUtil.formatDateAndTime(image.getCreatedAtDate()); + public String getValue(VideoDTO video) { + return DateAndTimeFormatterUtil.formatDateAndTime(video.getCreatedAtDate()); + } + }; + + TextColumn mimeTypeColumn = new TextColumn() { + @Override + public String getValue(VideoDTO video) { + return video.getMimeType() != null ? video.getMimeType().name() : ""; } }; SafeHtmlCell tagsCell = new SafeHtmlCell(); Column tagsColumn = new Column(tagsCell) { @Override - public SafeHtml getValue(VideoDTO image) { + public SafeHtml getValue(VideoDTO video) { SafeHtmlBuilder builder = new SafeHtmlBuilder(); - int tagsCount = image.getTags().size(); + int tagsCount = video.getTags().size(); int i = 1; - for (String tag : image.getTags()) { + for (String tag : video.getTags()) { builder.appendEscaped(tag); if (i < tagsCount) { builder.appendHtmlConstant(", "); @@ -163,12 +170,12 @@ public class VideosListComposite extends Composite { new VideoConfigImagesBarCell(stringMessages)); videoActionColumn.setFieldUpdater(new FieldUpdater() { @Override - public void update(int index, VideoDTO image, String value) { + public void update(int index, VideoDTO video, String value) { if (ImageConfigImagesBarCell.ACTION_REMOVE.equals(value)) { - videoListDataProvider.getList().remove(image); + videoListDataProvider.getList().remove(video); updateTableVisisbilty(); } else if (ImageConfigImagesBarCell.ACTION_EDIT.equals(value)) { - openEditVideoDialog(image); + openEditVideoDialog(video); } } }); @@ -179,6 +186,7 @@ public class VideosListComposite extends Composite { table.addColumn(shortVideoNameColumn, "Short name"); table.addColumn(titleColumn, stringMessages.title()); table.addColumn(createdAtDateColumn, "Created At"); + table.addColumn(mimeTypeColumn, stringMessages.mimeType()); table.addColumn(tagsColumn, "Tags"); table.addColumn(videoActionColumn, stringMessages.actions()); table.addColumnSortHandler(getVideoTableColumnSortHandler(videoListDataProvider.getList(), titleColumn, createdAtDateColumn)); @@ -237,9 +245,9 @@ public class VideosListComposite extends Composite { } @Override - public void ok(VideoDTO updatedImage) { + public void ok(VideoDTO updatedVideo) { videoListDataProvider.getList().remove(selectedVideo); - videoListDataProvider.getList().add(updatedImage); + videoListDataProvider.getList().add(updatedVideo); updateTableVisisbilty(); } }); From b48fc46213bf51e2baaa2764969619de02042e44 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 6 Jun 2015 18:52:33 +0200 Subject: [PATCH 031/117] added russian and chinese locale tags to suggest list for tags in video editor --- .../java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index a091018b7b8..a15a4f6eae9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -79,7 +79,7 @@ public abstract class VideoDialog extends DataEntryDialog { } }); thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); - final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured", "Locale_de, Locale_en" }); + final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured", "Locale_de, Locale_en", "Locale_ru", "Locale_cn" }); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ tagSuggestions, "Enter tags for the video", 50)); From 49ab1a712ef0822e2b62d6778b7407ca5350941c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 8 Jun 2015 10:27:22 +0200 Subject: [PATCH 032/117] Adapted current version of the NewsBox partial --- .../event/overview/EventOverviewStage.ui.xml | 3 +- .../partials/updatesBox/UpdatesBoxItem.ui.xml | 29 ++++++++----------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml index 6d8b2c3fffd..1bc987b11e8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml @@ -9,8 +9,7 @@
    - - +
    diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml index cdf86405d56..2c2e02a9800 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.ui.xml @@ -3,23 +3,18 @@
  • - - -
    -
  • \ No newline at end of file From 2dbe93c7e12e6862f3d2eebf804ce3db1781f75b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 8 Jun 2015 10:31:03 +0200 Subject: [PATCH 033/117] Fixed compilation error after master merge --- .../ui/shared/dispatch/event/GetEventOverviewStageAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index c7ddcbfad29..de2c5d47694 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -143,7 +143,7 @@ public class GetEventOverviewStageAction implements Action Date: Mon, 8 Jun 2015 16:42:22 +0200 Subject: [PATCH 034/117] Added youtube and vimeo to the supported video types --- .../java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index a15a4f6eae9..63c19540248 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -70,6 +70,8 @@ public abstract class VideoDialog extends DataEntryDialog { 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()); videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { From f5a8bb46c4a480b4639dbf6e77b2c3b9326a153f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 8 Jun 2015 16:46:04 +0200 Subject: [PATCH 035/117] Added MediaConstants class to handle common media tag names --- .../gwt/ui/adminconsole/ImageDialog.java | 6 +++--- .../gwt/ui/adminconsole/VideoDialog.java | 6 +++--- .../gwt/ui/shared/media/MediaConstants.java | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index 04861e14a6c..c4c31ed8cc2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -1,7 +1,6 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; @@ -14,6 +13,7 @@ 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; @@ -66,10 +66,10 @@ public abstract class ImageDialog extends DataEntryDialog { } }); - final List tagSuggestions = Arrays.asList(new String[] { "Stage", "Teaser", "Sponsor", "Logo" }); + tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ - tagSuggestions, "Enter tags for the image", 50)); + MediaConstants.imageTagSuggestions, "Enter tags for the image", 50)); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index 63c19540248..a9fd5f654e9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -1,7 +1,6 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; @@ -15,6 +14,7 @@ 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.media.MimeType; import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload; import com.sap.sse.gwt.client.IconResources; @@ -81,10 +81,10 @@ public abstract class VideoDialog extends DataEntryDialog { } }); thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); - final List tagSuggestions = Arrays.asList(new String[] { "Highlight", "Featured", "Locale_de, Locale_en", "Locale_ru", "Locale_cn" }); + tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ - tagSuggestions, "Enter tags for the video", 50)); + MediaConstants.videoTagSuggestions, "Enter tags for the video", 50)); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java new file mode 100644 index 00000000000..c3180715bde --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -0,0 +1,21 @@ +package com.sap.sailing.gwt.ui.shared.media; + +import java.util.Arrays; +import java.util.List; + +public final class MediaConstants { + + public static final String STAGE = "Stage"; + public static final String TEASER = "Teaser"; + public static final String HIGHLIGHT = "Highlight"; + public static final String LIVESTREAM = "Livestream"; + public static final String FEATURED = "Featured"; + public static final String LOCALE_PREFIX = "Locale_"; + public static final String LOCALE_EN = LOCALE_PREFIX + "en"; + public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor", "Logo" }); + public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED, LOCALE_PREFIX + "de", LOCALE_EN, LOCALE_PREFIX + "ru", LOCALE_PREFIX + "cn" }); + + private MediaConstants() { + } + +} From 44bebdc9206bc2e66f39f1f1e0f5e8757bf36c5b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 8 Jun 2015 16:47:01 +0200 Subject: [PATCH 036/117] Implemented locale dependent livestream and stage video based on the new media model --- .../sailing/gwt/server/HomeServiceUtil.java | 92 +++++++++++++++++++ .../event/GetEventOverviewStageAction.java | 27 +++--- 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index b5c9696e94b..5c9207d6c37 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.server; import java.net.URL; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -9,6 +10,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Random; +import java.util.Set; import java.util.concurrent.ExecutionException; import com.sap.sailing.domain.base.Competitor; @@ -25,8 +27,11 @@ 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.MimeType; +import com.sap.sse.common.media.VideoDescriptor; public final class HomeServiceUtil { private HomeServiceUtil() { @@ -413,4 +418,91 @@ public final class HomeServiceUtil { int size = Util.size(urls); return Util.get(urls, new Random(size).nextInt(size)); } + + public static VideoDescriptor getStageVideo(Event event, String localeName, Set acceptedTypes, Collection rankedTags, boolean acceptOtherTags) { + VideoDescriptor bestMatch = null; + + for (VideoDescriptor videoCandidate : event.getVideos()) { + if(!acceptedTypes.contains(videoCandidate.getMimeType())) { + continue; + } + + if(!acceptOtherTags && !hasOneTag(videoCandidate, rankedTags)) { + continue; + } + + LocaleMatch localeMatch = matchLocale(videoCandidate, localeName); + 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, localeName))) { + bestMatch = videoCandidate; + continue; + } + } + return bestMatch; + } + + private static int compareByTag(VideoDescriptor videoCandidate, VideoDescriptor bestMatch, + Collection rankedTags) { + for(String rankedTag : rankedTags) { + boolean hasTag = Util.contains(videoCandidate.getTags(), rankedTag); + boolean hasTagBestMatch = Util.contains(bestMatch.getTags(), rankedTag); + if(hasTag != hasTagBestMatch) { + return hasTag ? 1 : -1; + } + } + return 0; + } + + private static boolean isBetter(VideoDescriptor candidate, VideoDescriptor reference, String localeName) { + LocaleMatch localeMatch = matchLocale(candidate, localeName); + LocaleMatch localeMatchRef = matchLocale(reference, localeName); + if(localeMatch != localeMatchRef) { + return localeMatch.compareTo(localeMatchRef) < 0 ? true : false; + } + + // TODO filter by length + + return candidate.getCreatedAtDate().compareTo(reference.getCreatedAtDate()) > 0; + } + + private static boolean hasOneTag(VideoDescriptor videoCandidate, Collection 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, String localeName) { + boolean hasLocaleTag = false; + boolean hasEn = false; + for(String tag : videoCandidate.getTags()) { + if(tag.equals(MediaConstants.LOCALE_PREFIX + localeName)) { + return LocaleMatch.PERFECT; + } + hasLocaleTag |= tag.startsWith(MediaConstants.LOCALE_PREFIX); + hasEn |= tag.equals(MediaConstants.LOCALE_EN); + } + if(!hasLocaleTag) { + return LocaleMatch.NOT_TAGGED; + } + if(hasEn) { + return LocaleMatch.EN_FALLBACK; + } + return LocaleMatch.NO_MATCH; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index d1009001f1d..f9cb6174a41 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -1,6 +1,9 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; -import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; @@ -10,12 +13,16 @@ 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.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MimeType; +import com.sap.sse.common.media.VideoDescriptor; public class GetEventOverviewStageAction implements Action> { + private static final Set mimeTypes = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); + private static final Collection rankedTags = Arrays.asList(MediaConstants.LIVESTREAM, MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); + private static final Collection rankedTagsFinished = Arrays.asList(MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); + private UUID eventId; public GetEventOverviewStageAction() { @@ -46,18 +53,14 @@ public class GetEventOverviewStageAction implements Action 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 tags = state == EventState.FINISHED ? rankedTagsFinished : rankedTags; + VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocaleName(), mimeTypes, 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) { From f7a9dce04fe40eaac3735bb0f311df1116cb440b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 8 Jun 2015 17:38:41 +0200 Subject: [PATCH 037/117] Fixed preselection of mime type for already saved videos --- .../java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index a9fd5f654e9..a250cb6f3e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -102,8 +102,8 @@ public abstract class VideoDialog extends DataEntryDialog { } protected void setSelectedMimeType(MimeType mimeType) { - for(int i = 0; i < mimeTypeListBox.getVisibleItemCount(); i++) { - if(mimeTypeListBox.getItemText(0).equals(mimeType.name())) { + for(int i = 0; i < mimeTypeListBox.getItemCount(); i++) { + if(mimeTypeListBox.getItemText(i).equals(mimeType.name())) { mimeTypeListBox.setSelectedIndex(i); break; } From 9ed8dc8395bf0feb3b9ef57fa42cf6309fceb12e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 08:47:55 +0200 Subject: [PATCH 038/117] Stage image is calculated using the new media model --- .../sailing/gwt/server/HomeServiceUtil.java | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 5c9207d6c37..65bc9c0b168 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -3,15 +3,12 @@ package com.sap.sailing.gwt.server; import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.Set; -import java.util.concurrent.ExecutionException; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; @@ -29,7 +26,9 @@ 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.ImageDescriptor; import com.sap.sse.common.media.ImageSize; +import com.sap.sse.common.media.MediaDescriptor; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; @@ -228,11 +227,11 @@ public final class HomeServiceUtil { } /** - * 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: *
      - *
    1. If one or more image URLs has "stage" (ignoring case) in its name, only they are considered candidates.
    2. - *
    3. If no image URL has "stage" (ignoring case) in its name, all images from {@link #imageURLs} are considered + *
    4. If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.
    5. + *
    6. If no image has {@link MediaConstants#STAGE} tag, all images are considered * candidates.
    7. *
    8. From all candidates, the one with the biggest known size (determined by the product of width and height) is * chosen.
    9. @@ -240,69 +239,62 @@ public final class HomeServiceUtil { *
    */ 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: *
      - *
    1. If one or more image URLs has "stage" (ignoring case) in its name, only they are considered candidates.
    2. - *
    3. If no image URL has "stage" (ignoring case) in its name, all images from {@link #imageURLs} are considered + *
    4. If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.
    5. + *
    6. If no image has {@link MediaConstants#STAGE} tag, all images are considered * candidates.
    7. *
    8. From all candidates, the one with the biggest known size (determined by the product of width and height) is * chosen.
    9. *
    10. If the size isn't known for any candidate, the first candidate in {@link #imageURLs} is picked.
    11. *
    */ - public static URL getStageImageURL(final EventBase event) { - final URL result; - if (Util.isEmpty(event.getImageURLs())) { - result = null; - } else { - Comparator stageImageComparator = new Comparator() { - @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 sortedImageURLs = new ArrayList<>(); - for (URL url : event.getImageURLs()) { - sortedImageURLs.add(url); + public static ImageDescriptor getStageImage(final EventBase event) { + ImageDescriptor bestMatch = null; + + for(ImageDescriptor candidate : event.getImages()) { + if(bestMatch == null || isBetterStageImage(candidate, bestMatch)) { + bestMatch = candidate; + continue; } - Collections.sort(sortedImageURLs, stageImageComparator); - result = sortedImageURLs.get(sortedImageURLs.size() - 1); } - return result; + + return bestMatch; } + private static boolean isBetterStageImage(ImageDescriptor candidate, ImageDescriptor reference) { + boolean stage = hasTag(candidate, MediaConstants.STAGE); + boolean stageRef = hasTag(reference, MediaConstants.STAGE); + if(stage != stageRef) { + return stage; + } + boolean teaser = hasTag(candidate, MediaConstants.TEASER); + boolean teaserRef = hasTag(reference, MediaConstants.TEASER); + if(teaser != teaserRef) { + return !teaser; + } + + int size = imageSize(candidate); + int sizeRef = imageSize(reference); + if(size != sizeRef) { + return size > sizeRef; + } + return candidate.getCreatedAtDate().compareTo(reference.getCreatedAtDate()) > 0; + } + + private static int imageSize(ImageDescriptor candidate) { + int width = candidate.getWidthInPx() == null ? 0 : candidate.getWidthInPx(); + int height = candidate.getHeightInPx() == null ? 0 : candidate.getHeightInPx(); + // TODO fallback to event.getImageSize() if size is 0/null? + return width * height; + } + public static List getPhotoGalleryImageURLsAsString(EventBase event) { List urls = getPhotoGalleryImageURLs(event); List result = new ArrayList(urls.size()); @@ -313,7 +305,8 @@ public final class HomeServiceUtil { } public static List getPhotoGalleryImageURLs(EventBase event) { - URL stageImageURL = getStageImageURL(event); // if set, exclude stage image from photo gallery + ImageDescriptor stageImage = getStageImage(event); // if set, exclude stage image from photo gallery + URL stageImageURL = stageImage == null ? null : stageImage.getURL(); List result = new ArrayList<>(); Iterable imageURLs = event.getImageURLs(); @@ -394,8 +387,12 @@ 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, MediaConstants.TEASER)) { + return true; + } + } + return false; } public static boolean hasVideos(Event event) { @@ -453,8 +450,8 @@ public final class HomeServiceUtil { private static int compareByTag(VideoDescriptor videoCandidate, VideoDescriptor bestMatch, Collection rankedTags) { for(String rankedTag : rankedTags) { - boolean hasTag = Util.contains(videoCandidate.getTags(), rankedTag); - boolean hasTagBestMatch = Util.contains(bestMatch.getTags(), rankedTag); + boolean hasTag = hasTag(videoCandidate, rankedTag); + boolean hasTagBestMatch = hasTag(bestMatch, rankedTag); if(hasTag != hasTagBestMatch) { return hasTag ? 1 : -1; } @@ -473,8 +470,12 @@ public final class HomeServiceUtil { 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(VideoDescriptor videoCandidate, Collection acceptedTags) { + private static boolean hasOneTag(MediaDescriptor videoCandidate, Collection acceptedTags) { for(String tag : videoCandidate.getTags()) { if(acceptedTags.contains(tag)) { return true; From dc87e7bbf357d271d2c108160dfcaa17c8c02902 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 12:39:08 +0200 Subject: [PATCH 039/117] Using new media model --- .../sailing/gwt/server/HomeServiceImpl.java | 70 +++++-------- .../sailing/gwt/server/HomeServiceUtil.java | 99 ++++++++----------- .../gwt/client/media/AbstractMediaDTO.java | 6 +- 3 files changed, 70 insertions(+), 105 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 7ad06be51e6..6bc23c0a883 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -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; @@ -43,7 +40,6 @@ 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.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 +53,10 @@ 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.ImageDescriptor; import com.sap.sse.common.media.MediaType; import com.sap.sse.common.media.MimeType; +import com.sap.sse.common.media.VideoDescriptor; import com.sap.sse.util.ServiceTrackerFactory; /** @@ -93,7 +90,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 +179,14 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home EventReferenceDTO eventRef = new EventReferenceDTO(holder.event); - Iterable videosOfEvent = holder.event.getVideoURLs(); + Iterable 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()); + MimeType type = youTubeRandomUrl.getMimeType(); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.toString(), type, // - holder.event.getEndDate().asDate() // FIXME: using event enddate for now + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.getURL().toString(), type, // + youTubeRandomUrl.getCreatedAtDate().asDate() ); candidate.setTitle(holder.event.getName()); result.addVideo(candidate); @@ -217,25 +213,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) { - SailingImageDTO sailingImageDTO = new SailingImageDTO(eventRef, url.toString(), null); - if (imageSize != null) { - sailingImageDTO.setSizeInPx(imageSize.getWidth(), imageSize.getHeight()); - photoGalleryUrls.add(sailingImageDTO); - } - } - } catch (Exception e) { + for (ImageDescriptor url : HomeServiceUtil.getSailingLovesPhotographyImages(event)) { + if(url.getWidthInPx() != null && url.getHeightInPx() != null) { + 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()); + for (VideoDescriptor videoUrl : event.getVideos()) { + MimeType type =videoUrl.getMimeType(); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.toString(), type, // - holder.event.getEndDate().asDate() // FIXME: using event enddate for now + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.getURL().toString(), type, // + videoUrl.getCreatedAtDate().asDate() ); candidate.setTitle(holder.event.getName()); videoCandidates.add(candidate); @@ -428,27 +417,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); - } - // FIXME: using the event end date for 'createdAtDate' for now, we need a better solution for migration - SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), event.getEndDate().asDate()); - if (imageSize != null) { - entry.setSizeInPx(imageSize.getWidth(), imageSize.getHeight()); - } - 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()); + for(VideoDescriptor url : event.getVideos()) { + MimeType type = url.getMimeType(); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.toString(), type, null); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.getURL().toString(), type, null); media.addVideo(candidate); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 65bc9c0b168..8593181f965 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -1,6 +1,5 @@ package com.sap.sailing.gwt.server; -import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -27,7 +26,6 @@ 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.ImageDescriptor; -import com.sap.sse.common.media.ImageSize; import com.sap.sse.common.media.MediaDescriptor; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; @@ -37,12 +35,10 @@ public final class 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) { @@ -104,47 +100,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, MediaConstants.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; } @@ -179,13 +171,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, MediaConstants.TEASER)) { return imageUrl; } } @@ -193,16 +185,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()) { @@ -218,10 +205,10 @@ public final class HomeServiceUtil { } if (!bestFit.isNull()) { - return bestFit.url; + return bestFit.image; } if (!actualWorstcase.isNull()) { - return actualWorstcase.url; + return actualWorstcase.image; } return null; } @@ -296,44 +283,38 @@ public final class HomeServiceUtil { } public static List getPhotoGalleryImageURLsAsString(EventBase event) { - List urls = getPhotoGalleryImageURLs(event); + List urls = getPhotoGalleryImages(event); List result = new ArrayList(urls.size()); - for (URL url : urls) { - result.add(url.toString()); + for (ImageDescriptor url : urls) { + result.add(url.getURL().toString()); } return result; } - public static List getPhotoGalleryImageURLs(EventBase event) { + public static List getPhotoGalleryImages(EventBase event) { ImageDescriptor stageImage = getStageImage(event); // if set, exclude stage image from photo gallery - URL stageImageURL = stageImage == null ? null : stageImage.getURL(); - List result = new ArrayList<>(); - Iterable imageURLs = event.getImageURLs(); + List result = new ArrayList<>(); + Iterable imageURLs = event.getImages(); boolean first = true; - for (Iterator iter = imageURLs.iterator(); iter.hasNext(); ) { - URL imageUrl = iter.next(); - if(imageUrl.toString().toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) { + for (Iterator iter = imageURLs.iterator(); iter.hasNext(); ) { + ImageDescriptor image = iter.next(); + if(hasTag(image, MediaConstants.TEASER)) { continue; } - if ((first && !iter.hasNext()) || !Util.equalsWithNull(imageUrl, stageImageURL)) { - result.add(imageUrl); + if ((first && !iter.hasNext()) || !Util.equalsWithNull(image, stageImage)) { + result.add(image); } first = false; } return result; } - public static List getSailingLovesPhotographyImages(EventBase event) { - final List 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 getSailingLovesPhotographyImages(EventBase event) { + final List acceptedImages = new LinkedList<>(); + for (ImageDescriptor candidateImageUrl : event.getImages()) { + if (candidateImageUrl.getWidthInPx() != null && candidateImageUrl.getHeightInPx() != null && candidateImageUrl.getHeightInPx() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) { + acceptedImages.add(candidateImageUrl); } } return acceptedImages; @@ -396,7 +377,7 @@ public final class HomeServiceUtil { } public static boolean hasVideos(Event event) { - return !Util.isEmpty(event.getVideoURLs()); + return !Util.isEmpty(event.getVideos()); } public static boolean isPartOfEvent(Event event, Regatta regattaEntity) { @@ -408,7 +389,7 @@ public final class HomeServiceUtil { return false; } - public static URL getRandomURL(Iterable urls) { + public static VideoDescriptor getRandomVideo(Iterable urls) { if(Util.isEmpty(urls)) { return null; } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java index 8b5f0bc37d8..8111fd3fc3b 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -76,8 +76,10 @@ public abstract class AbstractMediaDTO implements IsSerializable { return tags; } - public void setTags(List tags) { - this.tags = tags; + public void setTags(Iterable tags) { + for(String tag: tags) { + this.tags.add(tag); + } } public String getSourceRef() { From 775a65b8b38def9f193735a0a4574c0fe37284f3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 13:08:43 +0200 Subject: [PATCH 040/117] Improved migration code to set image sizes if available --- .../impl/DomainObjectFactoryImpl.java | 4403 +++++++++-------- .../com/sap/sailing/domain/base/Event.java | 133 +- .../gwt/ui/shared/media/MediaUtils.java | 52 - .../sap/sse/common/media/ImageDescriptor.java | 4 +- .../sse/common/media/ImageDescriptorImpl.java | 7 +- .../com/sap/sse/common/media/MediaUtils.java | 99 + 6 files changed, 2382 insertions(+), 2316 deletions(-) mode change 100755 => 100644 java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/MediaUtils.java diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java old mode 100755 new mode 100644 index 087bfa2f380..8f344ffa1b6 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -1,2196 +1,2207 @@ -package com.sap.sailing.domain.persistence.impl; - -import java.io.Serializable; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bson.types.ObjectId; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import com.mongodb.BasicDBList; -import com.mongodb.BasicDBObject; -import com.mongodb.BasicDBObjectBuilder; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.DBObject; -import com.mongodb.MongoException; -import com.mongodb.WriteResult; -import com.mongodb.util.JSON; -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; -import com.sap.sailing.domain.abstractlog.race.CompetitorResults; -import com.sap.sailing.domain.abstractlog.race.FixedMarkPassingEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLog; -import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogEventRestoreFactory; -import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent; -import com.sap.sailing.domain.abstractlog.race.SuppressedMarkPassingsEvent; -import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; -import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl; -import com.sap.sailing.domain.abstractlog.race.scoring.AdditionalScoringInformationType; -import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent; -import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; -import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRevokeEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnTimeFactorEventImpl; -import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl; -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.ControlPoint; -import com.sap.sailing.domain.base.ControlPointWithTwoMarks; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.CourseBase; -import com.sap.sailing.domain.base.DomainFactory; -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.RaceDefinition; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.base.RegattaRegistry; -import com.sap.sailing.domain.base.RemoteSailingServerReference; -import com.sap.sailing.domain.base.Series; -import com.sap.sailing.domain.base.Venue; -import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.base.configuration.DeviceConfiguration; -import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationImpl; -import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; -import com.sap.sailing.domain.base.impl.CourseDataImpl; -import com.sap.sailing.domain.base.impl.EventImpl; -import com.sap.sailing.domain.base.impl.FleetImpl; -import com.sap.sailing.domain.base.impl.RegattaImpl; -import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; -import com.sap.sailing.domain.base.impl.SeriesImpl; -import com.sap.sailing.domain.base.impl.VenueImpl; -import com.sap.sailing.domain.base.impl.WaypointImpl; -import com.sap.sailing.domain.common.MarkType; -import com.sap.sailing.domain.common.MaxPointsReason; -import com.sap.sailing.domain.common.PassingInstruction; -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.RaceIdentifier; -import com.sap.sailing.domain.common.RankingMetrics; -import com.sap.sailing.domain.common.RegattaName; -import com.sap.sailing.domain.common.RegattaNameAndRaceName; -import com.sap.sailing.domain.common.ScoringSchemeType; -import com.sap.sailing.domain.common.SpeedWithBearing; -import com.sap.sailing.domain.common.Wind; -import com.sap.sailing.domain.common.WindSource; -import com.sap.sailing.domain.common.WindSourceType; -import com.sap.sailing.domain.common.configuration.DeviceConfigurationMatcherType; -import com.sap.sailing.domain.common.impl.DegreeBearingImpl; -import com.sap.sailing.domain.common.impl.DegreePosition; -import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; -import com.sap.sailing.domain.common.impl.WindImpl; -import com.sap.sailing.domain.common.impl.WindSourceImpl; -import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID; -import com.sap.sailing.domain.common.racelog.Flags; -import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; -import com.sap.sailing.domain.common.racelog.RacingProcedureType; -import com.sap.sailing.domain.common.racelog.tracking.TransformationException; -import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections; -import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections.LeaderboardCorrectionsResolvedListener; -import com.sap.sailing.domain.leaderboard.EventResolver; -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; -import com.sap.sailing.domain.leaderboard.LeaderboardRegistry; -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.impl.DelayedLeaderboardCorrectionsImpl; -import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; -import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; -import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; -import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; -import com.sap.sailing.domain.persistence.DomainObjectFactory; -import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory; -import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory; -import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; -import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; -import com.sap.sailing.domain.racelog.RaceLogIdentifier; -import com.sap.sailing.domain.racelog.RaceLogStore; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler; -import com.sap.sailing.domain.ranking.OneDesignRankingMetric; -import com.sap.sailing.domain.ranking.RankingMetricConstructor; -import com.sap.sailing.domain.ranking.RankingMetricsFactory; -import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; -import com.sap.sailing.domain.regattalog.RegattaLogStore; -import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; -import com.sap.sailing.domain.tracking.WindTrack; -import com.sap.sailing.domain.tracking.impl.WindTrackImpl; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.CompetitorJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.DeviceConfigurationJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.deserialization.impl.RegattaConfigurationJsonDeserializer; -import com.sap.sse.common.Color; -import com.sap.sse.common.Duration; -import com.sap.sse.common.NoCorrespondingServiceRegisteredException; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.TimeRange; -import com.sap.sse.common.TypeBasedServiceFinder; -import com.sap.sse.common.TypeBasedServiceFinderFactory; -import com.sap.sse.common.Util; -import com.sap.sse.common.Util.Triple; -import com.sap.sse.common.impl.MillisecondsDurationImpl; -import com.sap.sse.common.impl.MillisecondsTimePoint; -import com.sap.sse.common.impl.RGBColor; -import com.sap.sse.common.impl.TimeRangeImpl; -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 DomainObjectFactoryImpl implements DomainObjectFactory { - private static final Logger logger = Logger.getLogger(DomainObjectFactoryImpl.class.getName()); - private final CompetitorJsonDeserializer competitorDeserializer; - - private final DB database; - - private RaceLogEventRestoreFactory raceLogEventFactory; - private final DomainFactory baseDomainFactory; - private final TypeBasedServiceFinder deviceIdentifierServiceFinder; - private final TypeBasedServiceFinderFactory serviceFinderFactory; - - /** - * Uses null as the {@link TypeBasedServiceFinder}, meaning that no {@link DeviceIdentifier}s can be loaded - * using this instance of a {@link DomainObjectFactory}. - */ - public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory) { - this(db, baseDomainFactory, /* deviceTypeServiceFinder */ null); - } - - public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory, TypeBasedServiceFinderFactory serviceFinderFactory) { - super(); - this.serviceFinderFactory = serviceFinderFactory; - if (serviceFinderFactory != null) { - this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); - this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); - } else { - this.deviceIdentifierServiceFinder = null; - } - this.baseDomainFactory = baseDomainFactory; - this.competitorDeserializer = CompetitorJsonDeserializer.create(baseDomainFactory); - this.database = db; - this.raceLogEventFactory = RaceLogEventRestoreFactory.INSTANCE; - } - - @Override - public DomainFactory getBaseDomainFactory() { - return baseDomainFactory; - } - - public Wind loadWind(DBObject object) { - return new WindImpl(loadPosition(object), loadTimePoint(object), loadSpeedWithBearing(object)); - } - - public Position loadPosition(DBObject object) { - Number latNumber = (Number) object.get(FieldNames.LAT_DEG.name()); - Double lat = latNumber == null ? null : latNumber.doubleValue(); - Number lngNumber = (Number) object.get(FieldNames.LNG_DEG.name()); - Double lng = lngNumber == null ? null : lngNumber.doubleValue(); - if (lat != null && lng != null) { - return new DegreePosition(lat, lng); - } else { - return null; - } - } - - public static TimePoint loadTimePoint(DBObject object, String fieldName) { - TimePoint result = null; - Number timePointAsNumber = (Number) object.get(fieldName); - if (timePointAsNumber != null) { - result = new MillisecondsTimePoint(timePointAsNumber.longValue()); - } - return result; - } - - public static TimePoint loadTimePoint(DBObject object, FieldNames field) { - return loadTimePoint(object, field.name()); - } - - public static TimeRange loadTimeRange(DBObject object, FieldNames field) { - DBObject timeRangeObj = (DBObject) object.get(field.name()); - if (timeRangeObj == null) { - return null; - } - TimePoint from = loadTimePoint(timeRangeObj, FieldNames.FROM_MILLIS); - TimePoint to = loadTimePoint(timeRangeObj, FieldNames.TO_MILLIS); - return new TimeRangeImpl(from, to); - } - /** - * Loads a {@link TimePoint} on the given object at {@link FieldNames#TIME_AS_MILLIS}. - */ - public TimePoint loadTimePoint(DBObject object) { - return loadTimePoint(object, FieldNames.TIME_AS_MILLIS); - } - - public SpeedWithBearing loadSpeedWithBearing(DBObject object) { - return new KnotSpeedWithBearingImpl(((Number) object.get(FieldNames.KNOT_SPEED.name())).doubleValue(), - new DegreeBearingImpl(((Number) object.get(FieldNames.DEGREE_BEARING.name())).doubleValue())); - } - - @Override - public RaceIdentifier loadRaceIdentifier(DBObject dbObject) { - RaceIdentifier result = null; - String regattaName = (String) dbObject.get(FieldNames.EVENT_NAME.name()); - String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name()); - if (regattaName != null && raceName != null) { - result = new RegattaNameAndRaceName(regattaName, raceName); - } - return result; - } - - private void ensureIndicesOnWindTracks(DBCollection windTracks) { - windTracks.createIndex(new BasicDBObject(FieldNames.RACE_ID.name(), 1)); // for new programmatic access - windTracks.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); // for export or human look-up - // for legacy access to not yet migrated fixes - windTracks.createIndex(new BasicDBObjectBuilder().add(FieldNames.EVENT_NAME.name(), 1) - .add(FieldNames.RACE_NAME.name(), 1).get()); - // Unique index - try { - windTracks.createIndex( - new BasicDBObjectBuilder().add(FieldNames.RACE_ID.name(), 1) - .add(FieldNames.WIND_SOURCE_NAME.name(), 1).add(FieldNames.WIND_SOURCE_ID.name(), 1) - .add(FieldNames.WIND.name() + "." + FieldNames.TIME_AS_MILLIS.name(), 1).get(), - new BasicDBObjectBuilder().add("unique", true).add("dropDups", true).get()); - } catch (MongoException exception) { - - if (exception.getCode() == 10092) { - logger.warning(String.format( - "Setting the unique index on the %s collection failed because you have too many duplicates. " - + "This leads to the mongo error code %s and the following message: %s \nTo fix this follow " - + "the steps provided on the wiki page: http://wiki.sapsailing.com/wiki/cook-book#Remove-" - + "duplicates-from-WIND_TRACK-collection", CollectionNames.WIND_TRACKS.name(), - exception.getCode(), exception.getMessage())); - } else { - logger.severe(String.format( - "Setting the unique index on the %s collection failed with error code %s and message: %s", - CollectionNames.WIND_TRACKS.name(), exception.getCode(), exception.getMessage())); - } - } - } - - @Override - public Leaderboard loadLeaderboard(String name, RegattaRegistry regattaRegistry) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - Leaderboard result = null; - try { - BasicDBObject query = new BasicDBObject(); - query.put(FieldNames.LEADERBOARD_NAME.name(), name); - for (DBObject o : leaderboardCollection.find(query)) { - result = loadLeaderboard(o, regattaRegistry, /* leaderboardRegistry */ null, /* groupForMetaLeaderboard */ null); - } - } catch (Exception e) { - // something went wrong during DB access; report, then use empty new wind track - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard "+name+"."); - logger.log(Level.SEVERE, "loadLeaderboard", e); - } - return result; - } - - @Override - public Iterable getAllLeaderboards(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - Set result = new HashSet(); - try { - for (DBObject o : leaderboardCollection.find()) { - final Leaderboard loadedLeaderboard = loadLeaderboard(o, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ null); - if (loadedLeaderboard != null) { - result.add(loadedLeaderboard); - } - } - } catch (Exception e) { - // something went wrong during DB access; report, then use empty new wind track - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboards."); - logger.log(Level.SEVERE, "getAllLeaderboards", e); - } - return result; - } - - /** - * If the DBObject has a field {@link FieldNames#REGATTA_NAME} then the object represents a - * {@link RegattaLeaderboard}. Otherwise, a {@link FlexibleLeaderboard} will be loaded. - * - * @param leaderboardRegistry - * if not null, then before creating and loading the leaderboard it is looked up in this - * registry and only loaded if not found there. If leaderboardRegistry is null, - * the leaderboard is loaded in any case. If the leaderboard is loaded and - * leaderboardRegistry is not null, the leaderboard loaded is - * {@link LeaderboardRegistry#addLeaderboard(Leaderboard) added to the registry}. - * @param groupForMetaLeaderboard - * if not null, a {@link LeaderboardGroupMetaLeaderboard} instance is created and set as the - * group's {@link LeaderboardGroup#setOverallLeaderboard(Leaderboard) overall leaderboard} - * - * @return null in case the leaderboard couldn't be loaded, e.g., because the regatta referenced by a - * {@link RegattaLeaderboard} cannot be found; the leaderboard loaded or found in - * leaderboardRegistry, otherwise - */ - private Leaderboard loadLeaderboard(DBObject dbLeaderboard, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry, - LeaderboardGroup groupForMetaLeaderboard) { - Leaderboard result = null; - String leaderboardName = (String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name()); - if (leaderboardRegistry != null) { - result = leaderboardRegistry.getLeaderboardByName(leaderboardName); - } - if (result == null) { - ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbLeaderboard, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS); - String regattaName = (String) dbLeaderboard.get(FieldNames.REGATTA_NAME.name()); - if (groupForMetaLeaderboard != null) { - result = new LeaderboardGroupMetaLeaderboard(groupForMetaLeaderboard, - loadScoringScheme(dbLeaderboard), resultDiscardingRule); - groupForMetaLeaderboard.setOverallLeaderboard(result); - } else if (regattaName == null) { - result = loadFlexibleLeaderboard(dbLeaderboard, resultDiscardingRule); - } else { - result = loadRegattaLeaderboard(leaderboardName, regattaName, dbLeaderboard, resultDiscardingRule, regattaRegistry); - } - if (result != null) { - final Leaderboard finalResult = result; - finalResult.setDisplayName((String) dbLeaderboard.get(FieldNames.LEADERBOARD_DISPLAY_NAME.name())); - - DelayedLeaderboardCorrections loadedLeaderboardCorrections = new DelayedLeaderboardCorrectionsImpl(result, baseDomainFactory); - final boolean[] needsMigration = new boolean[1]; - loadedLeaderboardCorrections.addLeaderboardCorrectionsResolvedListener(new LeaderboardCorrectionsResolvedListener() { - @Override - public void correctionsResolved(DelayedLeaderboardCorrections delayedLeaderboardCorrections) { - if (needsMigration[0]) { - new MongoObjectFactoryImpl(database).storeLeaderboard(finalResult); - } - } - }); - needsMigration[0] = loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections, result.getScoreCorrection()) || needsMigration[0]; - needsMigration[0] = loadSuppressedCompetitors(dbLeaderboard, loadedLeaderboardCorrections) || needsMigration[0]; - loadColumnFactors(dbLeaderboard, result); - // add the leaderboard to the registry - if (leaderboardRegistry != null) { - leaderboardRegistry.addLeaderboard(result); - logger.info("loaded leaderboard "+result.getName()+" into "+leaderboardRegistry); - } - } - } - return result; - } - - private void loadColumnFactors(DBObject dbLeaderboard, Leaderboard result) { - DBObject dbColumnFactors = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMN_FACTORS.name()); - if (dbColumnFactors != null) { - for (String encodedRaceColumnName : dbColumnFactors.keySet()) { - double factor = ((Number) dbColumnFactors.get(encodedRaceColumnName)).doubleValue(); - String raceColumnName = MongoUtils.unescapeDollarAndDot(encodedRaceColumnName); - final RaceColumn raceColumn = result.getRaceColumnByName(raceColumnName); - if (raceColumn != null) { - raceColumn.setFactor(factor); - } else { - logger.warning("Expected to find race column named "+raceColumnName+" in leaderboard "+result.getName()+ - " to apply column factor "+factor+", but the race column wasn't found. Ignoring factor."); - } - } - } - } - - private boolean loadSuppressedCompetitors(DBObject dbLeaderboard, - DelayedLeaderboardCorrections loadedLeaderboardCorrections) { - final boolean needsMigration; - BasicDBList dbSuppressedCompetitorNames = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITORS.name()); - if (dbSuppressedCompetitorNames != null) { - needsMigration = true; - for (Object escapedCompetitorName : dbSuppressedCompetitorNames) { - loadedLeaderboardCorrections.suppressCompetitorByName(MongoUtils.unescapeDollarAndDot((String) escapedCompetitorName)); - } - } else { - needsMigration = false; - } - BasicDBList dbSuppressedCompetitorIDs = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name()); - if (dbSuppressedCompetitorIDs != null) { - for (Object competitorId : dbSuppressedCompetitorIDs) { - loadedLeaderboardCorrections.suppressCompetitorById((Serializable) competitorId); - } - } - return needsMigration; - } - - /** - * @param dbObject expects to find a field identified by field which holds a {@link BasicDBList} - */ - private ThresholdBasedResultDiscardingRule loadResultDiscardingRule(DBObject dbObject, FieldNames field) { - BasicDBList dbDiscardIndexResultsStartingWithHowManyRaces = (BasicDBList) dbObject.get(field.name()); - final ThresholdBasedResultDiscardingRule result; - if (dbDiscardIndexResultsStartingWithHowManyRaces == null) { - result = null; - } else { - int[] discardIndexResultsStartingWithHowManyRaces = new int[dbDiscardIndexResultsStartingWithHowManyRaces - .size()]; - int i = 0; - for (Object discardingThresholdAsObject : dbDiscardIndexResultsStartingWithHowManyRaces) { - discardIndexResultsStartingWithHowManyRaces[i++] = (Integer) discardingThresholdAsObject; - } - result = new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces); - } - return result; - } - - /** - * @return null if the regatta cannot be resolved; otherwise the leaderboard for the regatta specified - */ - private RegattaLeaderboard loadRegattaLeaderboard(String leaderboardName, String regattaName, DBObject dbLeaderboard, - ThresholdBasedResultDiscardingRule resultDiscardingRule, RegattaRegistry regattaRegistry) { - RegattaLeaderboard result = null; - Regatta regatta = regattaRegistry.getRegatta(new RegattaName(regattaName)); - if (regatta == null) { - logger.info("Couldn't find regatta "+regattaName+" for corresponding regatta leaderboard. Not loading regatta leaderboard."); - } else { - result = new RegattaLeaderboardImpl(regatta, resultDiscardingRule); - result.setName(leaderboardName); - } - return result; - } - - private RaceLogStore getRaceLogStore() { - return MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore( - new MongoObjectFactoryImpl(database, serviceFinderFactory), this); - } - - private RegattaLogStore getRegattaLogStore() { - return MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore( - new MongoObjectFactoryImpl(database, serviceFinderFactory), this); - } - - private FlexibleLeaderboard loadFlexibleLeaderboard(DBObject dbLeaderboard, - ThresholdBasedResultDiscardingRule resultDiscardingRule) { - final FlexibleLeaderboardImpl result; - BasicDBList dbRaceColumns = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMNS.name()); - if (dbRaceColumns == null) { - // this was probably an orphaned overall leaderboard - logger.warning("Probably found orphan overall leaderboard named " - + dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name())+". Ignoring."); - result = null; - } else { - final ScoringScheme scoringScheme = loadScoringScheme(dbLeaderboard); - - Serializable courseAreaId = (Serializable) dbLeaderboard.get(FieldNames.COURSE_AREA_ID.name()); - CourseArea courseArea = null; - if (courseAreaId != null) { - UUID courseAreaUuid = UUID.fromString(courseAreaId.toString()); - courseArea = baseDomainFactory.getExistingCourseAreaById(courseAreaUuid); - } - - result = new FlexibleLeaderboardImpl(getRaceLogStore(), getRegattaLogStore(), - (String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name()), - resultDiscardingRule, scoringScheme, courseArea); - // For a FlexibleLeaderboard, there should be only the default fleet for any race column - for (Object dbRaceColumnAsObject : dbRaceColumns) { - BasicDBObject dbRaceColumn = (BasicDBObject) dbRaceColumnAsObject; - String columnName = (String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name()); - - RaceColumn raceColumn = result.addRaceColumn(columnName, - (Boolean) dbRaceColumn.get(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name())); - - Map raceIdentifiers = loadRaceIdentifiers(dbRaceColumn); - RaceIdentifier defaultFleetRaceIdentifier = raceIdentifiers.get(result.getFleet(null).getName()); - if (defaultFleetRaceIdentifier == null) { - // Backward compatibility - defaultFleetRaceIdentifier = raceIdentifiers.get(null); - } - if (defaultFleetRaceIdentifier != null) { - Fleet defaultFleet = result.getFleet(null); - if (defaultFleet != null) { - - raceColumn.setRaceIdentifier(defaultFleet, defaultFleetRaceIdentifier); - } else { - // leaderboard has no default fleet; don't know what to do with default RaceIdentifier - logger.warning("Discarding RaceIdentifier " + defaultFleetRaceIdentifier - + " for default fleet for leaderboard " + result.getName() - + " because no default fleet was found in leaderboard"); - } - } - - } - } - return result; - } - - private ScoringScheme loadScoringScheme(DBObject dbLeaderboard) { - ScoringSchemeType scoringSchemeType = getScoringSchemeType(dbLeaderboard); - final ScoringScheme scoringScheme = baseDomainFactory.createScoringScheme(scoringSchemeType); - return scoringScheme; - } - - private boolean loadLeaderboardCorrections(DBObject dbLeaderboard, DelayedLeaderboardCorrections correctionsToUpdate, - SettableScoreCorrection scoreCorrectionToUpdate) { - boolean needsMigration = false; - DBObject carriedPoints = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_CARRIED_POINTS.name()); - if (carriedPoints != null) { - needsMigration = true; - for (String escapedCompetitorName : carriedPoints.keySet()) { - Double carriedPointsForCompetitor = ((Number) carriedPoints.get(escapedCompetitorName)).doubleValue(); - if (carriedPointsForCompetitor != null) { - correctionsToUpdate.setCarriedPointsByName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), carriedPointsForCompetitor); - } - } - } - BasicDBList carriedPointsById = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name()); - if (carriedPointsById != null) { - for (Object o : carriedPointsById) { - DBObject competitorIdAndCarriedPoints = (DBObject) o; - Serializable competitorId = (Serializable) competitorIdAndCarriedPoints.get(FieldNames.COMPETITOR_ID.name()); - Double carriedPointsForCompetitor = ((Number) competitorIdAndCarriedPoints - .get(FieldNames.LEADERBOARD_CARRIED_POINTS.name())).doubleValue(); - if (carriedPointsForCompetitor != null) { - correctionsToUpdate.setCarriedPointsByID(competitorId, carriedPointsForCompetitor); - } - } - } - DBObject dbScoreCorrection = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name()); - if (dbScoreCorrection.containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name())) { - scoreCorrectionToUpdate.setTimePointOfLastCorrectionsValidity( - new MillisecondsTimePoint((Long) dbScoreCorrection.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name()))); - dbScoreCorrection.removeField(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name()); - } - if (dbScoreCorrection.containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name())) { - scoreCorrectionToUpdate.setComment((String) dbScoreCorrection.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name())); - dbScoreCorrection.removeField(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name()); - } - for (String escapedRaceColumnName : dbScoreCorrection.keySet()) { - // deprecated style: a DBObject per race where the keys are the escaped competitor names - // new style: a BasicDBList per race where each entry is a DBObject with COMPETITOR_ID and - // LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON and LEADERBOARD_CORRECTED_SCORE fields each - DBObject dbScoreCorrectionForRace = (DBObject) dbScoreCorrection.get(escapedRaceColumnName); - final RaceColumn raceColumn = correctionsToUpdate.getLeaderboard().getRaceColumnByName(MongoUtils.unescapeDollarAndDot(escapedRaceColumnName)); - if (raceColumn != null) { - if (dbScoreCorrectionForRace instanceof BasicDBList) { - for (Object o : (BasicDBList) dbScoreCorrectionForRace) { - DBObject dbScoreCorrectionForCompetitorInRace = (DBObject) o; - Serializable competitorId = (Serializable) dbScoreCorrectionForCompetitorInRace - .get(FieldNames.COMPETITOR_ID.name()); - if (dbScoreCorrectionForCompetitorInRace - .containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())) { - correctionsToUpdate.setMaxPointsReasonByID(competitorId, raceColumn, MaxPointsReason - .valueOf((String) dbScoreCorrectionForCompetitorInRace - .get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()))); - } - if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_CORRECTED_SCORE - .name())) { - final Double leaderboardCorrectedScore = ((Number) dbScoreCorrectionForCompetitorInRace - .get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name())).doubleValue(); - correctionsToUpdate.correctScoreByID(competitorId, raceColumn, - (Double) leaderboardCorrectedScore); - } - } - } else { - needsMigration = true; - for (String competitorName : dbScoreCorrectionForRace.keySet()) { - DBObject dbScoreCorrectionForCompetitorInRace = (DBObject) dbScoreCorrectionForRace - .get(competitorName); - if (dbScoreCorrectionForCompetitorInRace - .containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())) { - correctionsToUpdate.setMaxPointsReasonByName(MongoUtils - .unescapeDollarAndDot(competitorName), raceColumn, MaxPointsReason - .valueOf((String) dbScoreCorrectionForCompetitorInRace - .get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()))); - } - if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_CORRECTED_SCORE - .name())) { - final Double leaderboardCorrectedScore = ((Number) dbScoreCorrectionForCompetitorInRace - .get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name())).doubleValue(); - correctionsToUpdate.correctScoreByName(MongoUtils.unescapeDollarAndDot(competitorName), - raceColumn, (Double) leaderboardCorrectedScore); - } - } - } - } else { - logger.warning("Couldn't find race column " + MongoUtils.unescapeDollarAndDot(escapedRaceColumnName) - + " in leaderboard " + correctionsToUpdate.getLeaderboard().getName()); - } - } - DBObject competitorDisplayNames = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name()); - // deprecated style: a DBObject whose keys are the escaped competitor names - // new style: a BasicDBList whose entries are DBObjects with COMPETITOR_ID and COMPETITOR_DISPLAY_NAME fields - if (competitorDisplayNames != null) { - if (competitorDisplayNames instanceof BasicDBList) { - for (Object o : (BasicDBList) competitorDisplayNames) { - DBObject competitorDisplayName = (DBObject) o; - final Serializable competitorId = (Serializable) competitorDisplayName.get(FieldNames.COMPETITOR_ID.name()); - final String displayName = (String) competitorDisplayName.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); - correctionsToUpdate.setDisplayNameByID(competitorId, displayName); - } - } else { - needsMigration = true; - for (String escapedCompetitorName : competitorDisplayNames.keySet()) { - correctionsToUpdate.setDisplayNameByName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), - (String) competitorDisplayNames.get(escapedCompetitorName)); - } - } - } - return needsMigration; - } - - /** - * Expects a DBObject under the key {@link FieldNames#RACE_IDENTIFIERS} whose keys are the fleet names and whose - * values are the race identifiers as DBObjects (see {@link #loadRaceIdentifier(DBObject)}). If legacy DB instances - * have a {@link RaceIdentifier} that is not associated with a fleet name, it may be stored directly in the - * dbRaceColumn. In this case, it is returned with null as the fleet name key. - * - * @return a map with fleet names as key and the corresponding fleet's race identifier as value; the special - * null key is used to identify a "default fleet" for backward compatibility with stored - * leaderboards which don't know about fleets yet; this key should be mapped to the leaderboard's default - * fleet. - */ - private Map loadRaceIdentifiers(DBObject dbRaceColumn) { - Map result = new HashMap(); - // try to load a deprecated single race identifier to associate with the default fleet: - RaceIdentifier singleLegacyRaceIdentifier = loadRaceIdentifier(dbRaceColumn); - if (singleLegacyRaceIdentifier != null) { - result.put(null, singleLegacyRaceIdentifier); - } - DBObject raceIdentifiersPerFleet = (DBObject) dbRaceColumn.get(FieldNames.RACE_IDENTIFIERS.name()); - if (raceIdentifiersPerFleet != null) { - for (String escapedFleetName : raceIdentifiersPerFleet.keySet()) { - String fleetName = MongoUtils.unescapeDollarAndDot(escapedFleetName); - result.put(fleetName, loadRaceIdentifier((DBObject) raceIdentifiersPerFleet.get(fleetName))); - } - } - return result; - } - - @Override - public LeaderboardGroup loadLeaderboardGroup(String name, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); - LeaderboardGroup leaderboardGroup = null; - try { - BasicDBObject query = new BasicDBObject(); - query.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), name); - leaderboardGroup = loadLeaderboardGroup(leaderboardGroupCollection.findOne(query), regattaRegistry, leaderboardRegistry); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard group "+name+"."); - logger.log(Level.SEVERE, "loadLeaderboardGroup", e); - } - - return leaderboardGroup; - } - - @Override - public Iterable getAllLeaderboardGroups(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); - Set leaderboardGroups = new HashSet(); - try { - for (DBObject o : leaderboardGroupCollection.find()) { - boolean hasUUID = o.containsField(FieldNames.LEADERBOARD_GROUP_UUID.name()); - final LeaderboardGroup leaderboardGroup = loadLeaderboardGroup(o, regattaRegistry, leaderboardRegistry); - leaderboardGroups.add(leaderboardGroup); - if (!hasUUID) { - // in an effort to migrate leaderboard groups without ID to such that have a UUID as their ID, we need - // to write a leaderboard group to the database again after it just received a UUID for the first time: - logger.info("Existing LeaderboardGroup " + leaderboardGroup.getName() - + " received a UUID during migration; updating the leaderboard group in the database"); - new MongoObjectFactoryImpl(database).storeLeaderboardGroup(leaderboardGroup); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard groups."); - logger.log(Level.SEVERE, "loadLeaderboardGroup", e); - } - - return leaderboardGroups; - } - - private LeaderboardGroup loadLeaderboardGroup(DBObject o, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - String name = (String) o.get(FieldNames.LEADERBOARD_GROUP_NAME.name()); - UUID uuid = (UUID) o.get(FieldNames.LEADERBOARD_GROUP_UUID.name()); - if (uuid == null) { - uuid = UUID.randomUUID(); - logger.info("Leaderboard group "+name+" receives UUID "+uuid+" in a migration effort"); - // migration: leaderboard groups that don't yet have a UUID receive a random one - } - String description = (String) o.get(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name()); - String displayName = (String) o.get(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name()); - boolean displayGroupsInReverseOrder = false; // default value - Object displayGroupsInReverseOrderObj = o.get(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name()); - if (displayGroupsInReverseOrderObj != null) { - displayGroupsInReverseOrder = (Boolean) displayGroupsInReverseOrderObj; - } - ArrayList leaderboards = new ArrayList(); - BasicDBList dbLeaderboardIds = (BasicDBList) o.get(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name()); - for (Object object : dbLeaderboardIds) { - ObjectId dbLeaderboardId = (ObjectId) object; - DBObject dbLeaderboard = leaderboardCollection.findOne(dbLeaderboardId); - if (dbLeaderboard != null) { - final Leaderboard loadedLeaderboard = loadLeaderboard(dbLeaderboard, regattaRegistry, - leaderboardRegistry, /* groupForMetaLeaderboard */null); - if (loadedLeaderboard != null) { - leaderboards.add(loadedLeaderboard); - } - } else { - logger.warning("couldn't find leaderboard with ID "+dbLeaderboardId+" referenced by leaderboard group "+name); - } - } - logger.info("loaded leaderboard group "+name); - LeaderboardGroupImpl result = new LeaderboardGroupImpl(uuid, name, description, displayName, displayGroupsInReverseOrder, leaderboards); - Object overallLeaderboardIdOrName = o.get(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name()); - if (overallLeaderboardIdOrName != null) { - final DBObject dbOverallLeaderboard; - if (overallLeaderboardIdOrName instanceof ObjectId) { - dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardIdOrName); - } else { - dbOverallLeaderboard = (DBObject) overallLeaderboardIdOrName; - } - if (dbOverallLeaderboard != null) { - // the loadLeaderboard call adds the overall leaderboard to the leaderboard registry and sets it as the - // overall leaderboard of the leaderboard group - loadLeaderboard(dbOverallLeaderboard, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ result); - } - } - return result; - } - - @Override - public Iterable getLeaderboardsNotInGroup(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - Set result = new HashSet(); - try { - // For MongoDB 2.4 $where with refs to global objects no longer works - // http://docs.mongodb.org/manual/reference/operator/where/#op._S_where - // Also a single where leads to a table walk without using indexes. So avoid $where. - - // Don't change the query object, unless you know what you're doing. - // It queries all leaderboards not referenced to be part of a leaderboard group - // and in particular not being an overall leaderboard of a leaderboard group. - DBCursor allLeaderboards = leaderboardCollection.find(); - for (DBObject leaderboardFromDB : allLeaderboards) { - DBObject inLeaderboardGroupsQuery = new BasicDBObject(); - inLeaderboardGroupsQuery.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), ((ObjectId)leaderboardFromDB.get("_id")).toString()); - boolean inLeaderboardGroups = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupsQuery).size()>0; - - DBObject inLeaderboardGroupOverallQuery = new BasicDBObject(); - inLeaderboardGroupOverallQuery.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), ((ObjectId)leaderboardFromDB.get("_id")).toString()); - boolean inLeaderboardGroupOverall = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupOverallQuery).size()>0; - - DBObject inLeaderboardGroupOverallQueryName = new BasicDBObject(); - inLeaderboardGroupOverallQueryName.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), leaderboardFromDB.get(FieldNames.LEADERBOARD_NAME.name())); - boolean inLeaderboardGroupOverallName = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupOverallQueryName).size()>0; - - if (!inLeaderboardGroups && !inLeaderboardGroupOverall && !inLeaderboardGroupOverallName) { - final Leaderboard loadedLeaderboard = loadLeaderboard(leaderboardFromDB, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ null); - if (loadedLeaderboard != null) { - result.add(loadedLeaderboard); - } - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboards."); - logger.log(Level.SEVERE, "getAllLeaderboards", e); - } - return result; - } - - @Override - public WindTrack loadWindTrack(String regattaName, RaceDefinition race, WindSource windSource, long millisecondsOverWhichToAverage) { - final WindTrack result; - Map resultMap = loadWindTracks(regattaName, race, windSource, millisecondsOverWhichToAverage); - if (resultMap.containsKey(windSource)) { - result = resultMap.get(windSource); - } else { - // create an empty wind track as result if no fixes were found in store for the wind source requested - result = new WindTrackImpl(millisecondsOverWhichToAverage, windSource.getType().getBaseConfidence(), - windSource.getType().useSpeed(), - /* nameForReadWriteLock */ WindTrackImpl.class.getSimpleName()+" for source "+windSource.toString()); - } - return result; - } - - @Override - public Map loadWindTracks(String regattaName, RaceDefinition race, - long millisecondsOverWhichToAverageWind) { - Map result = loadWindTracks(regattaName, race, /* constrain wind source */ null, millisecondsOverWhichToAverageWind); - return result; - } - - /** - * @param constrainToWindSource - * if null, wind for all sources will be loaded; otherwise, only wind data for the wind - * source specified by this argument will be loaded - */ - private Map loadWindTracks(String regattaName, RaceDefinition race, - WindSource constrainToWindSource, long millisecondsOverWhichToAverageWind) { - Map result = new HashMap(); - try { - DBCollection windTracks = database.getCollection(CollectionNames.WIND_TRACKS.name()); - ensureIndicesOnWindTracks(windTracks); - BasicDBObject queryById = new BasicDBObject(); - // the default query is by the RACE_ID key: - queryById.put(FieldNames.RACE_ID.name(), race.getId()); - if (constrainToWindSource != null) { - queryById.put(FieldNames.WIND_SOURCE_NAME.name(), constrainToWindSource.name()); - } - for (DBObject dbWind : windTracks.find(queryById)) { - loadWindFix(result, dbWind, millisecondsOverWhichToAverageWind); - } - // Additionally check for legacy wind fixes stored with the old EVENT_NAME key; if any are found, migrate them - BasicDBObject queryByName = new BasicDBObject(); - queryByName.put(FieldNames.EVENT_NAME.name(), regattaName); - queryByName.put(FieldNames.RACE_NAME.name(), race.getName()); - if (constrainToWindSource != null) { - queryByName.put(FieldNames.WIND_SOURCE_NAME.name(), constrainToWindSource.name()); - } - final DBCursor windFixesFoundByName = windTracks.find(queryByName); - if (windFixesFoundByName.hasNext()) { - List windFixesToMigrate = new ArrayList(); - for (DBObject dbWind : windFixesFoundByName) { - Util.Pair wind = loadWindFix(result, dbWind, millisecondsOverWhichToAverageWind); - // write the wind fix with the new ID-based key and remove the legacy wind fix from the DB - windFixesToMigrate.add(new MongoObjectFactoryImpl(database).storeWindTrackEntry(race, regattaName, - wind.getB(), wind.getA())); - } - logger.info("Migrating "+windFixesFoundByName.size()+" wind fixes of regatta "+regattaName+ - " and race "+race.getName()+" to ID-based keys"); - windTracks.insert(windFixesToMigrate.toArray(new DBObject[windFixesToMigrate.size()])); - logger.info("Removing "+windFixesFoundByName.size()+" wind fixes that were keyed by the names of regatta "+regattaName+ - " and race "+race.getName()); - windTracks.remove(queryByName); - } - } catch (Exception e) { - // something went wrong during DB access; report, then use empty new wind track - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded wind data. Check MongoDB settings."); - logger.log(Level.SEVERE, "loadWindTrack", e); - } - return result; - } - - private Util.Pair loadWindFix(Map result, DBObject dbWind, long millisecondsOverWhichToAverageWind) { - Wind wind = loadWind((DBObject) dbWind.get(FieldNames.WIND.name())); - WindSourceType windSourceType = WindSourceType.valueOf((String) dbWind.get(FieldNames.WIND_SOURCE_NAME.name())); - WindSource windSource; - if (dbWind.containsField(FieldNames.WIND_SOURCE_ID.name())) { - windSource = new WindSourceWithAdditionalID(windSourceType, (String) dbWind.get(FieldNames.WIND_SOURCE_ID.name())); - } else { - windSource = new WindSourceImpl(windSourceType); - } - WindTrack track = result.get(windSource); - if (track == null) { - track = new WindTrackImpl(millisecondsOverWhichToAverageWind, windSource.getType().getBaseConfidence(), - windSource.getType().useSpeed(), - /* nameForReadWriteLock */ WindTrackImpl.class.getSimpleName()+" for source "+windSource.toString()); - result.put(windSource, track); - } - track.add(wind); - return new Util.Pair(wind, windSource); - } - - @Override - public void loadLeaderboardGroupLinksForEvents(EventResolver eventResolver, - LeaderboardGroupResolver leaderboardGroupResolver) { - DBCollection links = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name()); - for (Object o : links.find()) { - DBObject dbLink = (DBObject) o; - UUID eventId = (UUID) dbLink.get(FieldNames.EVENT_ID.name()); - Event event = eventResolver.getEvent(eventId); - if (event == null) { - logger.info("Found leaderboard group IDs for event with ID "+eventId+" but couldn't find that event."); - } else { - @SuppressWarnings("unchecked") - List leaderboardGroupIDs = (List) dbLink.get(FieldNames.LEADERBOARD_GROUP_UUID.name()); - for (UUID leaderboardGroupID : leaderboardGroupIDs) { - LeaderboardGroup leaderboardGroup = leaderboardGroupResolver.getLeaderboardGroupByID(leaderboardGroupID); - if (leaderboardGroup != null) { - event.addLeaderboardGroup(leaderboardGroup); - } - } - } - } - } - - @Override - public Event loadEvent(String name) { - Event result; - BasicDBObject query = new BasicDBObject(); - query.put(FieldNames.EVENT_NAME.name(), name); - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); - DBObject eventDBObject = eventCollection.findOne(query); - if (eventDBObject != null) { - result = loadEvent(eventDBObject); - } else { - result = null; - } - return result; - } - - @Override - public Iterable loadAllEvents() { - ArrayList result = new ArrayList(); - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); - - try { - for (DBObject object : eventCollection.find()) { - Event event = loadEvent(object); - migrateImagesAndVideosOfEvent(event); - result.add(event); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load events."); - logger.log(Level.SEVERE, "loadAllEvents", e); - } - - return result; - } - - - private RemoteSailingServerReference loadSailingSever(DBObject serverDBObject) { - RemoteSailingServerReference result = null; - String name = (String) serverDBObject.get(FieldNames.SERVER_NAME.name()); - String urlAsString = (String) serverDBObject.get(FieldNames.SERVER_URL.name()); - try { - URL serverUrl = new URL(urlAsString); - result = new RemoteSailingServerReferenceImpl(name, serverUrl); - } catch (MalformedURLException e) { - logger.log(Level.SEVERE, "Can't load the sailing server with URL " + urlAsString, e); - } - return result; - } - - @Override - public Iterable loadAllRemoteSailingServerReferences() { - ArrayList result = new ArrayList(); - DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); - try { - for (DBObject o : serverCollection.find()) { - if (loadSailingSever(o) != null) { - result.add(loadSailingSever(o)); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load sailing server instances URLs."); - logger.log(Level.SEVERE, "loadAllSailingServers", e); - } - return result; - } - - /** - * An event doesn't store its regattas; it's the regatta that stores a reference to its event; the regatta - * needs to add itself to the event when loaded or instantiated. - */ - private Event loadEvent(DBObject eventDBObject) { - String name = (String) eventDBObject.get(FieldNames.EVENT_NAME.name()); - String description = (String) eventDBObject.get(FieldNames.EVENT_DESCRIPTION.name()); - UUID id = (UUID) eventDBObject.get(FieldNames.EVENT_ID.name()); - TimePoint startDate = loadTimePoint(eventDBObject, FieldNames.EVENT_START_DATE); - TimePoint endDate = loadTimePoint(eventDBObject, FieldNames.EVENT_END_DATE); - boolean isPublic = eventDBObject.get(FieldNames.EVENT_IS_PUBLIC.name()) != null ? (Boolean) eventDBObject.get(FieldNames.EVENT_IS_PUBLIC.name()) : false; - Venue venue = loadVenue((DBObject) eventDBObject.get(FieldNames.VENUE.name())); - Event result = new EventImpl(name, startDate, endDate, venue, isPublic, id); - result.setDescription(description); - String officialWebSiteURLAsString = (String) eventDBObject.get(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name()); - if (officialWebSiteURLAsString != null) { - try { - result.setOfficialWebsiteURL(new URL(officialWebSiteURLAsString)); - } catch (MalformedURLException e) { - logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL."); - } - } - String logoImageURLAsString = (String) eventDBObject.get(FieldNames.EVENT_LOGO_IMAGE_URL.name()); - if (logoImageURLAsString != null) { - try { - result.setLogoImageURL(new URL(logoImageURLAsString)); - } catch (MalformedURLException e) { - logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+name+". Ignoring this URL."); - } - } - BasicDBList imageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); - if (imageURLs != null) { - for (Object imageURL : imageURLs) { - try { - result.addImageURL(new URL((String) imageURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing image URL "+imageURL+" for event "+name+". Ignoring this image URL."); - } - } - } - BasicDBList videoURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); - if (videoURLs != null) { - for (Object videoURL : videoURLs) { - try { - result.addVideoURL(new URL((String) videoURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing video URL "+videoURL+" for event "+name+". Ignoring this video URL."); - } - } - } - BasicDBList sponsorImageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); - if (sponsorImageURLs != null) { - for (Object sponsorImageURL : sponsorImageURLs) { - try { - result.addSponsorImageURL(new URL((String) sponsorImageURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing sponsor image URL "+sponsorImageURL+" for event "+name+". Ignoring this sponsor image URL."); - } - } - } - BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); - if (images != null) { - for (Object imageObject : images) { - ImageDescriptor image = loadImage((DBObject) imageObject); - if (image != null) { - result.addImage(image); - } - } - } - BasicDBList videos = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEOS.name()); - if (videos != null) { - for (Object videoObject : videos) { - VideoDescriptor video = loadVideo((DBObject) videoObject); - if (video != null) { - result.addVideo(video); - } - } - } - return result; - } - - private Venue loadVenue(DBObject dbObject) { - String name = (String) dbObject.get(FieldNames.VENUE_NAME.name()); - BasicDBList dbCourseAreas = (BasicDBList) dbObject.get(FieldNames.COURSE_AREAS.name()); - Venue result = new VenueImpl(name); - for (Object courseAreaDBObject : dbCourseAreas) { - CourseArea courseArea = loadCourseArea((DBObject) courseAreaDBObject); - result.addCourseArea(courseArea); - } - return result; - } - - private CourseArea loadCourseArea(DBObject courseAreaDBObject) { - String name = (String) courseAreaDBObject.get(FieldNames.COURSE_AREA_NAME.name()); - UUID id = (UUID) courseAreaDBObject.get(FieldNames.COURSE_AREA_ID.name()); - return baseDomainFactory.getOrCreateCourseArea(id, name); - } - - @Override - public Iterable loadAllRegattas(TrackedRegattaRegistry trackedRegattaRegistry) { - List result = new ArrayList(); - DBCollection regattaCollection = database.getCollection(CollectionNames.REGATTAS.name()); - for (DBObject dbRegatta : regattaCollection.find()) { - result.add(loadRegatta(dbRegatta, trackedRegattaRegistry)); - } - return result; - } - - @Override - public Regatta loadRegatta(String name, TrackedRegattaRegistry trackedRegattaRegistry) { - DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), name); - DBCollection regattaCollection = database.getCollection(CollectionNames.REGATTAS.name()); - DBObject dbRegatta = regattaCollection.findOne(query); - Regatta result = loadRegatta(dbRegatta, trackedRegattaRegistry); - assert result == null || result.getName().equals(name); - return result; - } - - private Regatta loadRegatta(DBObject dbRegatta, TrackedRegattaRegistry trackedRegattaRegistry) { - Regatta result = null; - if (dbRegatta != null) { - String name = (String) dbRegatta.get(FieldNames.REGATTA_NAME.name()); - String boatClassName = (String) dbRegatta.get(FieldNames.BOAT_CLASS_NAME.name()); - TimePoint startDate = loadTimePoint(dbRegatta, FieldNames.REGATTA_START_DATE); - TimePoint endDate = loadTimePoint(dbRegatta, FieldNames.REGATTA_END_DATE); - Serializable id = (Serializable) dbRegatta.get(FieldNames.REGATTA_ID.name()); - if (id == null) { - id = name; - } - BoatClass boatClass = null; - if (boatClassName != null) { - boolean typicallyStartsUpwind = (Boolean) dbRegatta.get(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name()); - boatClass = baseDomainFactory.getOrCreateBoatClass(boatClassName, typicallyStartsUpwind); - } - BasicDBList dbSeries = (BasicDBList) dbRegatta.get(FieldNames.REGATTA_SERIES.name()); - Iterable series = loadSeries(dbSeries, trackedRegattaRegistry); - Serializable courseAreaId = (Serializable) dbRegatta.get(FieldNames.COURSE_AREA_ID.name()); - CourseArea courseArea = null; - if (courseAreaId != null) { - UUID courseAreaUuid = UUID.fromString(courseAreaId.toString()); - courseArea = baseDomainFactory.getExistingCourseAreaById(courseAreaUuid); - } - RegattaConfiguration configuration = null; - if (dbRegatta.containsField(FieldNames.REGATTA_REGATTA_CONFIGURATION.name())) { - try { - JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(dbRegatta.get(FieldNames.REGATTA_REGATTA_CONFIGURATION.name())))); - configuration = RegattaConfigurationJsonDeserializer.create().deserialize(json); - } catch (JsonDeserializationException|ParseException e) { - logger.log(Level.WARNING, "Error loading racing procedure configration for regatta.", e); - } - } - final Boolean useStartTimeInference = (Boolean) dbRegatta.get(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name()); - final RankingMetricConstructor rankingMetricConstructor = loadRankingMetricConstructor(dbRegatta); - result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, boatClass, startDate, endDate, series, /* persistent */true, - loadScoringScheme(dbRegatta), id, courseArea, useStartTimeInference == null ? true - : useStartTimeInference, rankingMetricConstructor); - result.setRegattaConfiguration(configuration); - } - return result; - } - - private RankingMetricConstructor loadRankingMetricConstructor(DBObject dbRegatta) { - DBObject rankingMetricJson = (DBObject) dbRegatta.get(FieldNames.REGATTA_RANKING_METRIC.name()); - // default is OneDesignRankingMetric - final RankingMetricConstructor result; - if (rankingMetricJson == null) { - result = OneDesignRankingMetric::new; - } else { - final String rankingMetricTypeName = (String) rankingMetricJson.get(FieldNames.REGATTA_RANKING_METRIC_TYPE.name()); - result = RankingMetricsFactory.getRankingMetricConstructor(RankingMetrics.valueOf(rankingMetricTypeName)); - } - return result; - } - - private ScoringSchemeType getScoringSchemeType(DBObject dbObject) { - String scoringSchemeTypeName = (String) dbObject.get(FieldNames.SCORING_SCHEME_TYPE.name()); - ScoringSchemeType scoringSchemeType; - if (scoringSchemeTypeName == null) { - scoringSchemeType = ScoringSchemeType.LOW_POINT; // the default - } else { - try { - scoringSchemeType = ScoringSchemeType.valueOf(scoringSchemeTypeName); - } catch (IllegalArgumentException ila) { - // can happen that the database contains a scoring scheme that - // has not yet been implemented - fall back with a warning - scoringSchemeType = ScoringSchemeType.LOW_POINT; - logger.warning("Could not find scoring scheme " + scoringSchemeTypeName + "! Most probably this has not yet been implemented or even been removed."); - } - } - return scoringSchemeType; - } - - private Iterable loadSeries(BasicDBList dbSeries, TrackedRegattaRegistry trackedRegattaRegistry) { - List result = new ArrayList(); - for (Object o : dbSeries) { - DBObject oneDBSeries = (DBObject) o; - Series series = loadSeries(oneDBSeries, trackedRegattaRegistry); - result.add(series); - } - return result; - } - - private Series loadSeries(DBObject dbSeries, TrackedRegattaRegistry trackedRegattaRegistry) { - String name = (String) dbSeries.get(FieldNames.SERIES_NAME.name()); - boolean isMedal = (Boolean) dbSeries.get(FieldNames.SERIES_IS_MEDAL.name()); - Boolean startsWithZeroScore = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name()); - Boolean hasSplitFleetContiguousScoring = (Boolean) dbSeries.get(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name()); - Boolean firstColumnIsNonDiscardableCarryForward = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name()); - final BasicDBList dbFleets = (BasicDBList) dbSeries.get(FieldNames.SERIES_FLEETS.name()); - List fleets = loadFleets(dbFleets); - BasicDBList dbRaceColumns = (BasicDBList) dbSeries.get(FieldNames.SERIES_RACE_COLUMNS.name()); - Iterable raceColumnNames = loadRaceColumnNames(dbRaceColumns); - Series series = new SeriesImpl(name, isMedal, fleets, raceColumnNames, trackedRegattaRegistry); - if (dbSeries.get(FieldNames.SERIES_DISCARDING_THRESHOLDS.name()) != null) { - ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbSeries, FieldNames.SERIES_DISCARDING_THRESHOLDS); - series.setResultDiscardingRule(resultDiscardingRule); - } - if (startsWithZeroScore != null) { - series.setStartsWithZeroScore(startsWithZeroScore); - } - if (hasSplitFleetContiguousScoring != null) { - series.setSplitFleetContiguousScoring(hasSplitFleetContiguousScoring); - } - if (firstColumnIsNonDiscardableCarryForward != null) { - series.setFirstColumnIsNonDiscardableCarryForward(firstColumnIsNonDiscardableCarryForward); - } - loadRaceColumnRaceLinks(dbRaceColumns, series); - return series; - } - - private Iterable loadRaceColumnNames(BasicDBList dbRaceColumns) { - List result = new ArrayList(); - for (Object o : dbRaceColumns) { - DBObject dbRaceColumn = (DBObject) o; - result.add((String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name())); - } - return result; - } - - private void loadRaceColumnRaceLinks(BasicDBList dbRaceColumns, Series series) { - for (Object o : dbRaceColumns) { - DBObject dbRaceColumn = (DBObject) o; - String name = (String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name()); - Map raceIdentifiersPerFleetName = loadRaceIdentifiers(dbRaceColumn); - for (Map.Entry e : raceIdentifiersPerFleetName.entrySet()) { - // null key for "default" fleet is not acceptable here - if (e.getKey() == null) { - logger.warning("Ignoring null fleet name while loading RaceColumn " + name); - } else { - series.getRaceColumnByName(name).setRaceIdentifier(series.getFleetByName(e.getKey()), e.getValue()); - } - } - } - } - - private List loadFleets(BasicDBList dbFleets) { - List result = new ArrayList(); - for (Object o : dbFleets) { - DBObject dbFleet = (DBObject) o; - Fleet fleet = loadFleet(dbFleet); - result.add(fleet); - } - return result; - } - - private Fleet loadFleet(DBObject dbFleet) { - Fleet result; - String name = (String) dbFleet.get(FieldNames.FLEET_NAME.name()); - Integer ordering = (Integer) dbFleet.get(FieldNames.FLEET_ORDERING.name()); - if (ordering == null) { - ordering = 0; - } - Integer colorAsInt = (Integer) dbFleet.get(FieldNames.FLEET_COLOR.name()); - Color color = null; - if (colorAsInt != null) { - int r = colorAsInt % 256; - int g = (colorAsInt / 256 ) % 256; - int b = (colorAsInt / 256 / 256) % 256; - color = new RGBColor(r, g, b); - } - result = new FleetImpl(name, ordering, color); - return result; - } - - @Override - public Map loadRaceIDToRegattaAssociations(RegattaRegistry regattaRegistry) { - DBCollection raceIDToRegattaCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); - Map result = new HashMap(); - for (DBObject o : raceIDToRegattaCollection.find()) { - Regatta regatta = regattaRegistry.getRegattaByName((String) o.get(FieldNames.REGATTA_NAME.name())); - if (regatta != null) { - result.put((String) o.get(FieldNames.RACE_ID_AS_STRING.name()), regatta); - } else { - logger.warning("Couldn't find regatta " + o.get(FieldNames.REGATTA_NAME.name()) - + ". Cannot restore race associations with this regatta."); - } - } - return result; - } - - @Override - public RaceLog loadRaceLog(RaceLogIdentifier identifier) { - RaceLog result = new RaceLogImpl(RaceLogImpl.class.getSimpleName(), identifier.getIdentifier()); - try { - BasicDBObject query = new BasicDBObject(); - query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(identifier.getIdentifier())); - loadRaceLogEvents(result, query); - - // query for events with deprecated identifier format... - query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(identifier.getDeprecatedIdentifier())); - - List eventsToMigrate = loadRaceLogEvents(result, query); - if (!eventsToMigrate.isEmpty()) { - // ... migrate them... - MongoRaceLogStoreVisitor storeVisitor = new MongoRaceLogStoreVisitor(identifier, new MongoObjectFactoryImpl(database, serviceFinderFactory)); - for (RaceLogEvent event : eventsToMigrate) { - event.accept(storeVisitor); - } - // ... and delete the old ones... - database.getCollection(CollectionNames.RACE_LOGS.name()).remove(query); - } - } catch (Throwable t) { - // something went wrong during DB access; report, then use empty new race log - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded race log data. Check MongoDB settings."); - logger.log(Level.SEVERE, "loadRaceLog", t); - } - return result; - } - - private List loadRaceLogEvents(RaceLog targetRaceLog, BasicDBObject query) { - List result = new ArrayList<>(); - DBCollection raceLog = database.getCollection(CollectionNames.RACE_LOGS.name()); - for (DBObject o : raceLog.find(query)) { - try { - RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name())); - if (raceLogEvent != null) { - targetRaceLog.load(raceLogEvent); - result.add(raceLogEvent); - } - } catch (IllegalStateException e) { - logger.log(Level.SEVERE, "Couldn't load race log event "+o+": "+e.getMessage(), e); - } - } - return result; - } - - public RaceLogEvent loadRaceLogEvent(DBObject dbObject) { - TimePoint logicalTimePoint = loadTimePoint(dbObject); - TimePoint createdAt = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_CREATED_AT); - Serializable id = (Serializable) dbObject.get(FieldNames.RACE_LOG_EVENT_ID.name()); - Integer passId = (Integer) dbObject.get(FieldNames.RACE_LOG_EVENT_PASS_ID.name()); - BasicDBList dbCompetitors = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name()); - List competitors = loadCompetitorsForRaceLogEvent(dbCompetitors); - final AbstractLogEventAuthor author; - String authorName = (String) dbObject.get(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name()); - Number authorPriority = (Number) dbObject.get(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name()); - if (authorName != null && authorPriority != null) { - author = new LogEventAuthorImpl(authorName, authorPriority.intValue()); - } else { - author = LogEventAuthorImpl.createCompatibilityAuthor(); - } - - String eventClass = (String) dbObject.get(FieldNames.RACE_LOG_EVENT_CLASS.name()); - if (eventClass.equals(RaceLogStartTimeEvent.class.getSimpleName())) { - return loadRaceLogStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogRaceStatusEvent.class.getSimpleName())) { - return loadRaceLogRaceStatusEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogFlagEvent.class.getSimpleName())) { - return loadRaceLogFlagEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogPassChangeEvent.class.getSimpleName())) { - return loadRaceLogPassChangeEvent(createdAt, author, logicalTimePoint, id, passId, competitors); - } else if (eventClass.equals(RaceLogCourseAreaChangedEvent.class.getSimpleName())) { - return loadRaceLogCourseAreaChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogCourseDesignChangedEvent.class.getSimpleName())) { - return loadRaceLogCourseDesignChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogFinishPositioningListChangedEvent.class.getSimpleName())) { - return loadRaceLogFinishPositioningListChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogFinishPositioningConfirmedEvent.class.getSimpleName())) { - return loadRaceLogFinishPositioningConfirmedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogPathfinderEvent.class.getSimpleName())) { - return loadRaceLogPathfinderEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogGateLineOpeningTimeEvent.class.getSimpleName())) { - return loadRaceLogGateLineOpeningTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogStartProcedureChangedEvent.class.getSimpleName())) { - return loadRaceLogStartProcedureChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogProtestStartTimeEvent.class.getSimpleName())) { - return loadRaceLogRaceLogProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogWindFixEvent.class.getSimpleName())) { - return loadRaceLogRaceLogWindFixEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogDeviceCompetitorMappingEvent.class.getSimpleName())) { - return loadRaceLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogDeviceMarkMappingEvent.class.getSimpleName())) { - return loadRaceLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogDenoteForTrackingEvent.class.getSimpleName())) { - return loadRaceLogDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogStartTrackingEvent.class.getSimpleName())) { - return loadRaceLogStartEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogRevokeEvent.class.getSimpleName())) { - return loadRaceLogRevokeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogRegisterCompetitorEvent.class.getSimpleName())) { - return loadRaceLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogDefineMarkEvent.class.getSimpleName())) { - return loadRaceLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) { - return loadRaceLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(RaceLogAdditionalScoringInformationEvent.class.getSimpleName())) { - return loadRaceLogAdditionalScoringInformationEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(FixedMarkPassingEvent.class.getSimpleName())){ - return loadRaceLogFixedMarkPassingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } else if (eventClass.equals(SuppressedMarkPassingsEvent.class.getSimpleName())){ - return loadRaceLogSuppressedMarkPassingsEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); - } - - throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass)); - } - - private RaceLogEvent loadRaceLogRaceLogWindFixEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Wind wind = loadWind((DBObject) dbObject.get(FieldNames.WIND.name())); - return raceLogEventFactory.createWindFixEvent(createdAt, author, logicalTimePoint, id, competitors, passId, wind); - } - - private RaceLogEvent loadRaceLogDeviceCompetitorMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - DeviceIdentifier device = null; - try { - device = loadDeviceId(deviceIdentifierServiceFinder, - (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); - } catch (Exception e) { - logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); - e.printStackTrace(); - } - Competitor mappedTo = baseDomainFactory.getExistingCompetitorById( - (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name())); - TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); - TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); - return raceLogEventFactory.createDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); - } - - private RaceLogEvent loadRaceLogDeviceMarkMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - DeviceIdentifier device = null; - try { - device = loadDeviceId(deviceIdentifierServiceFinder, - (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); - } catch (Exception e) { - logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); - e.printStackTrace(); - } - //have to load complete mark, as no order is guaranteed for loading of racelog events - Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name())); - TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); - TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); - return raceLogEventFactory.createDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); - } - - private RaceLogEvent loadRaceLogDenoteForTrackingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name()); - BoatClass boatClass = baseDomainFactory.getOrCreateBoatClass((String) dbObject.get(FieldNames.BOAT_CLASS_NAME.name())); - Serializable raceId = (Serializable) dbObject.get(FieldNames.RACE_ID.name()); - return raceLogEventFactory.createDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, raceName, boatClass, raceId); - } - - private RaceLogEvent loadRaceLogStartEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - return raceLogEventFactory.createStartTrackingEvent(createdAt, author, logicalTimePoint, id, passId); - } - - private RaceLogEvent loadRaceLogRevokeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Serializable revokedEventId = Helpers.tryUuidConversion( - (Serializable) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name())); - String revokedEventType = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name()); - String revokedEventShortInfo = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name()); - String reason = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_REASON.name()); - return raceLogEventFactory.createRevokeEvent(createdAt, author, logicalTimePoint, id, passId, - revokedEventId, revokedEventType, revokedEventShortInfo, reason); - } - - private RaceLogEvent loadRaceLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Serializable competitorId = (Serializable) dbObject.get(FieldNames.RACE_LOG_COMPETITOR_ID.name()); - Competitor comp = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); - return raceLogEventFactory.createRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, comp); - } - - private RaceLogEvent loadRaceLogDefineMarkEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Mark mark = loadMark((DBObject) dbObject.get(FieldNames.RACE_LOG_MARK.name())); - return raceLogEventFactory.createDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, mark); - } - - private RaceLogEvent loadRaceLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name())); - TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.RACE_LOG_CLOSING_TIMEPOINT); - return raceLogEventFactory.createCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, - deviceMappingEventId, closingTimePoint); - } - - private RaceLogEvent loadRaceLogAdditionalScoringInformationEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Object additionalScoringInformationTypeInfo = dbObject.get(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name()); - AdditionalScoringInformationType informationType = AdditionalScoringInformationType.UNKNOWN; - if (additionalScoringInformationTypeInfo != null) { - informationType = AdditionalScoringInformationType.valueOf(additionalScoringInformationTypeInfo.toString()); - } else { - logger.warning("Could not find additional scoring information attached to db log for " + dbObject.toString()); - } - return raceLogEventFactory.createAdditionalScoringInformationEvent(createdAt, author, logicalTimePoint, id, competitors, passId, informationType); - } - - private RaceLogEvent loadRaceLogRaceLogProtestStartTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - TimePoint protestStartTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_PROTEST_START_TIME); - return raceLogEventFactory.createProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, competitors, passId, protestStartTime); - } - - private RaceLogEvent loadRaceLogStartProcedureChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - RacingProcedureType type = RacingProcedureType.valueOf(dbObject.get(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name()).toString()); - return raceLogEventFactory.createStartProcedureChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, type); - } - - private RaceLogEvent loadRaceLogGateLineOpeningTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Number gateLaunchStopTime = (Number) dbObject.get(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name()); - Number golfDownTime = 0; - if (dbObject.containsField(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name())) { - golfDownTime = (Number) dbObject.get(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name()); - } - return raceLogEventFactory.createGateLineOpeningTimeEvent(createdAt, author, logicalTimePoint, id, competitors, - passId, gateLaunchStopTime == null ? null : gateLaunchStopTime.longValue(), golfDownTime.longValue()); - } - - private RaceLogEvent loadRaceLogPathfinderEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - String pathfinderId = dbObject.get(FieldNames.RACE_LOG_PATHFINDER_ID.name()).toString(); - return raceLogEventFactory.createPathfinderEvent(createdAt, author, logicalTimePoint, id, competitors, passId, pathfinderId); - } - - private RaceLogEvent loadRaceLogFinishPositioningConfirmedEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - BasicDBList dbPositionedCompetitorList = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name()); - CompetitorResults positionedCompetitors = null; - //When a confirmation event is loaded that does not contain the positioned competitors (this is the case for the ESS events in - //Singapore and Quingdao) then null should be set for the positionedCompetitors, which is evaluated later on. - if (dbPositionedCompetitorList != null) { - positionedCompetitors = loadPositionedCompetitors(dbPositionedCompetitorList); - } - - return raceLogEventFactory.createFinishPositioningConfirmedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, positionedCompetitors); - } - - private RaceLogEvent loadRaceLogFinishPositioningListChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - BasicDBList dbPositionedCompetitorList = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name()); - CompetitorResults positionedCompetitors = loadPositionedCompetitors(dbPositionedCompetitorList); - - return raceLogEventFactory.createFinishPositioningListChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, positionedCompetitors); - } - - private RaceLogEvent loadRaceLogPassChangeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors) { - return raceLogEventFactory.createPassChangeEvent(createdAt, author, logicalTimePoint, id, competitors, passId); - } - - private RaceLogCourseDesignChangedEvent loadRaceLogCourseDesignChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - String courseName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name()); - CourseBase courseData = loadCourseData((BasicDBList) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN.name()), courseName); - return raceLogEventFactory.createCourseDesignChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, courseData); - } - - private RaceLogCourseAreaChangedEvent loadRaceLogCourseAreaChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - Serializable courseAreaId = (Serializable) dbObject.get(FieldNames.COURSE_AREA_ID.name()); - return raceLogEventFactory.createCourseAreaChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, courseAreaId); - } - - private RaceLogEvent loadRaceLogFixedMarkPassingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - TimePoint ofFixedPassing = loadTimePoint(dbObject, FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING); - Integer zeroBasedIndexOfWaypoint = (Integer) dbObject.get(FieldNames.INDEX_OF_PASSED_WAYPOINT.name()); - return raceLogEventFactory.createFixedMarkPassingEvent(logicalTimePoint, author, id, competitors, passId, ofFixedPassing, zeroBasedIndexOfWaypoint); - } - - private RaceLogEvent loadRaceLogSuppressedMarkPassingsEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, - Serializable id, Integer passId, List competitors, DBObject dbObject) { - Integer zeroBasedIndexOfFirstSuppressedWaypoint = (Integer) dbObject.get(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name()); - return raceLogEventFactory.createSuppressedMarkPassingsEvent(logicalTimePoint, author, id, competitors, passId, zeroBasedIndexOfFirstSuppressedWaypoint); - } - - private CompetitorResults loadPositionedCompetitors(BasicDBList dbPositionedCompetitorList) { - CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - for (Object object : dbPositionedCompetitorList) { - DBObject dbObject = (DBObject) object; - - Serializable competitorId = (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()); - - String competitorName = (String) dbObject.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); - //The Competitor name is a new field in the list. Therefore the name might be null for existing events. In this case a standard name is set. - if (competitorName == null) { - competitorName = "loaded competitor"; - } - - //At this point we do not retrieve the competitor object since at any point in time, especially after a server restart, the DomainFactory and its competitor - //cache might be empty. But at this time the race log is loaded from database, so the competitor would be null. - //By not using the Competitor object retrieved from the DomainFactory we get completely independent from server restarts and the timepoint of loading - //competitors by tracking providers. - - MaxPointsReason maxPointsReason = MaxPointsReason.valueOf((String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())); - - Util.Triple positionedCompetitor = new Util.Triple(competitorId, competitorName, maxPointsReason); - positionedCompetitors.add(positionedCompetitor); - } - return positionedCompetitors; - } - - private List loadCompetitorsForRaceLogEvent(BasicDBList dbCompetitorList) { - List competitors = new ArrayList(); - for (Object object : dbCompetitorList) { - Serializable competitorId = (Serializable) object; - Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); - competitors.add(competitor); - } - return competitors; - } - - private RaceLogFlagEvent loadRaceLogFlagEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - Flags upperFlag = Flags.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name())); - Flags lowerFlag = Flags.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name())); - Boolean displayed = Boolean.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name())); - - if (upperFlag == null || lowerFlag == null || displayed == null) { - return null; - } - - return raceLogEventFactory.createFlagEvent(createdAt, author, logicalTimePoint, id, competitors, passId, upperFlag, lowerFlag, displayed); - } - - private RaceLogStartTimeEvent loadRaceLogStartTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - TimePoint startTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_START_TIME); - return raceLogEventFactory.createStartTimeEvent(createdAt, author, logicalTimePoint, id, competitors, passId, startTime); - } - - private RaceLogRaceStatusEvent loadRaceLogRaceStatusEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { - RaceLogRaceStatus nextStatus = RaceLogRaceStatus.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name())); - return raceLogEventFactory.createRaceStatusEvent(createdAt, author, logicalTimePoint, id, competitors, passId, nextStatus); - } - - @Override - public RegattaLog loadRegattaLog(RegattaLikeIdentifier identifier) { - RegattaLog result = new RegattaLogImpl(RegattaLogImpl.class.getSimpleName(), identifier); - try { - BasicDBObject query = new BasicDBObject(); - query.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), identifier.getIdentifierType()); - query.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), identifier.getName()); - loadRegattaLogEvents(result, query, identifier); - } catch (Throwable t) { - // something went wrong during DB access; report, then use empty new regatta log - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded regatta log data. Check MongoDB settings."); - logger.log(Level.SEVERE, "loadRegattaLog", t); - } - return result; - } - - private void loadRegattaLogEvents(RegattaLog targetRegattaLog, BasicDBObject query, RegattaLikeIdentifier regattaLogIdentifier) { - DBCollection collection = database.getCollection(CollectionNames.REGATTA_LOGS.name()); - for (DBObject o : collection.find(query)) { - try { - RegattaLogEvent event = loadRegattaLogEvent(o, regattaLogIdentifier); - if (event != null) { - targetRegattaLog.load(event); - } - } catch (IllegalStateException e) { - logger.log(Level.SEVERE, "Couldn't load regatta log event "+o+": "+e.getMessage(), e); - } - } - } - - private RegattaLogEvent loadRegattaLogEvent(DBObject o, RegattaLikeIdentifier regattaLogIdentifier) { - DBObject dbObject = (DBObject) o.get(FieldNames.REGATTA_LOG_EVENT.name()); - TimePoint logicalTimePoint = loadTimePoint(dbObject); - TimePoint createdAt = loadTimePoint(dbObject, FieldNames.REGATTA_LOG_EVENT_CREATED_AT); - Serializable id = (Serializable) dbObject.get(FieldNames.REGATTA_LOG_EVENT_ID.name()); - final AbstractLogEventAuthor author; - String authorName = (String) dbObject.get(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name()); - Number authorPriority = (Number) dbObject.get(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name()); - author = new LogEventAuthorImpl(authorName, authorPriority.intValue()); - //CloseOpenEnded, DeviceCompMapping, DeviceMarkMapping, RegisterComp, Revoke - String eventClass = (String) dbObject.get(FieldNames.REGATTA_LOG_EVENT_CLASS.name()); - if (eventClass.equals(RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName())) { - return loadRegattaLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, dbObject, regattaLogIdentifier, o); - } else if (eventClass.equals(RegattaLogDeviceMarkMappingEvent.class.getSimpleName())) { - return loadRegattaLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, dbObject, regattaLogIdentifier, o); - } else if (eventClass.equals(RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) { - return loadRegattaLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, dbObject); - } else if (eventClass.equals(RegattaLogRegisterCompetitorEvent.class.getSimpleName())) { - return loadRegattaLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, dbObject); - } else if (eventClass.equals(RegattaLogSetCompetitorTimeOnTimeFactorEvent.class.getSimpleName())) { - return loadRegattaLogSetCompetitorTimeOnTimeFactorEvent(createdAt, author, logicalTimePoint, id, dbObject); - } else if (eventClass.equals(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent.class.getSimpleName())) { - return loadRegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent(createdAt, author, logicalTimePoint, id, dbObject); - } else if (eventClass.equals(RegattaLogRevokeEvent.class.getSimpleName())) { - return loadRegattaLogRevokeEvent(createdAt, author, logicalTimePoint, id, dbObject); - } - throw new IllegalStateException(String.format("Unknown RegattaLogEvent type %s", eventClass)); - } - - private Competitor getCompetitorByID(DBObject dbObject) { - Serializable competitorId = (Serializable) dbObject.get(FieldNames.REGATTA_LOG_COMPETITOR_ID.name()); - Competitor comp = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); - return comp; - } - - private RegattaLogEvent loadRegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent(TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { - final Competitor comp = getCompetitorByID(dbObject); - final Double timeOnTimeFactor = (Double) dbObject.get(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name()); - return new RegattaLogSetCompetitorTimeOnTimeFactorEventImpl(createdAt, author, logicalTimePoint, id, comp, timeOnTimeFactor); - } - - private RegattaLogEvent loadRegattaLogSetCompetitorTimeOnTimeFactorEvent(TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { - final Competitor comp = getCompetitorByID(dbObject); - final Double timeOnDistanceSecondsAllowancePerNauticalMile = (Double) dbObject.get(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name()); - final Duration timeOnDistanceAllowancePerNauticalMile = timeOnDistanceSecondsAllowancePerNauticalMile == null ? null : - new MillisecondsDurationImpl((long) (timeOnDistanceSecondsAllowancePerNauticalMile*1000)); - return new RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEventImpl(createdAt, author, logicalTimePoint, id, comp, timeOnDistanceAllowancePerNauticalMile); - } - - private RegattaLogRevokeEvent loadRegattaLogRevokeEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { - Serializable revokedEventId = Helpers.tryUuidConversion( - (Serializable) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name())); - String revokedEventType = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name()); - String revokedEventShortInfo = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name()); - String reason = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_REASON.name()); - return new RegattaLogRevokeEventImpl(createdAt, author, logicalTimePoint, id, - revokedEventId, revokedEventType, revokedEventShortInfo, reason); - } - - private RegattaLogRegisterCompetitorEvent loadRegattaLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { - Competitor comp = getCompetitorByID(dbObject); - return new RegattaLogRegisterCompetitorEventImpl(createdAt, author, logicalTimePoint, id, comp); - } - - private RegattaLogCloseOpenEndedDeviceMappingEvent loadRegattaLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { - Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get( - FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name())); - TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT); - return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(createdAt, author, logicalTimePoint, id, - deviceMappingEventId, closingTimePoint); - } - - private RegattaLogDeviceMarkMappingEvent loadRegattaLogDeviceMarkMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint logicalTimePoint, Serializable id, DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) { - DeviceIdentifier device = null; - try { - device = loadDeviceId(deviceIdentifierServiceFinder, - (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); - } catch (Exception e) { - logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); - e.printStackTrace(); - } - //have to load complete mark, as no order is guaranteed for loading of racelog events - Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name())); - Triple times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO); - final TimePoint from = times.getA(); - final TimePoint to = times.getB(); - final RegattaLogDeviceMarkMappingEventImpl result = new RegattaLogDeviceMarkMappingEventImpl(createdAt, author, logicalTimePoint, id, mappedTo, device, from, to); - final boolean needsMigration = times.getC(); - if (needsMigration) { - // remove old version of mapping event - WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject); - assert removeResult.getN() == 1; - // and then insert using the fixed storage implementation - new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result); - } - return result; - } - - /** - * Loads a from and a to time point from fromField and toField of dbObject. - * If the fromField is not found, the fromFieldDeprecated is attempted. If found, migration - * is deemed necessary, expressed by returning true in the {@link Triple#getC()} component of the result. - * Same for the to-field. - * - * @return the from-time in {@link Triple#getA()}, the to-time in {@link Triple#getB()} and whether or not migration is - * necessary because a value was only found in a deprecated field in {@link Triple#getC()}. - */ - private Triple loadFromToTimePoint(final DBObject dbObject, FieldNames fromField, FieldNames fromFieldDeprecated, - FieldNames toField, FieldNames toFieldDeprecated) { - boolean needsMigration = false; - TimePoint from = loadTimePoint(dbObject, fromField); - if (from == null) { - // see bug 2733: erroneously, some records before the fix were written using RACE_LOG_FROM instead of REGATTA_LOG_FROM - // If such a case is found here, migrate the record. - from = loadTimePoint(dbObject, fromFieldDeprecated); - if (from != null) { - needsMigration = true; - } - } - TimePoint to = loadTimePoint(dbObject, toField); - if (to == null) { - // see bug 2733: erroneously, some records before the fix were written using RACE_LOG_FROM instead of REGATTA_LOG_FROM - // If such a case is found here, migrate the record. - to = loadTimePoint(dbObject, toFieldDeprecated); - if (to != null) { - needsMigration = true; - } - } - return new Triple<>(from, to, needsMigration); - } - - private RegattaLogDeviceCompetitorMappingEvent loadRegattaLogDeviceCompetitorMappingEvent(TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, final DBObject dbObject, - RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) { - DeviceIdentifier device = null; - try { - device = loadDeviceId(deviceIdentifierServiceFinder, - (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); - } catch (Exception e) { - logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); - e.printStackTrace(); - } - Competitor mappedTo = baseDomainFactory.getExistingCompetitorById( - (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name())); - Triple times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO); - final TimePoint from = times.getA(); - final TimePoint to = times.getB(); - final boolean needsMigration = times.getC(); - final RegattaLogDeviceCompetitorMappingEventImpl result = new RegattaLogDeviceCompetitorMappingEventImpl(createdAt, author, logicalTimePoint, id, mappedTo, device, from, to); - if (needsMigration) { - // remove old version of mapping event - WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject); - assert removeResult.getN() == 1; - // and then insert using the fixed storage implementation - new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result); - } - return result; - } - - /** - * The old field name WAYPOINT_PASSINGSIDE has been replaced by WAYPOINT_PASSINGINSTRUCTIONS. If a race with the old - * field is loaded, the value of PASSINGSIDE is used and then migrated to PASSINGINSTRUCTION. If the first or last - * Waypoint has the PassingInstructions Gate, it is transfered to Line. - * - */ - @SuppressWarnings("deprecation") // Used to migrate from PASSINGSIDE to the new PASSINGINSTRUCTIONS - private CourseBase loadCourseData(BasicDBList dbCourseList, String courseName) { - if (courseName == null) { - courseName = "Course"; - } - CourseBase courseData = new CourseDataImpl(courseName); - int i = 0; - for (Object object : dbCourseList) { - DBObject dbObject = (DBObject) object; - Waypoint waypoint = null; - PassingInstruction passingInstructions = null; - String waypointPassingInstruction = (String) dbObject.get(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name()); - if (waypointPassingInstruction == null) { - waypointPassingInstruction = (String) dbObject.get(FieldNames.WAYPOINT_PASSINGSIDE.name()); - if(waypointPassingInstruction != null) { - logger.info("Migrating PassingInstruction "+waypointPassingInstruction+" to field name WAYPOINT_PASSINGINSTRUCTIONS"); - if((i==0||i==dbCourseList.size()-1)&&waypointPassingInstruction.toLowerCase().equals("gate")){ - logger.warning("Changing PassingInstructions of first or last Waypoint from Gate to Line."); - waypointPassingInstruction = "Line"; - } - dbObject.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), waypointPassingInstruction); - dbObject.removeField(FieldNames.WAYPOINT_PASSINGSIDE.name()); - } - } - if (waypointPassingInstruction != null) { - passingInstructions = PassingInstruction.valueOfIgnoringCase(waypointPassingInstruction); - } - ControlPoint controlPoint = loadControlPoint((DBObject) dbObject.get(FieldNames.CONTROLPOINT.name())); - if (passingInstructions == null) { - waypoint = new WaypointImpl(controlPoint); - } else { - waypoint = new WaypointImpl(controlPoint, passingInstructions); - } - courseData.addWaypoint(i++, waypoint); - } - return courseData; - } - - private ControlPoint loadControlPoint(DBObject dbObject) { - String controlPointClass = (String) dbObject.get(FieldNames.CONTROLPOINT_CLASS.name()); - ControlPoint controlPoint = null; - if (controlPointClass != null) { - if (controlPointClass.equals(Mark.class.getSimpleName())) { - Mark mark = loadMark((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); - controlPoint = mark; - } else if(controlPointClass.equals("Gate")) { - ControlPointWithTwoMarks cpwtm = loadControlPointWithTwoMarks((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); - dbObject.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); - controlPoint = cpwtm; - } else if (controlPointClass.equals(ControlPointWithTwoMarks.class.getSimpleName())) { - ControlPointWithTwoMarks cpwtm = loadControlPointWithTwoMarks((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); - controlPoint = cpwtm; - } - } - return controlPoint; - } - - /** - * Checks for the old GATE fields and migrates them to the new CONTROLPOINTWITHTWOMARKS fields. - */ - @SuppressWarnings("deprecation") // Used for migrating old races - private ControlPointWithTwoMarks loadControlPointWithTwoMarks(DBObject dbObject) { - String controlPointName = (String) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name()); - if (controlPointName == null) { - controlPointName = (String) dbObject.get(FieldNames.GATE_NAME.name()); - logger.info("Migrating name of ControlPointWithTwoMarks " + controlPointName - + " from GATE_NAME to new field CONTROLPOINTWITHTWOMARKS_NAME."); - dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), controlPointName); - dbObject.removeField(FieldNames.GATE_NAME.name()); - } - Serializable controlPointId = (Serializable) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name()); - if (controlPointId == null) { - controlPointId = (Serializable) dbObject.get(FieldNames.GATE_ID.name()); - logger.info("Migrating id of ControlPointWithTwoMarks " + controlPointName - + " from old field GATE_ID to CONTROLPOINTWITHTWOMARKS_ID."); - dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), controlPointId); - dbObject.removeField(FieldNames.GATE_ID.name()); - } - DBObject dbLeft = (DBObject) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name()); - if (dbLeft == null) { - dbLeft = (DBObject) dbObject.get(FieldNames.GATE_LEFT.name()); - logger.info("Migrating left Mark of ControlPointWithTwoMarks " + controlPointName + " from old field GATE_LEFT to CONTROLPOINTWITHTWOMARKS_LEFT"); - dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), dbLeft); - dbObject.removeField(FieldNames.GATE_LEFT.name()); - } - Mark leftMark = loadMark(dbLeft); - DBObject dbRight = (DBObject) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name()); - if (dbRight == null) { - dbRight = (DBObject) dbObject.get(FieldNames.GATE_RIGHT.name()); - logger.info("Migrating right Mark of ControlPointWithTwoMarks " + controlPointName + " from old field GATE_RIGHT to CONTROLPOINTWITHTWOMARKS_RIGHT"); - dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), dbRight); - dbObject.removeField(FieldNames.GATE_RIGHT.name()); - } - Mark rightMark = loadMark(dbRight); - ControlPointWithTwoMarks gate = baseDomainFactory.createControlPointWithTwoMarks(controlPointId, leftMark, rightMark, controlPointName); - return gate; - } - - private Mark loadMark(DBObject dbObject) { - Serializable markId = (Serializable) dbObject.get(FieldNames.MARK_ID.name()); - String markColor = (String) dbObject.get(FieldNames.MARK_COLOR.name()); - String markName = (String) dbObject.get(FieldNames.MARK_NAME.name()); - String markPattern = (String) dbObject.get(FieldNames.MARK_PATTERN.name()); - String markShape = (String) dbObject.get(FieldNames.MARK_SHAPE.name()); - Object markTypeRaw = dbObject.get(FieldNames.MARK_TYPE.name()); - MarkType markType = markTypeRaw == null ? null : MarkType.valueOf((String) markTypeRaw); - - Mark mark = baseDomainFactory.getOrCreateMark(markId, markName, markType, markColor, markShape, markPattern); - return mark; - } - - @Override - public Collection loadAllCompetitors() { - ArrayList result = new ArrayList(); - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); - try { - for (DBObject o : collection.find()) { - JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(o))); - Competitor c = competitorDeserializer.deserialize(json); - result.add(c); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load competitors."); - logger.log(Level.SEVERE, "loadCompetitors", e); - } - return result; - } - - @Override - public Iterable> loadAllDeviceConfigurations() { - Map result = new HashMap<>(); - DBCollection configurationCollection = database.getCollection(CollectionNames.CONFIGURATIONS.name()); - - try { - for (DBObject dbObject : configurationCollection.find()) { - Util.Pair entry = loadConfigurationEntry(dbObject); - result.put(entry.getA(), entry.getB()); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load configurations."); - logger.log(Level.SEVERE, "loadAllDeviceConfigurations", e); - } - - return result.entrySet(); - } - - private Util.Pair loadConfigurationEntry(DBObject dbObject) { - DBObject matcherObject = (DBObject) dbObject.get(FieldNames.CONFIGURATION_MATCHER.name()); - DBObject configObject = (DBObject) dbObject.get(FieldNames.CONFIGURATION_CONFIG.name()); - return new Util.Pair(loadConfigurationMatcher(matcherObject), - loadConfiguration(configObject)); - } - - private DeviceConfigurationMatcher loadConfigurationMatcher(DBObject matcherObject) { - DeviceConfigurationMatcherType type = DeviceConfigurationMatcherType.valueOf( - matcherObject.get(FieldNames.CONFIGURATION_MATCHER_TYPE.name()).toString()); - List clientIdentifiers = new ArrayList(); - BasicDBList clientIdentifiersObject = (BasicDBList) matcherObject.get(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name()); - if (clientIdentifiersObject != null) { - for (Object clientIdentifier : clientIdentifiersObject) { - clientIdentifiers.add(clientIdentifier.toString()); - } - } - return baseDomainFactory.getOrCreateDeviceConfigurationMatcher(type, clientIdentifiers); - } - - private DeviceConfiguration loadConfiguration(DBObject configObject) { - DeviceConfiguration configuration = null; - try { - JsonDeserializer deserializer = DeviceConfigurationJsonDeserializer.create(); - JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(configObject))); - configuration = deserializer.deserialize(json); - } catch (JsonDeserializationException | ParseException e) { - logger.log(Level.SEVERE, "Error parsing configuration object from MongoDB, falling back to empty configuration."); - logger.log(Level.SEVERE, "loadConfiguration", e); - configuration = new DeviceConfigurationImpl(new RegattaConfigurationImpl()); - } - return configuration; - } - - private DeviceIdentifier loadDeviceId( - TypeBasedServiceFinder deviceIdentifierServiceFinder, DBObject deviceId) - throws TransformationException, NoCorrespondingServiceRegisteredException { - String deviceType = (String) deviceId.get(FieldNames.DEVICE_TYPE.name()); - Object deviceTypeId = deviceId.get(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name()); - String stringRepresentation = (String) deviceId.get(FieldNames.DEVICE_STRING_REPRESENTATION.name()); - - try { - return deviceIdentifierServiceFinder.findService(deviceType).deserialize(deviceTypeId, deviceType, stringRepresentation); - } catch (TransformationException e) { - return new PlaceHolderDeviceIdentifierSerializationHandler().deserialize( - stringRepresentation, deviceType, stringRepresentation); - } - } - - @Override - public Map> loadResultUrls() { - Map> resultUrls = new HashMap<>(); - DBCollection resultUrlCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); - for (DBObject dbObject : resultUrlCollection.find()) { - String providerName = (String) dbObject.get(FieldNames.RESULT_PROVIDERNAME.name()); - String urlString = (String) dbObject.get(FieldNames.RESULT_URL.name()); - URL url; - try { - url = new URL(urlString); - } catch (MalformedURLException e) { - logger.log(Level.SEVERE, "Failed to parse result Url String: " + urlString + ". Did not load url!"); - continue; - } - if (!resultUrls.containsKey(providerName)) { - resultUrls.put(providerName, new HashSet()); - } - Set set = resultUrls.get(providerName); - set.add(url); - } - return resultUrls; - } - - private ImageDescriptor loadImage(DBObject dbObject) { - ImageDescriptor image = null; - URL imageURL = loadURL(dbObject, FieldNames.IMAGE_URL); - if (imageURL != null) { - String title = (String) dbObject.get(FieldNames.IMAGE_TITLE.name()); - String subtitle = (String) dbObject.get(FieldNames.IMAGE_SUBTITLE.name()); - String copyright = (String) dbObject.get(FieldNames.IMAGE_COPYRIGHT.name()); - //Object mimeTypeRaw = dbObject.get(FieldNames.IMAGE_MIMETYPE.name()); - //MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); - Integer imageWidth = (Integer) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); - Integer imageHeight = (Integer) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); - TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.IMAGE_CREATEDATDATE); - BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.IMAGE_TAGS.name()); - List imageTags = new ArrayList(); - if (tags != null) { - for (Object tagObject : tags) { - imageTags.add((String) tagObject); - } - } - image = new ImageDescriptorImpl(imageURL, createdAtDate); - image.setCopyright(copyright); - image.setTitle(title); - image.setSubtitle(subtitle); - image.setTags(imageTags); - if (imageWidth != null && imageHeight != null) { - image.setSize(imageWidth, imageHeight); - } - } - return image; - } - - private VideoDescriptor loadVideo(DBObject dbObject) { - VideoDescriptor video = null; - URL videoURL = loadURL(dbObject, FieldNames.VIDEO_URL); - if(videoURL != null) { - String title = (String) dbObject.get(FieldNames.VIDEO_TITLE.name()); - String subtitle = (String) dbObject.get(FieldNames.VIDEO_SUBTITLE.name()); - String copyright = (String) dbObject.get(FieldNames.VIDEO_COPYRIGHT.name()); - Object mimeTypeRaw = dbObject.get(FieldNames.VIDEO_MIMETYPE.name()); - MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); - TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.VIDEO_CREATEDATDATE); - BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.VIDEO_TAGS.name()); - Integer lengthInSeconds = (Integer) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); - URL thumbnailURL = loadURL(dbObject, FieldNames.VIDEO_THUMBNAIL_URL); - List videoTags = new ArrayList(); - if (tags != null) { - for (Object tagObject : tags) { - videoTags.add((String) tagObject); - } - } - video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate); - video.setCopyright(copyright); - video.setTitle(title); - video.setSubtitle(subtitle); - video.setTags(videoTags); - video.setLengthInSeconds(lengthInSeconds); - video.setThumbnailURL(thumbnailURL); - } - return video; - } - - private URL loadURL(DBObject dbObject, FieldNames field) { - URL result = null; - String urlAsString = (String) dbObject.get(field.name()); - if(urlAsString != null) { - try { - result = new URL(urlAsString); - } catch (MalformedURLException e) { - logger.severe("Error parsing URL '"+urlAsString+"' in field "+field.name()+"."); - } - } - return result; - } - - /** - * Migrates images and videos stored as pure URLs to the new richer format once - * @param event the event to migrate - */ - private void migrateImagesAndVideosOfEvent(Event event) { - int amountOfURLbasedImagesAndVideos = Util.size(event.getImageURLs()) + Util.size(event.getSponsorImageURLs()) + Util.size(event.getVideoURLs()); - int amountOfImagesAndVideos = Util.size(event.getImages()) + Util.size(event.getVideos()); - boolean migrationRequired = amountOfURLbasedImagesAndVideos > 0 && amountOfImagesAndVideos == 0; - if(migrationRequired) { - for(URL url: event.getImageURLs()) { - String urlAsString = url.toString(); - ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); - if(urlAsString.indexOf("stage") > 0) { - image.addTag("Stage"); - } else if(urlAsString.indexOf("eventteaser") > 0) { - image.addTag("Teaser"); - } - event.addImage(image); - } - for(URL url: event.getSponsorImageURLs()) { - ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); - image.addTag("Sponsor"); - event.addImage(image); - } - for(URL url: event.getVideoURLs()) { - VideoDescriptor video = new VideoDescriptorImpl(url, MimeType.unknown, MillisecondsTimePoint.now()); - event.addVideo(video); - } - new MongoObjectFactoryImpl(database).storeEvent(event); - } - } -} +package com.sap.sailing.domain.persistence.impl; + +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.bson.types.ObjectId; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import com.mongodb.BasicDBList; +import com.mongodb.BasicDBObject; +import com.mongodb.BasicDBObjectBuilder; +import com.mongodb.DB; +import com.mongodb.DBCollection; +import com.mongodb.DBCursor; +import com.mongodb.DBObject; +import com.mongodb.MongoException; +import com.mongodb.WriteResult; +import com.mongodb.util.JSON; +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; +import com.sap.sailing.domain.abstractlog.race.CompetitorResults; +import com.sap.sailing.domain.abstractlog.race.FixedMarkPassingEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogEventRestoreFactory; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent; +import com.sap.sailing.domain.abstractlog.race.SuppressedMarkPassingsEvent; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl; +import com.sap.sailing.domain.abstractlog.race.scoring.AdditionalScoringInformationType; +import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRevokeEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnTimeFactorEventImpl; +import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.ControlPoint; +import com.sap.sailing.domain.base.ControlPointWithTwoMarks; +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.base.DomainFactory; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.base.RegattaRegistry; +import com.sap.sailing.domain.base.RemoteSailingServerReference; +import com.sap.sailing.domain.base.Series; +import com.sap.sailing.domain.base.Venue; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationImpl; +import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; +import com.sap.sailing.domain.base.impl.CourseDataImpl; +import com.sap.sailing.domain.base.impl.EventImpl; +import com.sap.sailing.domain.base.impl.FleetImpl; +import com.sap.sailing.domain.base.impl.RegattaImpl; +import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; +import com.sap.sailing.domain.base.impl.SeriesImpl; +import com.sap.sailing.domain.base.impl.VenueImpl; +import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.MarkType; +import com.sap.sailing.domain.common.MaxPointsReason; +import com.sap.sailing.domain.common.PassingInstruction; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.RaceIdentifier; +import com.sap.sailing.domain.common.RankingMetrics; +import com.sap.sailing.domain.common.RegattaName; +import com.sap.sailing.domain.common.RegattaNameAndRaceName; +import com.sap.sailing.domain.common.ScoringSchemeType; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.common.WindSourceType; +import com.sap.sailing.domain.common.configuration.DeviceConfigurationMatcherType; +import com.sap.sailing.domain.common.impl.DegreeBearingImpl; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; +import com.sap.sailing.domain.common.impl.WindImpl; +import com.sap.sailing.domain.common.impl.WindSourceImpl; +import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID; +import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; +import com.sap.sailing.domain.common.racelog.RacingProcedureType; +import com.sap.sailing.domain.common.racelog.tracking.TransformationException; +import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections; +import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections.LeaderboardCorrectionsResolvedListener; +import com.sap.sailing.domain.leaderboard.EventResolver; +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; +import com.sap.sailing.domain.leaderboard.LeaderboardRegistry; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.domain.leaderboard.ScoringScheme; +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; +import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; +import com.sap.sailing.domain.leaderboard.impl.DelayedLeaderboardCorrectionsImpl; +import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; +import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; +import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; +import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; +import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; +import com.sap.sailing.domain.persistence.DomainObjectFactory; +import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory; +import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory; +import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; +import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; +import com.sap.sailing.domain.racelog.RaceLogIdentifier; +import com.sap.sailing.domain.racelog.RaceLogStore; +import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; +import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler; +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; +import com.sap.sailing.domain.ranking.RankingMetricConstructor; +import com.sap.sailing.domain.ranking.RankingMetricsFactory; +import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; +import com.sap.sailing.domain.regattalog.RegattaLogStore; +import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; +import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sailing.domain.tracking.impl.WindTrackImpl; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; +import com.sap.sailing.server.gateway.deserialization.impl.CompetitorJsonDeserializer; +import com.sap.sailing.server.gateway.deserialization.impl.DeviceConfigurationJsonDeserializer; +import com.sap.sailing.server.gateway.deserialization.impl.Helpers; +import com.sap.sailing.server.gateway.deserialization.impl.RegattaConfigurationJsonDeserializer; +import com.sap.sse.common.Color; +import com.sap.sse.common.Duration; +import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.TimeRange; +import com.sap.sse.common.TypeBasedServiceFinder; +import com.sap.sse.common.TypeBasedServiceFinderFactory; +import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.Util.Triple; +import com.sap.sse.common.impl.MillisecondsDurationImpl; +import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.impl.RGBColor; +import com.sap.sse.common.impl.TimeRangeImpl; +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; + +public class DomainObjectFactoryImpl implements DomainObjectFactory { + private static final Logger logger = Logger.getLogger(DomainObjectFactoryImpl.class.getName()); + private final CompetitorJsonDeserializer competitorDeserializer; + + private final DB database; + + private RaceLogEventRestoreFactory raceLogEventFactory; + private final DomainFactory baseDomainFactory; + private final TypeBasedServiceFinder deviceIdentifierServiceFinder; + private final TypeBasedServiceFinderFactory serviceFinderFactory; + + /** + * Uses null as the {@link TypeBasedServiceFinder}, meaning that no {@link DeviceIdentifier}s can be loaded + * using this instance of a {@link DomainObjectFactory}. + */ + public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory) { + this(db, baseDomainFactory, /* deviceTypeServiceFinder */ null); + } + + public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory, TypeBasedServiceFinderFactory serviceFinderFactory) { + super(); + this.serviceFinderFactory = serviceFinderFactory; + if (serviceFinderFactory != null) { + this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); + this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); + } else { + this.deviceIdentifierServiceFinder = null; + } + this.baseDomainFactory = baseDomainFactory; + this.competitorDeserializer = CompetitorJsonDeserializer.create(baseDomainFactory); + this.database = db; + this.raceLogEventFactory = RaceLogEventRestoreFactory.INSTANCE; + } + + @Override + public DomainFactory getBaseDomainFactory() { + return baseDomainFactory; + } + + public Wind loadWind(DBObject object) { + return new WindImpl(loadPosition(object), loadTimePoint(object), loadSpeedWithBearing(object)); + } + + public Position loadPosition(DBObject object) { + Number latNumber = (Number) object.get(FieldNames.LAT_DEG.name()); + Double lat = latNumber == null ? null : latNumber.doubleValue(); + Number lngNumber = (Number) object.get(FieldNames.LNG_DEG.name()); + Double lng = lngNumber == null ? null : lngNumber.doubleValue(); + if (lat != null && lng != null) { + return new DegreePosition(lat, lng); + } else { + return null; + } + } + + public static TimePoint loadTimePoint(DBObject object, String fieldName) { + TimePoint result = null; + Number timePointAsNumber = (Number) object.get(fieldName); + if (timePointAsNumber != null) { + result = new MillisecondsTimePoint(timePointAsNumber.longValue()); + } + return result; + } + + public static TimePoint loadTimePoint(DBObject object, FieldNames field) { + return loadTimePoint(object, field.name()); + } + + public static TimeRange loadTimeRange(DBObject object, FieldNames field) { + DBObject timeRangeObj = (DBObject) object.get(field.name()); + if (timeRangeObj == null) { + return null; + } + TimePoint from = loadTimePoint(timeRangeObj, FieldNames.FROM_MILLIS); + TimePoint to = loadTimePoint(timeRangeObj, FieldNames.TO_MILLIS); + return new TimeRangeImpl(from, to); + } + /** + * Loads a {@link TimePoint} on the given object at {@link FieldNames#TIME_AS_MILLIS}. + */ + public TimePoint loadTimePoint(DBObject object) { + return loadTimePoint(object, FieldNames.TIME_AS_MILLIS); + } + + public SpeedWithBearing loadSpeedWithBearing(DBObject object) { + return new KnotSpeedWithBearingImpl(((Number) object.get(FieldNames.KNOT_SPEED.name())).doubleValue(), + new DegreeBearingImpl(((Number) object.get(FieldNames.DEGREE_BEARING.name())).doubleValue())); + } + + @Override + public RaceIdentifier loadRaceIdentifier(DBObject dbObject) { + RaceIdentifier result = null; + String regattaName = (String) dbObject.get(FieldNames.EVENT_NAME.name()); + String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name()); + if (regattaName != null && raceName != null) { + result = new RegattaNameAndRaceName(regattaName, raceName); + } + return result; + } + + private void ensureIndicesOnWindTracks(DBCollection windTracks) { + windTracks.createIndex(new BasicDBObject(FieldNames.RACE_ID.name(), 1)); // for new programmatic access + windTracks.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); // for export or human look-up + // for legacy access to not yet migrated fixes + windTracks.createIndex(new BasicDBObjectBuilder().add(FieldNames.EVENT_NAME.name(), 1) + .add(FieldNames.RACE_NAME.name(), 1).get()); + // Unique index + try { + windTracks.createIndex( + new BasicDBObjectBuilder().add(FieldNames.RACE_ID.name(), 1) + .add(FieldNames.WIND_SOURCE_NAME.name(), 1).add(FieldNames.WIND_SOURCE_ID.name(), 1) + .add(FieldNames.WIND.name() + "." + FieldNames.TIME_AS_MILLIS.name(), 1).get(), + new BasicDBObjectBuilder().add("unique", true).add("dropDups", true).get()); + } catch (MongoException exception) { + + if (exception.getCode() == 10092) { + logger.warning(String.format( + "Setting the unique index on the %s collection failed because you have too many duplicates. " + + "This leads to the mongo error code %s and the following message: %s \nTo fix this follow " + + "the steps provided on the wiki page: http://wiki.sapsailing.com/wiki/cook-book#Remove-" + + "duplicates-from-WIND_TRACK-collection", CollectionNames.WIND_TRACKS.name(), + exception.getCode(), exception.getMessage())); + } else { + logger.severe(String.format( + "Setting the unique index on the %s collection failed with error code %s and message: %s", + CollectionNames.WIND_TRACKS.name(), exception.getCode(), exception.getMessage())); + } + } + } + + @Override + public Leaderboard loadLeaderboard(String name, RegattaRegistry regattaRegistry) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + Leaderboard result = null; + try { + BasicDBObject query = new BasicDBObject(); + query.put(FieldNames.LEADERBOARD_NAME.name(), name); + for (DBObject o : leaderboardCollection.find(query)) { + result = loadLeaderboard(o, regattaRegistry, /* leaderboardRegistry */ null, /* groupForMetaLeaderboard */ null); + } + } catch (Exception e) { + // something went wrong during DB access; report, then use empty new wind track + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard "+name+"."); + logger.log(Level.SEVERE, "loadLeaderboard", e); + } + return result; + } + + @Override + public Iterable getAllLeaderboards(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + Set result = new HashSet(); + try { + for (DBObject o : leaderboardCollection.find()) { + final Leaderboard loadedLeaderboard = loadLeaderboard(o, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ null); + if (loadedLeaderboard != null) { + result.add(loadedLeaderboard); + } + } + } catch (Exception e) { + // something went wrong during DB access; report, then use empty new wind track + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboards."); + logger.log(Level.SEVERE, "getAllLeaderboards", e); + } + return result; + } + + /** + * If the DBObject has a field {@link FieldNames#REGATTA_NAME} then the object represents a + * {@link RegattaLeaderboard}. Otherwise, a {@link FlexibleLeaderboard} will be loaded. + * + * @param leaderboardRegistry + * if not null, then before creating and loading the leaderboard it is looked up in this + * registry and only loaded if not found there. If leaderboardRegistry is null, + * the leaderboard is loaded in any case. If the leaderboard is loaded and + * leaderboardRegistry is not null, the leaderboard loaded is + * {@link LeaderboardRegistry#addLeaderboard(Leaderboard) added to the registry}. + * @param groupForMetaLeaderboard + * if not null, a {@link LeaderboardGroupMetaLeaderboard} instance is created and set as the + * group's {@link LeaderboardGroup#setOverallLeaderboard(Leaderboard) overall leaderboard} + * + * @return null in case the leaderboard couldn't be loaded, e.g., because the regatta referenced by a + * {@link RegattaLeaderboard} cannot be found; the leaderboard loaded or found in + * leaderboardRegistry, otherwise + */ + private Leaderboard loadLeaderboard(DBObject dbLeaderboard, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry, + LeaderboardGroup groupForMetaLeaderboard) { + Leaderboard result = null; + String leaderboardName = (String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name()); + if (leaderboardRegistry != null) { + result = leaderboardRegistry.getLeaderboardByName(leaderboardName); + } + if (result == null) { + ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbLeaderboard, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS); + String regattaName = (String) dbLeaderboard.get(FieldNames.REGATTA_NAME.name()); + if (groupForMetaLeaderboard != null) { + result = new LeaderboardGroupMetaLeaderboard(groupForMetaLeaderboard, + loadScoringScheme(dbLeaderboard), resultDiscardingRule); + groupForMetaLeaderboard.setOverallLeaderboard(result); + } else if (regattaName == null) { + result = loadFlexibleLeaderboard(dbLeaderboard, resultDiscardingRule); + } else { + result = loadRegattaLeaderboard(leaderboardName, regattaName, dbLeaderboard, resultDiscardingRule, regattaRegistry); + } + if (result != null) { + final Leaderboard finalResult = result; + finalResult.setDisplayName((String) dbLeaderboard.get(FieldNames.LEADERBOARD_DISPLAY_NAME.name())); + + DelayedLeaderboardCorrections loadedLeaderboardCorrections = new DelayedLeaderboardCorrectionsImpl(result, baseDomainFactory); + final boolean[] needsMigration = new boolean[1]; + loadedLeaderboardCorrections.addLeaderboardCorrectionsResolvedListener(new LeaderboardCorrectionsResolvedListener() { + @Override + public void correctionsResolved(DelayedLeaderboardCorrections delayedLeaderboardCorrections) { + if (needsMigration[0]) { + new MongoObjectFactoryImpl(database).storeLeaderboard(finalResult); + } + } + }); + needsMigration[0] = loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections, result.getScoreCorrection()) || needsMigration[0]; + needsMigration[0] = loadSuppressedCompetitors(dbLeaderboard, loadedLeaderboardCorrections) || needsMigration[0]; + loadColumnFactors(dbLeaderboard, result); + // add the leaderboard to the registry + if (leaderboardRegistry != null) { + leaderboardRegistry.addLeaderboard(result); + logger.info("loaded leaderboard "+result.getName()+" into "+leaderboardRegistry); + } + } + } + return result; + } + + private void loadColumnFactors(DBObject dbLeaderboard, Leaderboard result) { + DBObject dbColumnFactors = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMN_FACTORS.name()); + if (dbColumnFactors != null) { + for (String encodedRaceColumnName : dbColumnFactors.keySet()) { + double factor = ((Number) dbColumnFactors.get(encodedRaceColumnName)).doubleValue(); + String raceColumnName = MongoUtils.unescapeDollarAndDot(encodedRaceColumnName); + final RaceColumn raceColumn = result.getRaceColumnByName(raceColumnName); + if (raceColumn != null) { + raceColumn.setFactor(factor); + } else { + logger.warning("Expected to find race column named "+raceColumnName+" in leaderboard "+result.getName()+ + " to apply column factor "+factor+", but the race column wasn't found. Ignoring factor."); + } + } + } + } + + private boolean loadSuppressedCompetitors(DBObject dbLeaderboard, + DelayedLeaderboardCorrections loadedLeaderboardCorrections) { + final boolean needsMigration; + BasicDBList dbSuppressedCompetitorNames = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITORS.name()); + if (dbSuppressedCompetitorNames != null) { + needsMigration = true; + for (Object escapedCompetitorName : dbSuppressedCompetitorNames) { + loadedLeaderboardCorrections.suppressCompetitorByName(MongoUtils.unescapeDollarAndDot((String) escapedCompetitorName)); + } + } else { + needsMigration = false; + } + BasicDBList dbSuppressedCompetitorIDs = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name()); + if (dbSuppressedCompetitorIDs != null) { + for (Object competitorId : dbSuppressedCompetitorIDs) { + loadedLeaderboardCorrections.suppressCompetitorById((Serializable) competitorId); + } + } + return needsMigration; + } + + /** + * @param dbObject expects to find a field identified by field which holds a {@link BasicDBList} + */ + private ThresholdBasedResultDiscardingRule loadResultDiscardingRule(DBObject dbObject, FieldNames field) { + BasicDBList dbDiscardIndexResultsStartingWithHowManyRaces = (BasicDBList) dbObject.get(field.name()); + final ThresholdBasedResultDiscardingRule result; + if (dbDiscardIndexResultsStartingWithHowManyRaces == null) { + result = null; + } else { + int[] discardIndexResultsStartingWithHowManyRaces = new int[dbDiscardIndexResultsStartingWithHowManyRaces + .size()]; + int i = 0; + for (Object discardingThresholdAsObject : dbDiscardIndexResultsStartingWithHowManyRaces) { + discardIndexResultsStartingWithHowManyRaces[i++] = (Integer) discardingThresholdAsObject; + } + result = new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces); + } + return result; + } + + /** + * @return null if the regatta cannot be resolved; otherwise the leaderboard for the regatta specified + */ + private RegattaLeaderboard loadRegattaLeaderboard(String leaderboardName, String regattaName, DBObject dbLeaderboard, + ThresholdBasedResultDiscardingRule resultDiscardingRule, RegattaRegistry regattaRegistry) { + RegattaLeaderboard result = null; + Regatta regatta = regattaRegistry.getRegatta(new RegattaName(regattaName)); + if (regatta == null) { + logger.info("Couldn't find regatta "+regattaName+" for corresponding regatta leaderboard. Not loading regatta leaderboard."); + } else { + result = new RegattaLeaderboardImpl(regatta, resultDiscardingRule); + result.setName(leaderboardName); + } + return result; + } + + private RaceLogStore getRaceLogStore() { + return MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore( + new MongoObjectFactoryImpl(database, serviceFinderFactory), this); + } + + private RegattaLogStore getRegattaLogStore() { + return MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore( + new MongoObjectFactoryImpl(database, serviceFinderFactory), this); + } + + private FlexibleLeaderboard loadFlexibleLeaderboard(DBObject dbLeaderboard, + ThresholdBasedResultDiscardingRule resultDiscardingRule) { + final FlexibleLeaderboardImpl result; + BasicDBList dbRaceColumns = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMNS.name()); + if (dbRaceColumns == null) { + // this was probably an orphaned overall leaderboard + logger.warning("Probably found orphan overall leaderboard named " + + dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name())+". Ignoring."); + result = null; + } else { + final ScoringScheme scoringScheme = loadScoringScheme(dbLeaderboard); + + Serializable courseAreaId = (Serializable) dbLeaderboard.get(FieldNames.COURSE_AREA_ID.name()); + CourseArea courseArea = null; + if (courseAreaId != null) { + UUID courseAreaUuid = UUID.fromString(courseAreaId.toString()); + courseArea = baseDomainFactory.getExistingCourseAreaById(courseAreaUuid); + } + + result = new FlexibleLeaderboardImpl(getRaceLogStore(), getRegattaLogStore(), + (String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name()), + resultDiscardingRule, scoringScheme, courseArea); + // For a FlexibleLeaderboard, there should be only the default fleet for any race column + for (Object dbRaceColumnAsObject : dbRaceColumns) { + BasicDBObject dbRaceColumn = (BasicDBObject) dbRaceColumnAsObject; + String columnName = (String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name()); + + RaceColumn raceColumn = result.addRaceColumn(columnName, + (Boolean) dbRaceColumn.get(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name())); + + Map raceIdentifiers = loadRaceIdentifiers(dbRaceColumn); + RaceIdentifier defaultFleetRaceIdentifier = raceIdentifiers.get(result.getFleet(null).getName()); + if (defaultFleetRaceIdentifier == null) { + // Backward compatibility + defaultFleetRaceIdentifier = raceIdentifiers.get(null); + } + if (defaultFleetRaceIdentifier != null) { + Fleet defaultFleet = result.getFleet(null); + if (defaultFleet != null) { + + raceColumn.setRaceIdentifier(defaultFleet, defaultFleetRaceIdentifier); + } else { + // leaderboard has no default fleet; don't know what to do with default RaceIdentifier + logger.warning("Discarding RaceIdentifier " + defaultFleetRaceIdentifier + + " for default fleet for leaderboard " + result.getName() + + " because no default fleet was found in leaderboard"); + } + } + + } + } + return result; + } + + private ScoringScheme loadScoringScheme(DBObject dbLeaderboard) { + ScoringSchemeType scoringSchemeType = getScoringSchemeType(dbLeaderboard); + final ScoringScheme scoringScheme = baseDomainFactory.createScoringScheme(scoringSchemeType); + return scoringScheme; + } + + private boolean loadLeaderboardCorrections(DBObject dbLeaderboard, DelayedLeaderboardCorrections correctionsToUpdate, + SettableScoreCorrection scoreCorrectionToUpdate) { + boolean needsMigration = false; + DBObject carriedPoints = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_CARRIED_POINTS.name()); + if (carriedPoints != null) { + needsMigration = true; + for (String escapedCompetitorName : carriedPoints.keySet()) { + Double carriedPointsForCompetitor = ((Number) carriedPoints.get(escapedCompetitorName)).doubleValue(); + if (carriedPointsForCompetitor != null) { + correctionsToUpdate.setCarriedPointsByName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), carriedPointsForCompetitor); + } + } + } + BasicDBList carriedPointsById = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name()); + if (carriedPointsById != null) { + for (Object o : carriedPointsById) { + DBObject competitorIdAndCarriedPoints = (DBObject) o; + Serializable competitorId = (Serializable) competitorIdAndCarriedPoints.get(FieldNames.COMPETITOR_ID.name()); + Double carriedPointsForCompetitor = ((Number) competitorIdAndCarriedPoints + .get(FieldNames.LEADERBOARD_CARRIED_POINTS.name())).doubleValue(); + if (carriedPointsForCompetitor != null) { + correctionsToUpdate.setCarriedPointsByID(competitorId, carriedPointsForCompetitor); + } + } + } + DBObject dbScoreCorrection = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name()); + if (dbScoreCorrection.containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name())) { + scoreCorrectionToUpdate.setTimePointOfLastCorrectionsValidity( + new MillisecondsTimePoint((Long) dbScoreCorrection.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name()))); + dbScoreCorrection.removeField(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name()); + } + if (dbScoreCorrection.containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name())) { + scoreCorrectionToUpdate.setComment((String) dbScoreCorrection.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name())); + dbScoreCorrection.removeField(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name()); + } + for (String escapedRaceColumnName : dbScoreCorrection.keySet()) { + // deprecated style: a DBObject per race where the keys are the escaped competitor names + // new style: a BasicDBList per race where each entry is a DBObject with COMPETITOR_ID and + // LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON and LEADERBOARD_CORRECTED_SCORE fields each + DBObject dbScoreCorrectionForRace = (DBObject) dbScoreCorrection.get(escapedRaceColumnName); + final RaceColumn raceColumn = correctionsToUpdate.getLeaderboard().getRaceColumnByName(MongoUtils.unescapeDollarAndDot(escapedRaceColumnName)); + if (raceColumn != null) { + if (dbScoreCorrectionForRace instanceof BasicDBList) { + for (Object o : (BasicDBList) dbScoreCorrectionForRace) { + DBObject dbScoreCorrectionForCompetitorInRace = (DBObject) o; + Serializable competitorId = (Serializable) dbScoreCorrectionForCompetitorInRace + .get(FieldNames.COMPETITOR_ID.name()); + if (dbScoreCorrectionForCompetitorInRace + .containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())) { + correctionsToUpdate.setMaxPointsReasonByID(competitorId, raceColumn, MaxPointsReason + .valueOf((String) dbScoreCorrectionForCompetitorInRace + .get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()))); + } + if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_CORRECTED_SCORE + .name())) { + final Double leaderboardCorrectedScore = ((Number) dbScoreCorrectionForCompetitorInRace + .get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name())).doubleValue(); + correctionsToUpdate.correctScoreByID(competitorId, raceColumn, + (Double) leaderboardCorrectedScore); + } + } + } else { + needsMigration = true; + for (String competitorName : dbScoreCorrectionForRace.keySet()) { + DBObject dbScoreCorrectionForCompetitorInRace = (DBObject) dbScoreCorrectionForRace + .get(competitorName); + if (dbScoreCorrectionForCompetitorInRace + .containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())) { + correctionsToUpdate.setMaxPointsReasonByName(MongoUtils + .unescapeDollarAndDot(competitorName), raceColumn, MaxPointsReason + .valueOf((String) dbScoreCorrectionForCompetitorInRace + .get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()))); + } + if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_CORRECTED_SCORE + .name())) { + final Double leaderboardCorrectedScore = ((Number) dbScoreCorrectionForCompetitorInRace + .get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name())).doubleValue(); + correctionsToUpdate.correctScoreByName(MongoUtils.unescapeDollarAndDot(competitorName), + raceColumn, (Double) leaderboardCorrectedScore); + } + } + } + } else { + logger.warning("Couldn't find race column " + MongoUtils.unescapeDollarAndDot(escapedRaceColumnName) + + " in leaderboard " + correctionsToUpdate.getLeaderboard().getName()); + } + } + DBObject competitorDisplayNames = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name()); + // deprecated style: a DBObject whose keys are the escaped competitor names + // new style: a BasicDBList whose entries are DBObjects with COMPETITOR_ID and COMPETITOR_DISPLAY_NAME fields + if (competitorDisplayNames != null) { + if (competitorDisplayNames instanceof BasicDBList) { + for (Object o : (BasicDBList) competitorDisplayNames) { + DBObject competitorDisplayName = (DBObject) o; + final Serializable competitorId = (Serializable) competitorDisplayName.get(FieldNames.COMPETITOR_ID.name()); + final String displayName = (String) competitorDisplayName.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); + correctionsToUpdate.setDisplayNameByID(competitorId, displayName); + } + } else { + needsMigration = true; + for (String escapedCompetitorName : competitorDisplayNames.keySet()) { + correctionsToUpdate.setDisplayNameByName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), + (String) competitorDisplayNames.get(escapedCompetitorName)); + } + } + } + return needsMigration; + } + + /** + * Expects a DBObject under the key {@link FieldNames#RACE_IDENTIFIERS} whose keys are the fleet names and whose + * values are the race identifiers as DBObjects (see {@link #loadRaceIdentifier(DBObject)}). If legacy DB instances + * have a {@link RaceIdentifier} that is not associated with a fleet name, it may be stored directly in the + * dbRaceColumn. In this case, it is returned with null as the fleet name key. + * + * @return a map with fleet names as key and the corresponding fleet's race identifier as value; the special + * null key is used to identify a "default fleet" for backward compatibility with stored + * leaderboards which don't know about fleets yet; this key should be mapped to the leaderboard's default + * fleet. + */ + private Map loadRaceIdentifiers(DBObject dbRaceColumn) { + Map result = new HashMap(); + // try to load a deprecated single race identifier to associate with the default fleet: + RaceIdentifier singleLegacyRaceIdentifier = loadRaceIdentifier(dbRaceColumn); + if (singleLegacyRaceIdentifier != null) { + result.put(null, singleLegacyRaceIdentifier); + } + DBObject raceIdentifiersPerFleet = (DBObject) dbRaceColumn.get(FieldNames.RACE_IDENTIFIERS.name()); + if (raceIdentifiersPerFleet != null) { + for (String escapedFleetName : raceIdentifiersPerFleet.keySet()) { + String fleetName = MongoUtils.unescapeDollarAndDot(escapedFleetName); + result.put(fleetName, loadRaceIdentifier((DBObject) raceIdentifiersPerFleet.get(fleetName))); + } + } + return result; + } + + @Override + public LeaderboardGroup loadLeaderboardGroup(String name, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); + LeaderboardGroup leaderboardGroup = null; + try { + BasicDBObject query = new BasicDBObject(); + query.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), name); + leaderboardGroup = loadLeaderboardGroup(leaderboardGroupCollection.findOne(query), regattaRegistry, leaderboardRegistry); + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard group "+name+"."); + logger.log(Level.SEVERE, "loadLeaderboardGroup", e); + } + + return leaderboardGroup; + } + + @Override + public Iterable getAllLeaderboardGroups(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); + Set leaderboardGroups = new HashSet(); + try { + for (DBObject o : leaderboardGroupCollection.find()) { + boolean hasUUID = o.containsField(FieldNames.LEADERBOARD_GROUP_UUID.name()); + final LeaderboardGroup leaderboardGroup = loadLeaderboardGroup(o, regattaRegistry, leaderboardRegistry); + leaderboardGroups.add(leaderboardGroup); + if (!hasUUID) { + // in an effort to migrate leaderboard groups without ID to such that have a UUID as their ID, we need + // to write a leaderboard group to the database again after it just received a UUID for the first time: + logger.info("Existing LeaderboardGroup " + leaderboardGroup.getName() + + " received a UUID during migration; updating the leaderboard group in the database"); + new MongoObjectFactoryImpl(database).storeLeaderboardGroup(leaderboardGroup); + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard groups."); + logger.log(Level.SEVERE, "loadLeaderboardGroup", e); + } + + return leaderboardGroups; + } + + private LeaderboardGroup loadLeaderboardGroup(DBObject o, RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + String name = (String) o.get(FieldNames.LEADERBOARD_GROUP_NAME.name()); + UUID uuid = (UUID) o.get(FieldNames.LEADERBOARD_GROUP_UUID.name()); + if (uuid == null) { + uuid = UUID.randomUUID(); + logger.info("Leaderboard group "+name+" receives UUID "+uuid+" in a migration effort"); + // migration: leaderboard groups that don't yet have a UUID receive a random one + } + String description = (String) o.get(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name()); + String displayName = (String) o.get(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name()); + boolean displayGroupsInReverseOrder = false; // default value + Object displayGroupsInReverseOrderObj = o.get(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name()); + if (displayGroupsInReverseOrderObj != null) { + displayGroupsInReverseOrder = (Boolean) displayGroupsInReverseOrderObj; + } + ArrayList leaderboards = new ArrayList(); + BasicDBList dbLeaderboardIds = (BasicDBList) o.get(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name()); + for (Object object : dbLeaderboardIds) { + ObjectId dbLeaderboardId = (ObjectId) object; + DBObject dbLeaderboard = leaderboardCollection.findOne(dbLeaderboardId); + if (dbLeaderboard != null) { + final Leaderboard loadedLeaderboard = loadLeaderboard(dbLeaderboard, regattaRegistry, + leaderboardRegistry, /* groupForMetaLeaderboard */null); + if (loadedLeaderboard != null) { + leaderboards.add(loadedLeaderboard); + } + } else { + logger.warning("couldn't find leaderboard with ID "+dbLeaderboardId+" referenced by leaderboard group "+name); + } + } + logger.info("loaded leaderboard group "+name); + LeaderboardGroupImpl result = new LeaderboardGroupImpl(uuid, name, description, displayName, displayGroupsInReverseOrder, leaderboards); + Object overallLeaderboardIdOrName = o.get(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name()); + if (overallLeaderboardIdOrName != null) { + final DBObject dbOverallLeaderboard; + if (overallLeaderboardIdOrName instanceof ObjectId) { + dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardIdOrName); + } else { + dbOverallLeaderboard = (DBObject) overallLeaderboardIdOrName; + } + if (dbOverallLeaderboard != null) { + // the loadLeaderboard call adds the overall leaderboard to the leaderboard registry and sets it as the + // overall leaderboard of the leaderboard group + loadLeaderboard(dbOverallLeaderboard, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ result); + } + } + return result; + } + + @Override + public Iterable getLeaderboardsNotInGroup(RegattaRegistry regattaRegistry, LeaderboardRegistry leaderboardRegistry) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + Set result = new HashSet(); + try { + // For MongoDB 2.4 $where with refs to global objects no longer works + // http://docs.mongodb.org/manual/reference/operator/where/#op._S_where + // Also a single where leads to a table walk without using indexes. So avoid $where. + + // Don't change the query object, unless you know what you're doing. + // It queries all leaderboards not referenced to be part of a leaderboard group + // and in particular not being an overall leaderboard of a leaderboard group. + DBCursor allLeaderboards = leaderboardCollection.find(); + for (DBObject leaderboardFromDB : allLeaderboards) { + DBObject inLeaderboardGroupsQuery = new BasicDBObject(); + inLeaderboardGroupsQuery.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), ((ObjectId)leaderboardFromDB.get("_id")).toString()); + boolean inLeaderboardGroups = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupsQuery).size()>0; + + DBObject inLeaderboardGroupOverallQuery = new BasicDBObject(); + inLeaderboardGroupOverallQuery.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), ((ObjectId)leaderboardFromDB.get("_id")).toString()); + boolean inLeaderboardGroupOverall = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupOverallQuery).size()>0; + + DBObject inLeaderboardGroupOverallQueryName = new BasicDBObject(); + inLeaderboardGroupOverallQueryName.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), leaderboardFromDB.get(FieldNames.LEADERBOARD_NAME.name())); + boolean inLeaderboardGroupOverallName = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()).find(inLeaderboardGroupOverallQueryName).size()>0; + + if (!inLeaderboardGroups && !inLeaderboardGroupOverall && !inLeaderboardGroupOverallName) { + final Leaderboard loadedLeaderboard = loadLeaderboard(leaderboardFromDB, regattaRegistry, leaderboardRegistry, /* groupForMetaLeaderboard */ null); + if (loadedLeaderboard != null) { + result.add(loadedLeaderboard); + } + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboards."); + logger.log(Level.SEVERE, "getAllLeaderboards", e); + } + return result; + } + + @Override + public WindTrack loadWindTrack(String regattaName, RaceDefinition race, WindSource windSource, long millisecondsOverWhichToAverage) { + final WindTrack result; + Map resultMap = loadWindTracks(regattaName, race, windSource, millisecondsOverWhichToAverage); + if (resultMap.containsKey(windSource)) { + result = resultMap.get(windSource); + } else { + // create an empty wind track as result if no fixes were found in store for the wind source requested + result = new WindTrackImpl(millisecondsOverWhichToAverage, windSource.getType().getBaseConfidence(), + windSource.getType().useSpeed(), + /* nameForReadWriteLock */ WindTrackImpl.class.getSimpleName()+" for source "+windSource.toString()); + } + return result; + } + + @Override + public Map loadWindTracks(String regattaName, RaceDefinition race, + long millisecondsOverWhichToAverageWind) { + Map result = loadWindTracks(regattaName, race, /* constrain wind source */ null, millisecondsOverWhichToAverageWind); + return result; + } + + /** + * @param constrainToWindSource + * if null, wind for all sources will be loaded; otherwise, only wind data for the wind + * source specified by this argument will be loaded + */ + private Map loadWindTracks(String regattaName, RaceDefinition race, + WindSource constrainToWindSource, long millisecondsOverWhichToAverageWind) { + Map result = new HashMap(); + try { + DBCollection windTracks = database.getCollection(CollectionNames.WIND_TRACKS.name()); + ensureIndicesOnWindTracks(windTracks); + BasicDBObject queryById = new BasicDBObject(); + // the default query is by the RACE_ID key: + queryById.put(FieldNames.RACE_ID.name(), race.getId()); + if (constrainToWindSource != null) { + queryById.put(FieldNames.WIND_SOURCE_NAME.name(), constrainToWindSource.name()); + } + for (DBObject dbWind : windTracks.find(queryById)) { + loadWindFix(result, dbWind, millisecondsOverWhichToAverageWind); + } + // Additionally check for legacy wind fixes stored with the old EVENT_NAME key; if any are found, migrate them + BasicDBObject queryByName = new BasicDBObject(); + queryByName.put(FieldNames.EVENT_NAME.name(), regattaName); + queryByName.put(FieldNames.RACE_NAME.name(), race.getName()); + if (constrainToWindSource != null) { + queryByName.put(FieldNames.WIND_SOURCE_NAME.name(), constrainToWindSource.name()); + } + final DBCursor windFixesFoundByName = windTracks.find(queryByName); + if (windFixesFoundByName.hasNext()) { + List windFixesToMigrate = new ArrayList(); + for (DBObject dbWind : windFixesFoundByName) { + Util.Pair wind = loadWindFix(result, dbWind, millisecondsOverWhichToAverageWind); + // write the wind fix with the new ID-based key and remove the legacy wind fix from the DB + windFixesToMigrate.add(new MongoObjectFactoryImpl(database).storeWindTrackEntry(race, regattaName, + wind.getB(), wind.getA())); + } + logger.info("Migrating "+windFixesFoundByName.size()+" wind fixes of regatta "+regattaName+ + " and race "+race.getName()+" to ID-based keys"); + windTracks.insert(windFixesToMigrate.toArray(new DBObject[windFixesToMigrate.size()])); + logger.info("Removing "+windFixesFoundByName.size()+" wind fixes that were keyed by the names of regatta "+regattaName+ + " and race "+race.getName()); + windTracks.remove(queryByName); + } + } catch (Exception e) { + // something went wrong during DB access; report, then use empty new wind track + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded wind data. Check MongoDB settings."); + logger.log(Level.SEVERE, "loadWindTrack", e); + } + return result; + } + + private Util.Pair loadWindFix(Map result, DBObject dbWind, long millisecondsOverWhichToAverageWind) { + Wind wind = loadWind((DBObject) dbWind.get(FieldNames.WIND.name())); + WindSourceType windSourceType = WindSourceType.valueOf((String) dbWind.get(FieldNames.WIND_SOURCE_NAME.name())); + WindSource windSource; + if (dbWind.containsField(FieldNames.WIND_SOURCE_ID.name())) { + windSource = new WindSourceWithAdditionalID(windSourceType, (String) dbWind.get(FieldNames.WIND_SOURCE_ID.name())); + } else { + windSource = new WindSourceImpl(windSourceType); + } + WindTrack track = result.get(windSource); + if (track == null) { + track = new WindTrackImpl(millisecondsOverWhichToAverageWind, windSource.getType().getBaseConfidence(), + windSource.getType().useSpeed(), + /* nameForReadWriteLock */ WindTrackImpl.class.getSimpleName()+" for source "+windSource.toString()); + result.put(windSource, track); + } + track.add(wind); + return new Util.Pair(wind, windSource); + } + + @Override + public void loadLeaderboardGroupLinksForEvents(EventResolver eventResolver, + LeaderboardGroupResolver leaderboardGroupResolver) { + DBCollection links = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name()); + for (Object o : links.find()) { + DBObject dbLink = (DBObject) o; + UUID eventId = (UUID) dbLink.get(FieldNames.EVENT_ID.name()); + Event event = eventResolver.getEvent(eventId); + if (event == null) { + logger.info("Found leaderboard group IDs for event with ID "+eventId+" but couldn't find that event."); + } else { + @SuppressWarnings("unchecked") + List leaderboardGroupIDs = (List) dbLink.get(FieldNames.LEADERBOARD_GROUP_UUID.name()); + for (UUID leaderboardGroupID : leaderboardGroupIDs) { + LeaderboardGroup leaderboardGroup = leaderboardGroupResolver.getLeaderboardGroupByID(leaderboardGroupID); + if (leaderboardGroup != null) { + event.addLeaderboardGroup(leaderboardGroup); + } + } + } + } + } + + @Override + public Event loadEvent(String name) { + Event result; + BasicDBObject query = new BasicDBObject(); + query.put(FieldNames.EVENT_NAME.name(), name); + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); + DBObject eventDBObject = eventCollection.findOne(query); + if (eventDBObject != null) { + result = loadEvent(eventDBObject); + } else { + result = null; + } + return result; + } + + @Override + public Iterable loadAllEvents() { + ArrayList result = new ArrayList(); + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); + + try { + for (DBObject object : eventCollection.find()) { + Event event = loadEvent(object); + migrateImagesAndVideosOfEvent(event); + result.add(event); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load events."); + logger.log(Level.SEVERE, "loadAllEvents", e); + } + + return result; + } + + + private RemoteSailingServerReference loadSailingSever(DBObject serverDBObject) { + RemoteSailingServerReference result = null; + String name = (String) serverDBObject.get(FieldNames.SERVER_NAME.name()); + String urlAsString = (String) serverDBObject.get(FieldNames.SERVER_URL.name()); + try { + URL serverUrl = new URL(urlAsString); + result = new RemoteSailingServerReferenceImpl(name, serverUrl); + } catch (MalformedURLException e) { + logger.log(Level.SEVERE, "Can't load the sailing server with URL " + urlAsString, e); + } + return result; + } + + @Override + public Iterable loadAllRemoteSailingServerReferences() { + ArrayList result = new ArrayList(); + DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); + try { + for (DBObject o : serverCollection.find()) { + if (loadSailingSever(o) != null) { + result.add(loadSailingSever(o)); + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load sailing server instances URLs."); + logger.log(Level.SEVERE, "loadAllSailingServers", e); + } + return result; + } + + /** + * An event doesn't store its regattas; it's the regatta that stores a reference to its event; the regatta + * needs to add itself to the event when loaded or instantiated. + */ + private Event loadEvent(DBObject eventDBObject) { + String name = (String) eventDBObject.get(FieldNames.EVENT_NAME.name()); + String description = (String) eventDBObject.get(FieldNames.EVENT_DESCRIPTION.name()); + UUID id = (UUID) eventDBObject.get(FieldNames.EVENT_ID.name()); + TimePoint startDate = loadTimePoint(eventDBObject, FieldNames.EVENT_START_DATE); + TimePoint endDate = loadTimePoint(eventDBObject, FieldNames.EVENT_END_DATE); + boolean isPublic = eventDBObject.get(FieldNames.EVENT_IS_PUBLIC.name()) != null ? (Boolean) eventDBObject.get(FieldNames.EVENT_IS_PUBLIC.name()) : false; + Venue venue = loadVenue((DBObject) eventDBObject.get(FieldNames.VENUE.name())); + Event result = new EventImpl(name, startDate, endDate, venue, isPublic, id); + result.setDescription(description); + String officialWebSiteURLAsString = (String) eventDBObject.get(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name()); + if (officialWebSiteURLAsString != null) { + try { + result.setOfficialWebsiteURL(new URL(officialWebSiteURLAsString)); + } catch (MalformedURLException e) { + logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL."); + } + } + String logoImageURLAsString = (String) eventDBObject.get(FieldNames.EVENT_LOGO_IMAGE_URL.name()); + if (logoImageURLAsString != null) { + try { + result.setLogoImageURL(new URL(logoImageURLAsString)); + } catch (MalformedURLException e) { + logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+name+". Ignoring this URL."); + } + } + BasicDBList imageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); + if (imageURLs != null) { + for (Object imageURL : imageURLs) { + try { + result.addImageURL(new URL((String) imageURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing image URL "+imageURL+" for event "+name+". Ignoring this image URL."); + } + } + } + BasicDBList videoURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); + if (videoURLs != null) { + for (Object videoURL : videoURLs) { + try { + result.addVideoURL(new URL((String) videoURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing video URL "+videoURL+" for event "+name+". Ignoring this video URL."); + } + } + } + BasicDBList sponsorImageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); + if (sponsorImageURLs != null) { + for (Object sponsorImageURL : sponsorImageURLs) { + try { + result.addSponsorImageURL(new URL((String) sponsorImageURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing sponsor image URL "+sponsorImageURL+" for event "+name+". Ignoring this sponsor image URL."); + } + } + } + BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); + if (images != null) { + for (Object imageObject : images) { + ImageDescriptor image = loadImage((DBObject) imageObject); + if (image != null) { + result.addImage(image); + } + } + } + BasicDBList videos = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEOS.name()); + if (videos != null) { + for (Object videoObject : videos) { + VideoDescriptor video = loadVideo((DBObject) videoObject); + if (video != null) { + result.addVideo(video); + } + } + } + return result; + } + + private Venue loadVenue(DBObject dbObject) { + String name = (String) dbObject.get(FieldNames.VENUE_NAME.name()); + BasicDBList dbCourseAreas = (BasicDBList) dbObject.get(FieldNames.COURSE_AREAS.name()); + Venue result = new VenueImpl(name); + for (Object courseAreaDBObject : dbCourseAreas) { + CourseArea courseArea = loadCourseArea((DBObject) courseAreaDBObject); + result.addCourseArea(courseArea); + } + return result; + } + + private CourseArea loadCourseArea(DBObject courseAreaDBObject) { + String name = (String) courseAreaDBObject.get(FieldNames.COURSE_AREA_NAME.name()); + UUID id = (UUID) courseAreaDBObject.get(FieldNames.COURSE_AREA_ID.name()); + return baseDomainFactory.getOrCreateCourseArea(id, name); + } + + @Override + public Iterable loadAllRegattas(TrackedRegattaRegistry trackedRegattaRegistry) { + List result = new ArrayList(); + DBCollection regattaCollection = database.getCollection(CollectionNames.REGATTAS.name()); + for (DBObject dbRegatta : regattaCollection.find()) { + result.add(loadRegatta(dbRegatta, trackedRegattaRegistry)); + } + return result; + } + + @Override + public Regatta loadRegatta(String name, TrackedRegattaRegistry trackedRegattaRegistry) { + DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), name); + DBCollection regattaCollection = database.getCollection(CollectionNames.REGATTAS.name()); + DBObject dbRegatta = regattaCollection.findOne(query); + Regatta result = loadRegatta(dbRegatta, trackedRegattaRegistry); + assert result == null || result.getName().equals(name); + return result; + } + + private Regatta loadRegatta(DBObject dbRegatta, TrackedRegattaRegistry trackedRegattaRegistry) { + Regatta result = null; + if (dbRegatta != null) { + String name = (String) dbRegatta.get(FieldNames.REGATTA_NAME.name()); + String boatClassName = (String) dbRegatta.get(FieldNames.BOAT_CLASS_NAME.name()); + TimePoint startDate = loadTimePoint(dbRegatta, FieldNames.REGATTA_START_DATE); + TimePoint endDate = loadTimePoint(dbRegatta, FieldNames.REGATTA_END_DATE); + Serializable id = (Serializable) dbRegatta.get(FieldNames.REGATTA_ID.name()); + if (id == null) { + id = name; + } + BoatClass boatClass = null; + if (boatClassName != null) { + boolean typicallyStartsUpwind = (Boolean) dbRegatta.get(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name()); + boatClass = baseDomainFactory.getOrCreateBoatClass(boatClassName, typicallyStartsUpwind); + } + BasicDBList dbSeries = (BasicDBList) dbRegatta.get(FieldNames.REGATTA_SERIES.name()); + Iterable series = loadSeries(dbSeries, trackedRegattaRegistry); + Serializable courseAreaId = (Serializable) dbRegatta.get(FieldNames.COURSE_AREA_ID.name()); + CourseArea courseArea = null; + if (courseAreaId != null) { + UUID courseAreaUuid = UUID.fromString(courseAreaId.toString()); + courseArea = baseDomainFactory.getExistingCourseAreaById(courseAreaUuid); + } + RegattaConfiguration configuration = null; + if (dbRegatta.containsField(FieldNames.REGATTA_REGATTA_CONFIGURATION.name())) { + try { + JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(dbRegatta.get(FieldNames.REGATTA_REGATTA_CONFIGURATION.name())))); + configuration = RegattaConfigurationJsonDeserializer.create().deserialize(json); + } catch (JsonDeserializationException|ParseException e) { + logger.log(Level.WARNING, "Error loading racing procedure configration for regatta.", e); + } + } + final Boolean useStartTimeInference = (Boolean) dbRegatta.get(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name()); + final RankingMetricConstructor rankingMetricConstructor = loadRankingMetricConstructor(dbRegatta); + result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, boatClass, startDate, endDate, series, /* persistent */true, + loadScoringScheme(dbRegatta), id, courseArea, useStartTimeInference == null ? true + : useStartTimeInference, rankingMetricConstructor); + result.setRegattaConfiguration(configuration); + } + return result; + } + + private RankingMetricConstructor loadRankingMetricConstructor(DBObject dbRegatta) { + DBObject rankingMetricJson = (DBObject) dbRegatta.get(FieldNames.REGATTA_RANKING_METRIC.name()); + // default is OneDesignRankingMetric + final RankingMetricConstructor result; + if (rankingMetricJson == null) { + result = OneDesignRankingMetric::new; + } else { + final String rankingMetricTypeName = (String) rankingMetricJson.get(FieldNames.REGATTA_RANKING_METRIC_TYPE.name()); + result = RankingMetricsFactory.getRankingMetricConstructor(RankingMetrics.valueOf(rankingMetricTypeName)); + } + return result; + } + + private ScoringSchemeType getScoringSchemeType(DBObject dbObject) { + String scoringSchemeTypeName = (String) dbObject.get(FieldNames.SCORING_SCHEME_TYPE.name()); + ScoringSchemeType scoringSchemeType; + if (scoringSchemeTypeName == null) { + scoringSchemeType = ScoringSchemeType.LOW_POINT; // the default + } else { + try { + scoringSchemeType = ScoringSchemeType.valueOf(scoringSchemeTypeName); + } catch (IllegalArgumentException ila) { + // can happen that the database contains a scoring scheme that + // has not yet been implemented - fall back with a warning + scoringSchemeType = ScoringSchemeType.LOW_POINT; + logger.warning("Could not find scoring scheme " + scoringSchemeTypeName + "! Most probably this has not yet been implemented or even been removed."); + } + } + return scoringSchemeType; + } + + private Iterable loadSeries(BasicDBList dbSeries, TrackedRegattaRegistry trackedRegattaRegistry) { + List result = new ArrayList(); + for (Object o : dbSeries) { + DBObject oneDBSeries = (DBObject) o; + Series series = loadSeries(oneDBSeries, trackedRegattaRegistry); + result.add(series); + } + return result; + } + + private Series loadSeries(DBObject dbSeries, TrackedRegattaRegistry trackedRegattaRegistry) { + String name = (String) dbSeries.get(FieldNames.SERIES_NAME.name()); + boolean isMedal = (Boolean) dbSeries.get(FieldNames.SERIES_IS_MEDAL.name()); + Boolean startsWithZeroScore = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name()); + Boolean hasSplitFleetContiguousScoring = (Boolean) dbSeries.get(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name()); + Boolean firstColumnIsNonDiscardableCarryForward = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name()); + final BasicDBList dbFleets = (BasicDBList) dbSeries.get(FieldNames.SERIES_FLEETS.name()); + List fleets = loadFleets(dbFleets); + BasicDBList dbRaceColumns = (BasicDBList) dbSeries.get(FieldNames.SERIES_RACE_COLUMNS.name()); + Iterable raceColumnNames = loadRaceColumnNames(dbRaceColumns); + Series series = new SeriesImpl(name, isMedal, fleets, raceColumnNames, trackedRegattaRegistry); + if (dbSeries.get(FieldNames.SERIES_DISCARDING_THRESHOLDS.name()) != null) { + ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbSeries, FieldNames.SERIES_DISCARDING_THRESHOLDS); + series.setResultDiscardingRule(resultDiscardingRule); + } + if (startsWithZeroScore != null) { + series.setStartsWithZeroScore(startsWithZeroScore); + } + if (hasSplitFleetContiguousScoring != null) { + series.setSplitFleetContiguousScoring(hasSplitFleetContiguousScoring); + } + if (firstColumnIsNonDiscardableCarryForward != null) { + series.setFirstColumnIsNonDiscardableCarryForward(firstColumnIsNonDiscardableCarryForward); + } + loadRaceColumnRaceLinks(dbRaceColumns, series); + return series; + } + + private Iterable loadRaceColumnNames(BasicDBList dbRaceColumns) { + List result = new ArrayList(); + for (Object o : dbRaceColumns) { + DBObject dbRaceColumn = (DBObject) o; + result.add((String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name())); + } + return result; + } + + private void loadRaceColumnRaceLinks(BasicDBList dbRaceColumns, Series series) { + for (Object o : dbRaceColumns) { + DBObject dbRaceColumn = (DBObject) o; + String name = (String) dbRaceColumn.get(FieldNames.LEADERBOARD_COLUMN_NAME.name()); + Map raceIdentifiersPerFleetName = loadRaceIdentifiers(dbRaceColumn); + for (Map.Entry e : raceIdentifiersPerFleetName.entrySet()) { + // null key for "default" fleet is not acceptable here + if (e.getKey() == null) { + logger.warning("Ignoring null fleet name while loading RaceColumn " + name); + } else { + series.getRaceColumnByName(name).setRaceIdentifier(series.getFleetByName(e.getKey()), e.getValue()); + } + } + } + } + + private List loadFleets(BasicDBList dbFleets) { + List result = new ArrayList(); + for (Object o : dbFleets) { + DBObject dbFleet = (DBObject) o; + Fleet fleet = loadFleet(dbFleet); + result.add(fleet); + } + return result; + } + + private Fleet loadFleet(DBObject dbFleet) { + Fleet result; + String name = (String) dbFleet.get(FieldNames.FLEET_NAME.name()); + Integer ordering = (Integer) dbFleet.get(FieldNames.FLEET_ORDERING.name()); + if (ordering == null) { + ordering = 0; + } + Integer colorAsInt = (Integer) dbFleet.get(FieldNames.FLEET_COLOR.name()); + Color color = null; + if (colorAsInt != null) { + int r = colorAsInt % 256; + int g = (colorAsInt / 256 ) % 256; + int b = (colorAsInt / 256 / 256) % 256; + color = new RGBColor(r, g, b); + } + result = new FleetImpl(name, ordering, color); + return result; + } + + @Override + public Map loadRaceIDToRegattaAssociations(RegattaRegistry regattaRegistry) { + DBCollection raceIDToRegattaCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); + Map result = new HashMap(); + for (DBObject o : raceIDToRegattaCollection.find()) { + Regatta regatta = regattaRegistry.getRegattaByName((String) o.get(FieldNames.REGATTA_NAME.name())); + if (regatta != null) { + result.put((String) o.get(FieldNames.RACE_ID_AS_STRING.name()), regatta); + } else { + logger.warning("Couldn't find regatta " + o.get(FieldNames.REGATTA_NAME.name()) + + ". Cannot restore race associations with this regatta."); + } + } + return result; + } + + @Override + public RaceLog loadRaceLog(RaceLogIdentifier identifier) { + RaceLog result = new RaceLogImpl(RaceLogImpl.class.getSimpleName(), identifier.getIdentifier()); + try { + BasicDBObject query = new BasicDBObject(); + query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(identifier.getIdentifier())); + loadRaceLogEvents(result, query); + + // query for events with deprecated identifier format... + query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(identifier.getDeprecatedIdentifier())); + + List eventsToMigrate = loadRaceLogEvents(result, query); + if (!eventsToMigrate.isEmpty()) { + // ... migrate them... + MongoRaceLogStoreVisitor storeVisitor = new MongoRaceLogStoreVisitor(identifier, new MongoObjectFactoryImpl(database, serviceFinderFactory)); + for (RaceLogEvent event : eventsToMigrate) { + event.accept(storeVisitor); + } + // ... and delete the old ones... + database.getCollection(CollectionNames.RACE_LOGS.name()).remove(query); + } + } catch (Throwable t) { + // something went wrong during DB access; report, then use empty new race log + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded race log data. Check MongoDB settings."); + logger.log(Level.SEVERE, "loadRaceLog", t); + } + return result; + } + + private List loadRaceLogEvents(RaceLog targetRaceLog, BasicDBObject query) { + List result = new ArrayList<>(); + DBCollection raceLog = database.getCollection(CollectionNames.RACE_LOGS.name()); + for (DBObject o : raceLog.find(query)) { + try { + RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name())); + if (raceLogEvent != null) { + targetRaceLog.load(raceLogEvent); + result.add(raceLogEvent); + } + } catch (IllegalStateException e) { + logger.log(Level.SEVERE, "Couldn't load race log event "+o+": "+e.getMessage(), e); + } + } + return result; + } + + public RaceLogEvent loadRaceLogEvent(DBObject dbObject) { + TimePoint logicalTimePoint = loadTimePoint(dbObject); + TimePoint createdAt = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_CREATED_AT); + Serializable id = (Serializable) dbObject.get(FieldNames.RACE_LOG_EVENT_ID.name()); + Integer passId = (Integer) dbObject.get(FieldNames.RACE_LOG_EVENT_PASS_ID.name()); + BasicDBList dbCompetitors = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name()); + List competitors = loadCompetitorsForRaceLogEvent(dbCompetitors); + final AbstractLogEventAuthor author; + String authorName = (String) dbObject.get(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name()); + Number authorPriority = (Number) dbObject.get(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name()); + if (authorName != null && authorPriority != null) { + author = new LogEventAuthorImpl(authorName, authorPriority.intValue()); + } else { + author = LogEventAuthorImpl.createCompatibilityAuthor(); + } + + String eventClass = (String) dbObject.get(FieldNames.RACE_LOG_EVENT_CLASS.name()); + if (eventClass.equals(RaceLogStartTimeEvent.class.getSimpleName())) { + return loadRaceLogStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogRaceStatusEvent.class.getSimpleName())) { + return loadRaceLogRaceStatusEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogFlagEvent.class.getSimpleName())) { + return loadRaceLogFlagEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogPassChangeEvent.class.getSimpleName())) { + return loadRaceLogPassChangeEvent(createdAt, author, logicalTimePoint, id, passId, competitors); + } else if (eventClass.equals(RaceLogCourseAreaChangedEvent.class.getSimpleName())) { + return loadRaceLogCourseAreaChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogCourseDesignChangedEvent.class.getSimpleName())) { + return loadRaceLogCourseDesignChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogFinishPositioningListChangedEvent.class.getSimpleName())) { + return loadRaceLogFinishPositioningListChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogFinishPositioningConfirmedEvent.class.getSimpleName())) { + return loadRaceLogFinishPositioningConfirmedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogPathfinderEvent.class.getSimpleName())) { + return loadRaceLogPathfinderEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogGateLineOpeningTimeEvent.class.getSimpleName())) { + return loadRaceLogGateLineOpeningTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogStartProcedureChangedEvent.class.getSimpleName())) { + return loadRaceLogStartProcedureChangedEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogProtestStartTimeEvent.class.getSimpleName())) { + return loadRaceLogRaceLogProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogWindFixEvent.class.getSimpleName())) { + return loadRaceLogRaceLogWindFixEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogDeviceCompetitorMappingEvent.class.getSimpleName())) { + return loadRaceLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogDeviceMarkMappingEvent.class.getSimpleName())) { + return loadRaceLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogDenoteForTrackingEvent.class.getSimpleName())) { + return loadRaceLogDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogStartTrackingEvent.class.getSimpleName())) { + return loadRaceLogStartEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogRevokeEvent.class.getSimpleName())) { + return loadRaceLogRevokeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogRegisterCompetitorEvent.class.getSimpleName())) { + return loadRaceLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogDefineMarkEvent.class.getSimpleName())) { + return loadRaceLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) { + return loadRaceLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogAdditionalScoringInformationEvent.class.getSimpleName())) { + return loadRaceLogAdditionalScoringInformationEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(FixedMarkPassingEvent.class.getSimpleName())){ + return loadRaceLogFixedMarkPassingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(SuppressedMarkPassingsEvent.class.getSimpleName())){ + return loadRaceLogSuppressedMarkPassingsEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } + + throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass)); + } + + private RaceLogEvent loadRaceLogRaceLogWindFixEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Wind wind = loadWind((DBObject) dbObject.get(FieldNames.WIND.name())); + return raceLogEventFactory.createWindFixEvent(createdAt, author, logicalTimePoint, id, competitors, passId, wind); + } + + private RaceLogEvent loadRaceLogDeviceCompetitorMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + DeviceIdentifier device = null; + try { + device = loadDeviceId(deviceIdentifierServiceFinder, + (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); + } catch (Exception e) { + logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); + e.printStackTrace(); + } + Competitor mappedTo = baseDomainFactory.getExistingCompetitorById( + (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name())); + TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); + TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); + return raceLogEventFactory.createDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); + } + + private RaceLogEvent loadRaceLogDeviceMarkMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + DeviceIdentifier device = null; + try { + device = loadDeviceId(deviceIdentifierServiceFinder, + (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); + } catch (Exception e) { + logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); + e.printStackTrace(); + } + //have to load complete mark, as no order is guaranteed for loading of racelog events + Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name())); + TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); + TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); + return raceLogEventFactory.createDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); + } + + private RaceLogEvent loadRaceLogDenoteForTrackingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name()); + BoatClass boatClass = baseDomainFactory.getOrCreateBoatClass((String) dbObject.get(FieldNames.BOAT_CLASS_NAME.name())); + Serializable raceId = (Serializable) dbObject.get(FieldNames.RACE_ID.name()); + return raceLogEventFactory.createDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, raceName, boatClass, raceId); + } + + private RaceLogEvent loadRaceLogStartEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + return raceLogEventFactory.createStartTrackingEvent(createdAt, author, logicalTimePoint, id, passId); + } + + private RaceLogEvent loadRaceLogRevokeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Serializable revokedEventId = Helpers.tryUuidConversion( + (Serializable) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name())); + String revokedEventType = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name()); + String revokedEventShortInfo = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name()); + String reason = (String) dbObject.get(FieldNames.RACE_LOG_REVOKED_REASON.name()); + return raceLogEventFactory.createRevokeEvent(createdAt, author, logicalTimePoint, id, passId, + revokedEventId, revokedEventType, revokedEventShortInfo, reason); + } + + private RaceLogEvent loadRaceLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Serializable competitorId = (Serializable) dbObject.get(FieldNames.RACE_LOG_COMPETITOR_ID.name()); + Competitor comp = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); + return raceLogEventFactory.createRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, comp); + } + + private RaceLogEvent loadRaceLogDefineMarkEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Mark mark = loadMark((DBObject) dbObject.get(FieldNames.RACE_LOG_MARK.name())); + return raceLogEventFactory.createDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, mark); + } + + private RaceLogEvent loadRaceLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name())); + TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.RACE_LOG_CLOSING_TIMEPOINT); + return raceLogEventFactory.createCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, + deviceMappingEventId, closingTimePoint); + } + + private RaceLogEvent loadRaceLogAdditionalScoringInformationEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Object additionalScoringInformationTypeInfo = dbObject.get(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name()); + AdditionalScoringInformationType informationType = AdditionalScoringInformationType.UNKNOWN; + if (additionalScoringInformationTypeInfo != null) { + informationType = AdditionalScoringInformationType.valueOf(additionalScoringInformationTypeInfo.toString()); + } else { + logger.warning("Could not find additional scoring information attached to db log for " + dbObject.toString()); + } + return raceLogEventFactory.createAdditionalScoringInformationEvent(createdAt, author, logicalTimePoint, id, competitors, passId, informationType); + } + + private RaceLogEvent loadRaceLogRaceLogProtestStartTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + TimePoint protestStartTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_PROTEST_START_TIME); + return raceLogEventFactory.createProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, competitors, passId, protestStartTime); + } + + private RaceLogEvent loadRaceLogStartProcedureChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + RacingProcedureType type = RacingProcedureType.valueOf(dbObject.get(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name()).toString()); + return raceLogEventFactory.createStartProcedureChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, type); + } + + private RaceLogEvent loadRaceLogGateLineOpeningTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Number gateLaunchStopTime = (Number) dbObject.get(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name()); + Number golfDownTime = 0; + if (dbObject.containsField(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name())) { + golfDownTime = (Number) dbObject.get(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name()); + } + return raceLogEventFactory.createGateLineOpeningTimeEvent(createdAt, author, logicalTimePoint, id, competitors, + passId, gateLaunchStopTime == null ? null : gateLaunchStopTime.longValue(), golfDownTime.longValue()); + } + + private RaceLogEvent loadRaceLogPathfinderEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + String pathfinderId = dbObject.get(FieldNames.RACE_LOG_PATHFINDER_ID.name()).toString(); + return raceLogEventFactory.createPathfinderEvent(createdAt, author, logicalTimePoint, id, competitors, passId, pathfinderId); + } + + private RaceLogEvent loadRaceLogFinishPositioningConfirmedEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + BasicDBList dbPositionedCompetitorList = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name()); + CompetitorResults positionedCompetitors = null; + //When a confirmation event is loaded that does not contain the positioned competitors (this is the case for the ESS events in + //Singapore and Quingdao) then null should be set for the positionedCompetitors, which is evaluated later on. + if (dbPositionedCompetitorList != null) { + positionedCompetitors = loadPositionedCompetitors(dbPositionedCompetitorList); + } + + return raceLogEventFactory.createFinishPositioningConfirmedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, positionedCompetitors); + } + + private RaceLogEvent loadRaceLogFinishPositioningListChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + BasicDBList dbPositionedCompetitorList = (BasicDBList) dbObject.get(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name()); + CompetitorResults positionedCompetitors = loadPositionedCompetitors(dbPositionedCompetitorList); + + return raceLogEventFactory.createFinishPositioningListChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, positionedCompetitors); + } + + private RaceLogEvent loadRaceLogPassChangeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors) { + return raceLogEventFactory.createPassChangeEvent(createdAt, author, logicalTimePoint, id, competitors, passId); + } + + private RaceLogCourseDesignChangedEvent loadRaceLogCourseDesignChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + String courseName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name()); + CourseBase courseData = loadCourseData((BasicDBList) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN.name()), courseName); + return raceLogEventFactory.createCourseDesignChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, courseData); + } + + private RaceLogCourseAreaChangedEvent loadRaceLogCourseAreaChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + Serializable courseAreaId = (Serializable) dbObject.get(FieldNames.COURSE_AREA_ID.name()); + return raceLogEventFactory.createCourseAreaChangedEvent(createdAt, author, logicalTimePoint, id, competitors, passId, courseAreaId); + } + + private RaceLogEvent loadRaceLogFixedMarkPassingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + TimePoint ofFixedPassing = loadTimePoint(dbObject, FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING); + Integer zeroBasedIndexOfWaypoint = (Integer) dbObject.get(FieldNames.INDEX_OF_PASSED_WAYPOINT.name()); + return raceLogEventFactory.createFixedMarkPassingEvent(logicalTimePoint, author, id, competitors, passId, ofFixedPassing, zeroBasedIndexOfWaypoint); + } + + private RaceLogEvent loadRaceLogSuppressedMarkPassingsEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, + Serializable id, Integer passId, List competitors, DBObject dbObject) { + Integer zeroBasedIndexOfFirstSuppressedWaypoint = (Integer) dbObject.get(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name()); + return raceLogEventFactory.createSuppressedMarkPassingsEvent(logicalTimePoint, author, id, competitors, passId, zeroBasedIndexOfFirstSuppressedWaypoint); + } + + private CompetitorResults loadPositionedCompetitors(BasicDBList dbPositionedCompetitorList) { + CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); + for (Object object : dbPositionedCompetitorList) { + DBObject dbObject = (DBObject) object; + + Serializable competitorId = (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()); + + String competitorName = (String) dbObject.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); + //The Competitor name is a new field in the list. Therefore the name might be null for existing events. In this case a standard name is set. + if (competitorName == null) { + competitorName = "loaded competitor"; + } + + //At this point we do not retrieve the competitor object since at any point in time, especially after a server restart, the DomainFactory and its competitor + //cache might be empty. But at this time the race log is loaded from database, so the competitor would be null. + //By not using the Competitor object retrieved from the DomainFactory we get completely independent from server restarts and the timepoint of loading + //competitors by tracking providers. + + MaxPointsReason maxPointsReason = MaxPointsReason.valueOf((String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())); + + Util.Triple positionedCompetitor = new Util.Triple(competitorId, competitorName, maxPointsReason); + positionedCompetitors.add(positionedCompetitor); + } + return positionedCompetitors; + } + + private List loadCompetitorsForRaceLogEvent(BasicDBList dbCompetitorList) { + List competitors = new ArrayList(); + for (Object object : dbCompetitorList) { + Serializable competitorId = (Serializable) object; + Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); + competitors.add(competitor); + } + return competitors; + } + + private RaceLogFlagEvent loadRaceLogFlagEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + Flags upperFlag = Flags.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name())); + Flags lowerFlag = Flags.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name())); + Boolean displayed = Boolean.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name())); + + if (upperFlag == null || lowerFlag == null || displayed == null) { + return null; + } + + return raceLogEventFactory.createFlagEvent(createdAt, author, logicalTimePoint, id, competitors, passId, upperFlag, lowerFlag, displayed); + } + + private RaceLogStartTimeEvent loadRaceLogStartTimeEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + TimePoint startTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_START_TIME); + return raceLogEventFactory.createStartTimeEvent(createdAt, author, logicalTimePoint, id, competitors, passId, startTime); + } + + private RaceLogRaceStatusEvent loadRaceLogRaceStatusEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { + RaceLogRaceStatus nextStatus = RaceLogRaceStatus.valueOf((String) dbObject.get(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name())); + return raceLogEventFactory.createRaceStatusEvent(createdAt, author, logicalTimePoint, id, competitors, passId, nextStatus); + } + + @Override + public RegattaLog loadRegattaLog(RegattaLikeIdentifier identifier) { + RegattaLog result = new RegattaLogImpl(RegattaLogImpl.class.getSimpleName(), identifier); + try { + BasicDBObject query = new BasicDBObject(); + query.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), identifier.getIdentifierType()); + query.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), identifier.getName()); + loadRegattaLogEvents(result, query, identifier); + } catch (Throwable t) { + // something went wrong during DB access; report, then use empty new regatta log + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded regatta log data. Check MongoDB settings."); + logger.log(Level.SEVERE, "loadRegattaLog", t); + } + return result; + } + + private void loadRegattaLogEvents(RegattaLog targetRegattaLog, BasicDBObject query, RegattaLikeIdentifier regattaLogIdentifier) { + DBCollection collection = database.getCollection(CollectionNames.REGATTA_LOGS.name()); + for (DBObject o : collection.find(query)) { + try { + RegattaLogEvent event = loadRegattaLogEvent(o, regattaLogIdentifier); + if (event != null) { + targetRegattaLog.load(event); + } + } catch (IllegalStateException e) { + logger.log(Level.SEVERE, "Couldn't load regatta log event "+o+": "+e.getMessage(), e); + } + } + } + + private RegattaLogEvent loadRegattaLogEvent(DBObject o, RegattaLikeIdentifier regattaLogIdentifier) { + DBObject dbObject = (DBObject) o.get(FieldNames.REGATTA_LOG_EVENT.name()); + TimePoint logicalTimePoint = loadTimePoint(dbObject); + TimePoint createdAt = loadTimePoint(dbObject, FieldNames.REGATTA_LOG_EVENT_CREATED_AT); + Serializable id = (Serializable) dbObject.get(FieldNames.REGATTA_LOG_EVENT_ID.name()); + final AbstractLogEventAuthor author; + String authorName = (String) dbObject.get(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name()); + Number authorPriority = (Number) dbObject.get(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name()); + author = new LogEventAuthorImpl(authorName, authorPriority.intValue()); + //CloseOpenEnded, DeviceCompMapping, DeviceMarkMapping, RegisterComp, Revoke + String eventClass = (String) dbObject.get(FieldNames.REGATTA_LOG_EVENT_CLASS.name()); + if (eventClass.equals(RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName())) { + return loadRegattaLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, dbObject, regattaLogIdentifier, o); + } else if (eventClass.equals(RegattaLogDeviceMarkMappingEvent.class.getSimpleName())) { + return loadRegattaLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, dbObject, regattaLogIdentifier, o); + } else if (eventClass.equals(RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) { + return loadRegattaLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, dbObject); + } else if (eventClass.equals(RegattaLogRegisterCompetitorEvent.class.getSimpleName())) { + return loadRegattaLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, dbObject); + } else if (eventClass.equals(RegattaLogSetCompetitorTimeOnTimeFactorEvent.class.getSimpleName())) { + return loadRegattaLogSetCompetitorTimeOnTimeFactorEvent(createdAt, author, logicalTimePoint, id, dbObject); + } else if (eventClass.equals(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent.class.getSimpleName())) { + return loadRegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent(createdAt, author, logicalTimePoint, id, dbObject); + } else if (eventClass.equals(RegattaLogRevokeEvent.class.getSimpleName())) { + return loadRegattaLogRevokeEvent(createdAt, author, logicalTimePoint, id, dbObject); + } + throw new IllegalStateException(String.format("Unknown RegattaLogEvent type %s", eventClass)); + } + + private Competitor getCompetitorByID(DBObject dbObject) { + Serializable competitorId = (Serializable) dbObject.get(FieldNames.REGATTA_LOG_COMPETITOR_ID.name()); + Competitor comp = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId); + return comp; + } + + private RegattaLogEvent loadRegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent(TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { + final Competitor comp = getCompetitorByID(dbObject); + final Double timeOnTimeFactor = (Double) dbObject.get(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name()); + return new RegattaLogSetCompetitorTimeOnTimeFactorEventImpl(createdAt, author, logicalTimePoint, id, comp, timeOnTimeFactor); + } + + private RegattaLogEvent loadRegattaLogSetCompetitorTimeOnTimeFactorEvent(TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { + final Competitor comp = getCompetitorByID(dbObject); + final Double timeOnDistanceSecondsAllowancePerNauticalMile = (Double) dbObject.get(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name()); + final Duration timeOnDistanceAllowancePerNauticalMile = timeOnDistanceSecondsAllowancePerNauticalMile == null ? null : + new MillisecondsDurationImpl((long) (timeOnDistanceSecondsAllowancePerNauticalMile*1000)); + return new RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEventImpl(createdAt, author, logicalTimePoint, id, comp, timeOnDistanceAllowancePerNauticalMile); + } + + private RegattaLogRevokeEvent loadRegattaLogRevokeEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { + Serializable revokedEventId = Helpers.tryUuidConversion( + (Serializable) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name())); + String revokedEventType = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name()); + String revokedEventShortInfo = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name()); + String reason = (String) dbObject.get(FieldNames.REGATTA_LOG_REVOKED_REASON.name()); + return new RegattaLogRevokeEventImpl(createdAt, author, logicalTimePoint, id, + revokedEventId, revokedEventType, revokedEventShortInfo, reason); + } + + private RegattaLogRegisterCompetitorEvent loadRegattaLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { + Competitor comp = getCompetitorByID(dbObject); + return new RegattaLogRegisterCompetitorEventImpl(createdAt, author, logicalTimePoint, id, comp); + } + + private RegattaLogCloseOpenEndedDeviceMappingEvent loadRegattaLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, DBObject dbObject) { + Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get( + FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name())); + TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT); + return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(createdAt, author, logicalTimePoint, id, + deviceMappingEventId, closingTimePoint); + } + + private RegattaLogDeviceMarkMappingEvent loadRegattaLogDeviceMarkMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, + TimePoint logicalTimePoint, Serializable id, DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) { + DeviceIdentifier device = null; + try { + device = loadDeviceId(deviceIdentifierServiceFinder, + (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); + } catch (Exception e) { + logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); + e.printStackTrace(); + } + //have to load complete mark, as no order is guaranteed for loading of racelog events + Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name())); + Triple times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO); + final TimePoint from = times.getA(); + final TimePoint to = times.getB(); + final RegattaLogDeviceMarkMappingEventImpl result = new RegattaLogDeviceMarkMappingEventImpl(createdAt, author, logicalTimePoint, id, mappedTo, device, from, to); + final boolean needsMigration = times.getC(); + if (needsMigration) { + // remove old version of mapping event + WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject); + assert removeResult.getN() == 1; + // and then insert using the fixed storage implementation + new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result); + } + return result; + } + + /** + * Loads a from and a to time point from fromField and toField of dbObject. + * If the fromField is not found, the fromFieldDeprecated is attempted. If found, migration + * is deemed necessary, expressed by returning true in the {@link Triple#getC()} component of the result. + * Same for the to-field. + * + * @return the from-time in {@link Triple#getA()}, the to-time in {@link Triple#getB()} and whether or not migration is + * necessary because a value was only found in a deprecated field in {@link Triple#getC()}. + */ + private Triple loadFromToTimePoint(final DBObject dbObject, FieldNames fromField, FieldNames fromFieldDeprecated, + FieldNames toField, FieldNames toFieldDeprecated) { + boolean needsMigration = false; + TimePoint from = loadTimePoint(dbObject, fromField); + if (from == null) { + // see bug 2733: erroneously, some records before the fix were written using RACE_LOG_FROM instead of REGATTA_LOG_FROM + // If such a case is found here, migrate the record. + from = loadTimePoint(dbObject, fromFieldDeprecated); + if (from != null) { + needsMigration = true; + } + } + TimePoint to = loadTimePoint(dbObject, toField); + if (to == null) { + // see bug 2733: erroneously, some records before the fix were written using RACE_LOG_FROM instead of REGATTA_LOG_FROM + // If such a case is found here, migrate the record. + to = loadTimePoint(dbObject, toFieldDeprecated); + if (to != null) { + needsMigration = true; + } + } + return new Triple<>(from, to, needsMigration); + } + + private RegattaLogDeviceCompetitorMappingEvent loadRegattaLogDeviceCompetitorMappingEvent(TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, final DBObject dbObject, + RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) { + DeviceIdentifier device = null; + try { + device = loadDeviceId(deviceIdentifierServiceFinder, + (DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); + } catch (Exception e) { + logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); + e.printStackTrace(); + } + Competitor mappedTo = baseDomainFactory.getExistingCompetitorById( + (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name())); + Triple times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO); + final TimePoint from = times.getA(); + final TimePoint to = times.getB(); + final boolean needsMigration = times.getC(); + final RegattaLogDeviceCompetitorMappingEventImpl result = new RegattaLogDeviceCompetitorMappingEventImpl(createdAt, author, logicalTimePoint, id, mappedTo, device, from, to); + if (needsMigration) { + // remove old version of mapping event + WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject); + assert removeResult.getN() == 1; + // and then insert using the fixed storage implementation + new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result); + } + return result; + } + + /** + * The old field name WAYPOINT_PASSINGSIDE has been replaced by WAYPOINT_PASSINGINSTRUCTIONS. If a race with the old + * field is loaded, the value of PASSINGSIDE is used and then migrated to PASSINGINSTRUCTION. If the first or last + * Waypoint has the PassingInstructions Gate, it is transfered to Line. + * + */ + @SuppressWarnings("deprecation") // Used to migrate from PASSINGSIDE to the new PASSINGINSTRUCTIONS + private CourseBase loadCourseData(BasicDBList dbCourseList, String courseName) { + if (courseName == null) { + courseName = "Course"; + } + CourseBase courseData = new CourseDataImpl(courseName); + int i = 0; + for (Object object : dbCourseList) { + DBObject dbObject = (DBObject) object; + Waypoint waypoint = null; + PassingInstruction passingInstructions = null; + String waypointPassingInstruction = (String) dbObject.get(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name()); + if (waypointPassingInstruction == null) { + waypointPassingInstruction = (String) dbObject.get(FieldNames.WAYPOINT_PASSINGSIDE.name()); + if(waypointPassingInstruction != null) { + logger.info("Migrating PassingInstruction "+waypointPassingInstruction+" to field name WAYPOINT_PASSINGINSTRUCTIONS"); + if((i==0||i==dbCourseList.size()-1)&&waypointPassingInstruction.toLowerCase().equals("gate")){ + logger.warning("Changing PassingInstructions of first or last Waypoint from Gate to Line."); + waypointPassingInstruction = "Line"; + } + dbObject.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), waypointPassingInstruction); + dbObject.removeField(FieldNames.WAYPOINT_PASSINGSIDE.name()); + } + } + if (waypointPassingInstruction != null) { + passingInstructions = PassingInstruction.valueOfIgnoringCase(waypointPassingInstruction); + } + ControlPoint controlPoint = loadControlPoint((DBObject) dbObject.get(FieldNames.CONTROLPOINT.name())); + if (passingInstructions == null) { + waypoint = new WaypointImpl(controlPoint); + } else { + waypoint = new WaypointImpl(controlPoint, passingInstructions); + } + courseData.addWaypoint(i++, waypoint); + } + return courseData; + } + + private ControlPoint loadControlPoint(DBObject dbObject) { + String controlPointClass = (String) dbObject.get(FieldNames.CONTROLPOINT_CLASS.name()); + ControlPoint controlPoint = null; + if (controlPointClass != null) { + if (controlPointClass.equals(Mark.class.getSimpleName())) { + Mark mark = loadMark((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); + controlPoint = mark; + } else if(controlPointClass.equals("Gate")) { + ControlPointWithTwoMarks cpwtm = loadControlPointWithTwoMarks((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); + dbObject.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); + controlPoint = cpwtm; + } else if (controlPointClass.equals(ControlPointWithTwoMarks.class.getSimpleName())) { + ControlPointWithTwoMarks cpwtm = loadControlPointWithTwoMarks((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); + controlPoint = cpwtm; + } + } + return controlPoint; + } + + /** + * Checks for the old GATE fields and migrates them to the new CONTROLPOINTWITHTWOMARKS fields. + */ + @SuppressWarnings("deprecation") // Used for migrating old races + private ControlPointWithTwoMarks loadControlPointWithTwoMarks(DBObject dbObject) { + String controlPointName = (String) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name()); + if (controlPointName == null) { + controlPointName = (String) dbObject.get(FieldNames.GATE_NAME.name()); + logger.info("Migrating name of ControlPointWithTwoMarks " + controlPointName + + " from GATE_NAME to new field CONTROLPOINTWITHTWOMARKS_NAME."); + dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), controlPointName); + dbObject.removeField(FieldNames.GATE_NAME.name()); + } + Serializable controlPointId = (Serializable) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name()); + if (controlPointId == null) { + controlPointId = (Serializable) dbObject.get(FieldNames.GATE_ID.name()); + logger.info("Migrating id of ControlPointWithTwoMarks " + controlPointName + + " from old field GATE_ID to CONTROLPOINTWITHTWOMARKS_ID."); + dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), controlPointId); + dbObject.removeField(FieldNames.GATE_ID.name()); + } + DBObject dbLeft = (DBObject) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name()); + if (dbLeft == null) { + dbLeft = (DBObject) dbObject.get(FieldNames.GATE_LEFT.name()); + logger.info("Migrating left Mark of ControlPointWithTwoMarks " + controlPointName + " from old field GATE_LEFT to CONTROLPOINTWITHTWOMARKS_LEFT"); + dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), dbLeft); + dbObject.removeField(FieldNames.GATE_LEFT.name()); + } + Mark leftMark = loadMark(dbLeft); + DBObject dbRight = (DBObject) dbObject.get(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name()); + if (dbRight == null) { + dbRight = (DBObject) dbObject.get(FieldNames.GATE_RIGHT.name()); + logger.info("Migrating right Mark of ControlPointWithTwoMarks " + controlPointName + " from old field GATE_RIGHT to CONTROLPOINTWITHTWOMARKS_RIGHT"); + dbObject.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), dbRight); + dbObject.removeField(FieldNames.GATE_RIGHT.name()); + } + Mark rightMark = loadMark(dbRight); + ControlPointWithTwoMarks gate = baseDomainFactory.createControlPointWithTwoMarks(controlPointId, leftMark, rightMark, controlPointName); + return gate; + } + + private Mark loadMark(DBObject dbObject) { + Serializable markId = (Serializable) dbObject.get(FieldNames.MARK_ID.name()); + String markColor = (String) dbObject.get(FieldNames.MARK_COLOR.name()); + String markName = (String) dbObject.get(FieldNames.MARK_NAME.name()); + String markPattern = (String) dbObject.get(FieldNames.MARK_PATTERN.name()); + String markShape = (String) dbObject.get(FieldNames.MARK_SHAPE.name()); + Object markTypeRaw = dbObject.get(FieldNames.MARK_TYPE.name()); + MarkType markType = markTypeRaw == null ? null : MarkType.valueOf((String) markTypeRaw); + + Mark mark = baseDomainFactory.getOrCreateMark(markId, markName, markType, markColor, markShape, markPattern); + return mark; + } + + @Override + public Collection loadAllCompetitors() { + ArrayList result = new ArrayList(); + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); + try { + for (DBObject o : collection.find()) { + JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(o))); + Competitor c = competitorDeserializer.deserialize(json); + result.add(c); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load competitors."); + logger.log(Level.SEVERE, "loadCompetitors", e); + } + return result; + } + + @Override + public Iterable> loadAllDeviceConfigurations() { + Map result = new HashMap<>(); + DBCollection configurationCollection = database.getCollection(CollectionNames.CONFIGURATIONS.name()); + + try { + for (DBObject dbObject : configurationCollection.find()) { + Util.Pair entry = loadConfigurationEntry(dbObject); + result.put(entry.getA(), entry.getB()); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load configurations."); + logger.log(Level.SEVERE, "loadAllDeviceConfigurations", e); + } + + return result.entrySet(); + } + + private Util.Pair loadConfigurationEntry(DBObject dbObject) { + DBObject matcherObject = (DBObject) dbObject.get(FieldNames.CONFIGURATION_MATCHER.name()); + DBObject configObject = (DBObject) dbObject.get(FieldNames.CONFIGURATION_CONFIG.name()); + return new Util.Pair(loadConfigurationMatcher(matcherObject), + loadConfiguration(configObject)); + } + + private DeviceConfigurationMatcher loadConfigurationMatcher(DBObject matcherObject) { + DeviceConfigurationMatcherType type = DeviceConfigurationMatcherType.valueOf( + matcherObject.get(FieldNames.CONFIGURATION_MATCHER_TYPE.name()).toString()); + List clientIdentifiers = new ArrayList(); + BasicDBList clientIdentifiersObject = (BasicDBList) matcherObject.get(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name()); + if (clientIdentifiersObject != null) { + for (Object clientIdentifier : clientIdentifiersObject) { + clientIdentifiers.add(clientIdentifier.toString()); + } + } + return baseDomainFactory.getOrCreateDeviceConfigurationMatcher(type, clientIdentifiers); + } + + private DeviceConfiguration loadConfiguration(DBObject configObject) { + DeviceConfiguration configuration = null; + try { + JsonDeserializer deserializer = DeviceConfigurationJsonDeserializer.create(); + JSONObject json = Helpers.toJSONObjectSafe(new JSONParser().parse(JSON.serialize(configObject))); + configuration = deserializer.deserialize(json); + } catch (JsonDeserializationException | ParseException e) { + logger.log(Level.SEVERE, "Error parsing configuration object from MongoDB, falling back to empty configuration."); + logger.log(Level.SEVERE, "loadConfiguration", e); + configuration = new DeviceConfigurationImpl(new RegattaConfigurationImpl()); + } + return configuration; + } + + private DeviceIdentifier loadDeviceId( + TypeBasedServiceFinder deviceIdentifierServiceFinder, DBObject deviceId) + throws TransformationException, NoCorrespondingServiceRegisteredException { + String deviceType = (String) deviceId.get(FieldNames.DEVICE_TYPE.name()); + Object deviceTypeId = deviceId.get(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name()); + String stringRepresentation = (String) deviceId.get(FieldNames.DEVICE_STRING_REPRESENTATION.name()); + + try { + return deviceIdentifierServiceFinder.findService(deviceType).deserialize(deviceTypeId, deviceType, stringRepresentation); + } catch (TransformationException e) { + return new PlaceHolderDeviceIdentifierSerializationHandler().deserialize( + stringRepresentation, deviceType, stringRepresentation); + } + } + + @Override + public Map> loadResultUrls() { + Map> resultUrls = new HashMap<>(); + DBCollection resultUrlCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); + for (DBObject dbObject : resultUrlCollection.find()) { + String providerName = (String) dbObject.get(FieldNames.RESULT_PROVIDERNAME.name()); + String urlString = (String) dbObject.get(FieldNames.RESULT_URL.name()); + URL url; + try { + url = new URL(urlString); + } catch (MalformedURLException e) { + logger.log(Level.SEVERE, "Failed to parse result Url String: " + urlString + ". Did not load url!"); + continue; + } + if (!resultUrls.containsKey(providerName)) { + resultUrls.put(providerName, new HashSet()); + } + Set set = resultUrls.get(providerName); + set.add(url); + } + return resultUrls; + } + + private ImageDescriptor loadImage(DBObject dbObject) { + ImageDescriptor image = null; + URL imageURL = loadURL(dbObject, FieldNames.IMAGE_URL); + if (imageURL != null) { + String title = (String) dbObject.get(FieldNames.IMAGE_TITLE.name()); + String subtitle = (String) dbObject.get(FieldNames.IMAGE_SUBTITLE.name()); + String copyright = (String) dbObject.get(FieldNames.IMAGE_COPYRIGHT.name()); + //Object mimeTypeRaw = dbObject.get(FieldNames.IMAGE_MIMETYPE.name()); + //MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + Integer imageWidth = (Integer) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); + Integer imageHeight = (Integer) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); + TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.IMAGE_CREATEDATDATE); + BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.IMAGE_TAGS.name()); + List imageTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + imageTags.add((String) tagObject); + } + } + image = new ImageDescriptorImpl(imageURL, createdAtDate); + image.setCopyright(copyright); + image.setTitle(title); + image.setSubtitle(subtitle); + image.setTags(imageTags); + if (imageWidth != null && imageHeight != null) { + image.setSize(imageWidth, imageHeight); + } + } + return image; + } + + private VideoDescriptor loadVideo(DBObject dbObject) { + VideoDescriptor video = null; + URL videoURL = loadURL(dbObject, FieldNames.VIDEO_URL); + if(videoURL != null) { + String title = (String) dbObject.get(FieldNames.VIDEO_TITLE.name()); + String subtitle = (String) dbObject.get(FieldNames.VIDEO_SUBTITLE.name()); + String copyright = (String) dbObject.get(FieldNames.VIDEO_COPYRIGHT.name()); + Object mimeTypeRaw = dbObject.get(FieldNames.VIDEO_MIMETYPE.name()); + MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.VIDEO_CREATEDATDATE); + BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.VIDEO_TAGS.name()); + Integer lengthInSeconds = (Integer) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); + URL thumbnailURL = loadURL(dbObject, FieldNames.VIDEO_THUMBNAIL_URL); + List videoTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + videoTags.add((String) tagObject); + } + } + video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate); + video.setCopyright(copyright); + video.setTitle(title); + video.setSubtitle(subtitle); + video.setTags(videoTags); + video.setLengthInSeconds(lengthInSeconds); + video.setThumbnailURL(thumbnailURL); + } + return video; + } + + private URL loadURL(DBObject dbObject, FieldNames field) { + URL result = null; + String urlAsString = (String) dbObject.get(field.name()); + if(urlAsString != null) { + try { + result = new URL(urlAsString); + } catch (MalformedURLException e) { + logger.severe("Error parsing URL '"+urlAsString+"' in field "+field.name()+"."); + } + } + return result; + } + + /** + * Migrates images and videos stored as pure URLs to the new richer format once + * @param event the event to migrate + */ + private void migrateImagesAndVideosOfEvent(Event event) { + int amountOfURLbasedImagesAndVideos = Util.size(event.getImageURLs()) + Util.size(event.getSponsorImageURLs()) + Util.size(event.getVideoURLs()); + int amountOfImagesAndVideos = Util.size(event.getImages()) + Util.size(event.getVideos()); + boolean migrationRequired = amountOfURLbasedImagesAndVideos > 0 && amountOfImagesAndVideos == 0; + if(migrationRequired) { + for(URL url: event.getImageURLs()) { + String urlAsString = url.toString(); + ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if(imageDimensions != null) { + image.setSize(imageDimensions); + } + if(urlAsString.toLowerCase().indexOf("stage") > 0) { + image.addTag("Stage"); + } else if(urlAsString.toLowerCase().indexOf("eventteaser") > 0) { + image.addTag("Teaser"); + } + event.addImage(image); + } + for(URL url: event.getSponsorImageURLs()) { + ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if(imageDimensions != null) { + image.setSize(imageDimensions); + } + image.addTag("Sponsor"); + event.addImage(image); + } + for(URL url: event.getVideoURLs()) { + VideoDescriptor video = new VideoDescriptorImpl(url, MimeType.unknown, MillisecondsTimePoint.now()); + event.addVideo(video); + } + new MongoObjectFactoryImpl(database).storeEvent(event); + } + } +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java index fb25d1c77c3..abbe3dc0023 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java @@ -1,64 +1,69 @@ -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 getRegattas(); - - void addRegatta(Regatta regatta); - - void removeRegatta(Regatta regatta); - - /** - * For events, the ID is always a UUID. - */ - UUID getId(); - - /** - * Returns a non-null 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 getLeaderboardGroups(); - - void addLeaderboardGroup(LeaderboardGroup leaderboardGroup); - - /** - * @return true if and only if a leaderboard group equal to leaderboardGroup 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 leaderboardGroups. - */ - void setLeaderboardGroups(Iterable 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.

    - * - * Note that exceptions may result should the image be unavailable. If the image URL leads to a document that is not an image, - * null will result. - */ - ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException; - -} +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.ImageDescriptor; +import com.sap.sse.common.media.ImageSize; +import com.sap.sse.common.media.MediaUtils; + +/** + * 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 getRegattas(); + + void addRegatta(Regatta regatta); + + void removeRegatta(Regatta regatta); + + /** + * For events, the ID is always a UUID. + */ + UUID getId(); + + /** + * Returns a non-null 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 getLeaderboardGroups(); + + void addLeaderboardGroup(LeaderboardGroup leaderboardGroup); + + /** + * @return true if and only if a leaderboard group equal to leaderboardGroup 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 leaderboardGroups. + */ + void setLeaderboardGroups(Iterable 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.

    + * + * Note that exceptions may result should the image be unavailable. If the image URL leads to a document that is not an image, + * null will result. + * + * @deprecated Use {@link MediaUtils#getImageDimensions(URL)} or simply use the dimensions given by {@link ImageDescriptor} + */ + @Deprecated + ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException; + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java deleted file mode 100644 index e61f0c0eb93..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java +++ /dev/null @@ -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; - } - } - -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java index 240b2b46fa2..8cbdbe2acc3 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java @@ -1,7 +1,9 @@ package com.sap.sse.common.media; +import com.sap.sse.common.Util.Pair; + public interface ImageDescriptor extends MediaDescriptor { - void setSize(ImageSize size); + void setSize(Pair size); void setSize(Integer widthInPx, Integer heightInPx); Integer getWidthInPx(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index 424cd995dce..8ef721b9d6b 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -3,6 +3,7 @@ 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 { @@ -30,10 +31,10 @@ public class ImageDescriptorImpl extends AbstractMediaDescriptor implements Imag } @Override - public void setSize(ImageSize size) { + public void setSize(Pair size) { if (size != null) { - this.widthInPx = size.getWidth(); - this.heightInPx = size.getHeight(); + this.widthInPx = size.getA(); + this.heightInPx = size.getB(); } else { this.widthInPx = null; this.heightInPx = null; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaUtils.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaUtils.java new file mode 100644 index 00000000000..ca276c22ac6 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaUtils.java @@ -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 getImageDimensions(URL imageURL) { + Future> imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL); + try { + return imageSizeCalculator.get(); + } catch (Exception e) { + return null; + } + } + + private static final ExecutorService executor = Executors.newCachedThreadPool(); + + private static Future> getOrCreateImageSizeCalculator(final URL imageURL) { + Future> imageSizeFetcher = executor.submit(new Callable>() { + @Override + public Pair call() throws IOException { + Pair result = null; + ImageInputStream in = null; + try { + URLConnection conn = imageURL.openConnection(); + in = ImageIO.createImageInputStream(conn.getInputStream()); + final Iterator 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; + } +} From e25653b250ad9efc7c5eff2cd5d9b1189536942d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 13:15:17 +0200 Subject: [PATCH 041/117] Improved calculation of image short name --- .../sailing/gwt/ui/adminconsole/ImagesListComposite.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index 6d353240cd8..7312df6e505 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -115,9 +115,13 @@ public class ImagesListComposite extends Composite { @Override public SafeHtml getValue(ImageDTO image) { String linkName = ""; - int index = image.getSourceRef().lastIndexOf("/"); + String link = image.getSourceRef(); + if(link.endsWith("/")) { + link = link.substring(0, link.length() - 1); + } + int index = link.lastIndexOf("/"); if(index > 0) { - linkName = image.getSourceRef().substring(index+1, image.getSourceRef().length()); + linkName = link.substring(index+1, link.length()); } return ANCHORTEMPLATE.cell(image.getSourceRef(), linkName); } From bf5e86c5ecea139c189420208c5ad99907e3acf4 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 13:16:27 +0200 Subject: [PATCH 042/117] Fixed mapping of image size for AdminConsole --- .../java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 0667a8d717f..9ec5c162b5f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3504,6 +3504,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S result.setTitle(image.getTitle()); result.setSubtitle(image.getSubtitle()); result.setMimeType(image.getMimeType()); + result.setSizeInPx(image.getWidthInPx(), image.getHeightInPx()); List tags = new ArrayList(); for(String tag: image.getTags()) { tags.add(tag); From 3665ddd8062b2390779d09975c717043f1fcd1d0 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 13:23:34 +0200 Subject: [PATCH 043/117] Implemented auto-detection of video mime types --- .../domain/persistence/impl/DomainObjectFactoryImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 8f344ffa1b6..4cd1a1cd0c1 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -2198,7 +2198,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { event.addImage(image); } for(URL url: event.getVideoURLs()) { - VideoDescriptor video = new VideoDescriptorImpl(url, MimeType.unknown, MillisecondsTimePoint.now()); + MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); + VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, MillisecondsTimePoint.now()); event.addVideo(video); } new MongoObjectFactoryImpl(database).storeEvent(event); From b6fdd8a028090c4868a9c424d06ab12840966d63 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 14:08:35 +0200 Subject: [PATCH 044/117] Initial implementation of image size auto detection --- .../gwt/ui/adminconsole/ImageDialog.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index c4c31ed8cc2..e934b453208 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -5,9 +5,14 @@ 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; @@ -33,6 +38,8 @@ public abstract class ImageDialog extends DataEntryDialog { protected IntegerBox heightInPxBox; protected StringListInlineEditorComposite tagsListEditor; + final Image image; + protected static class ImageParameterValidator implements Validator { private StringMessages stringMessages; @@ -57,12 +64,29 @@ public abstract class ImageDialog extends DataEntryDialog { 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() { @Override public void onValueChange(ValueChangeEvent event) { validate(); + image.setUrl(event.getValue()); } }); @@ -71,7 +95,7 @@ public abstract class ImageDialog extends DataEntryDialog { 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); @@ -117,6 +141,8 @@ public abstract class ImageDialog extends DataEntryDialog { formGrid.setWidget(6, 1, heightInPxBox); formGrid.setWidget(7, 0, new Label("Tags:")); formGrid.setWidget(7, 1, tagsListEditor); + + panel.add(image); return panel; } From 637f3b16fa68bc2adeadba0c62f97b4918c09c8b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 15:34:36 +0200 Subject: [PATCH 045/117] Implemented incremental migration of media --- .../impl/DomainObjectFactoryImpl.java | 77 ++++++++++++------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 4cd1a1cd0c1..4c8dd554329 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -193,6 +193,7 @@ import com.sap.sse.common.impl.RGBColor; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.media.ImageDescriptor; import com.sap.sse.common.media.ImageDescriptorImpl; +import com.sap.sse.common.media.MediaDescriptor; import com.sap.sse.common.media.MediaUtils; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; @@ -2170,39 +2171,61 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { * @param event the event to migrate */ private void migrateImagesAndVideosOfEvent(Event event) { - int amountOfURLbasedImagesAndVideos = Util.size(event.getImageURLs()) + Util.size(event.getSponsorImageURLs()) + Util.size(event.getVideoURLs()); - int amountOfImagesAndVideos = Util.size(event.getImages()) + Util.size(event.getVideos()); - boolean migrationRequired = amountOfURLbasedImagesAndVideos > 0 && amountOfImagesAndVideos == 0; - if(migrationRequired) { - for(URL url: event.getImageURLs()) { - String urlAsString = url.toString(); - ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if(imageDimensions != null) { - image.setSize(imageDimensions); - } + boolean changedAnything = false; + + changedAnything |= migrateImagesOfEvent(event, event.getImageURLs(), false); + changedAnything |= migrateImagesOfEvent(event, event.getSponsorImageURLs(), true); + + for(URL url: event.getVideoURLs()) { + if(hasMedia(event.getVideos(), url)) { + continue; + } + changedAnything = true; + MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); + VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, MillisecondsTimePoint.now()); + event.addVideo(video); + } + + if(changedAnything) { + new MongoObjectFactoryImpl(database).storeEvent(event); + } + } + + private boolean migrateImagesOfEvent(Event event, Iterable images, boolean sponsor) { + boolean changedAnything = false; + for(URL url: event.getImageURLs()) { + String urlAsString = url.toString(); + if(hasMedia(event.getImages(), url)) { + continue; + } + changedAnything = true; + ImageDescriptorImpl image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); + + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if(imageDimensions != null) { + image.setSize(imageDimensions); + } + + if(sponsor) { + image.addTag("Sponsor"); + } else { if(urlAsString.toLowerCase().indexOf("stage") > 0) { image.addTag("Stage"); } else if(urlAsString.toLowerCase().indexOf("eventteaser") > 0) { image.addTag("Teaser"); } - event.addImage(image); } - for(URL url: event.getSponsorImageURLs()) { - ImageDescriptor image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if(imageDimensions != null) { - image.setSize(imageDimensions); - } - image.addTag("Sponsor"); - event.addImage(image); - } - for(URL url: event.getVideoURLs()) { - MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); - VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, MillisecondsTimePoint.now()); - event.addVideo(video); - } - new MongoObjectFactoryImpl(database).storeEvent(event); + event.addImage(image); } + return changedAnything; + } + + private boolean hasMedia(Iterable media, URL url) { + for(MediaDescriptor mediaEntry : media) { + if(url.equals(mediaEntry.getURL())) { + return true; + } + } + return false; } } From 05f051a9c42bba27bfae0460506764736f2be389 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 15:35:05 +0200 Subject: [PATCH 046/117] Removed unused "Logo" tag from the suggest list --- .../com/sap/sailing/gwt/ui/shared/media/MediaConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index c3180715bde..f2ffa6f8ae8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -12,7 +12,7 @@ public final class MediaConstants { public static final String FEATURED = "Featured"; public static final String LOCALE_PREFIX = "Locale_"; public static final String LOCALE_EN = LOCALE_PREFIX + "en"; - public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor", "Logo" }); + public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor" }); public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED, LOCALE_PREFIX + "de", LOCALE_EN, LOCALE_PREFIX + "ru", LOCALE_PREFIX + "cn" }); private MediaConstants() { From a1c23ce4dee466cbf4ad7db658cf49b9678a9ea6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 15:50:20 +0200 Subject: [PATCH 047/117] Fixed resonsive visualization of the boat class name --- .../client/place/event/partials/updatesBox/UpdatesBoxItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index d9f293e8129..b17a889fd3f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -45,7 +45,7 @@ public class UpdatesBoxItem extends Widget { String boatClass = entry.getBoatClass(); if(boatClass != null && !boatClass.isEmpty()) { icon.getStyle().setBackgroundImage("url(\"" + BoatClassImageResolver.getBoatClassIconResource(boatClass).getSafeUri().asString() + "\")"); - boatClassUi.setInnerText(boatClass); + boatClassUi.setInnerText(" / " + boatClass); } else { boatClassUi.removeFromParent(); } From 13a316cb1af078ec477633e72dad0507f4871bf6 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 9 Jun 2015 15:51:56 +0200 Subject: [PATCH 048/117] removed unused warning --- .../sailing/domain/persistence/impl/DomainObjectFactoryImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 4c8dd554329..ad33b2d64ab 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -5,7 +5,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; From 148f58b5892f81b5e04d77c49bf43f0582a0b767 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 16:09:36 +0200 Subject: [PATCH 049/117] Improved logic that is dependent on weather image size is available or not --- .../com/sap/sailing/gwt/server/HomeServiceImpl.java | 2 +- .../com/sap/sailing/gwt/server/HomeServiceUtil.java | 13 +++---------- .../com/sap/sse/common/media/ImageDescriptor.java | 3 +++ .../sap/sse/common/media/ImageDescriptorImpl.java | 13 +++++++++++++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 6bc23c0a883..d86625f6bdc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -214,7 +214,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home EventReferenceDTO eventRef = new EventReferenceDTO(holder.event); for (ImageDescriptor url : HomeServiceUtil.getSailingLovesPhotographyImages(event)) { - if(url.getWidthInPx() != null && url.getHeightInPx() != null) { + if(url.hasSize()) { SailingImageDTO sailingImageDTO = new SailingImageDTO(eventRef, url.getURL().toString(), null); sailingImageDTO.setSizeInPx(url.getWidthInPx(), url.getHeightInPx()); photoGalleryUrls.add(sailingImageDTO); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 8593181f965..606a483117f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -267,21 +267,14 @@ public final class HomeServiceUtil { return !teaser; } - int size = imageSize(candidate); - int sizeRef = imageSize(reference); + int size = candidate.getArea(); + int sizeRef = candidate.getArea(); if(size != sizeRef) { return size > sizeRef; } return candidate.getCreatedAtDate().compareTo(reference.getCreatedAtDate()) > 0; } - private static int imageSize(ImageDescriptor candidate) { - int width = candidate.getWidthInPx() == null ? 0 : candidate.getWidthInPx(); - int height = candidate.getHeightInPx() == null ? 0 : candidate.getHeightInPx(); - // TODO fallback to event.getImageSize() if size is 0/null? - return width * height; - } - public static List getPhotoGalleryImageURLsAsString(EventBase event) { List urls = getPhotoGalleryImages(event); List result = new ArrayList(urls.size()); @@ -313,7 +306,7 @@ public final class HomeServiceUtil { public static List getSailingLovesPhotographyImages(EventBase event) { final List acceptedImages = new LinkedList<>(); for (ImageDescriptor candidateImageUrl : event.getImages()) { - if (candidateImageUrl.getWidthInPx() != null && candidateImageUrl.getHeightInPx() != null && candidateImageUrl.getHeightInPx() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) { + if (candidateImageUrl.hasSize() && candidateImageUrl.getHeightInPx() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) { acceptedImages.add(candidateImageUrl); } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java index 8cbdbe2acc3..67ace752668 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java @@ -8,4 +8,7 @@ public interface ImageDescriptor extends MediaDescriptor { Integer getWidthInPx(); Integer getHeightInPx(); + + boolean hasSize(); + int getArea(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index 8ef721b9d6b..b3c6b71ac05 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -46,4 +46,17 @@ public class ImageDescriptorImpl extends AbstractMediaDescriptor implements Imag 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; + } } From bad03b0e4c37c1811224ca8773e8496ea7f2ec85 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 16:19:04 +0200 Subject: [PATCH 050/117] Added auto detection of video mime type when saving an event --- .../com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 9ec5c162b5f..7632b6cb6a7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -433,6 +433,8 @@ 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; @@ -3484,7 +3486,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } private VideoDescriptor convertToVideo(VideoDTO video) throws MalformedURLException { - VideoDescriptor result = new VideoDescriptorImpl(new URL(video.getSourceRef()), video.getMimeType(), new MillisecondsTimePoint(video.getCreatedAtDate())); + 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()); From 53838c96908b907e9b4ed0cba9e56e7e76f2253e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 16:38:35 +0200 Subject: [PATCH 051/117] Removed old image and video URL UIs to force users to use the new one --- .../java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index a5f382be601..99e2c3a034e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -242,9 +242,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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; From 7945ce91c14c2eb612c95338239e47a3ac9db0ce Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 16:40:01 +0200 Subject: [PATCH 052/117] Added Exception handling for parsing the URLs to not loose other changes on save --- .../gwt/ui/server/SailingServiceImpl.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 7632b6cb6a7..998c812f2c4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3309,14 +3309,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List imageURLs = createURLsFromStrings(imageURLStrings); List videoURLs = createURLsFromStrings(videoURLStrings); List sponsorimagieURLs = createURLsFromStrings(sponsorImageURLStrings); - List eventImages = new ArrayList(); - for (ImageDTO image : images) { - eventImages.add(convertToImage(image)); - } - List eventVideos = new ArrayList(); - for (VideoDTO video : videos) { - eventVideos.add(convertToVideo(video)); - } + List eventImages = convertToImages(images); + List eventVideos = convertToVideos(videos); getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, imageURLs, videoURLs, @@ -3346,14 +3340,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; - List eventImages = new ArrayList(); - for (ImageDTO image : images) { - eventImages.add(convertToImage(image)); - } - List eventVideos = new ArrayList(); - for (VideoDTO video : videos) { - eventVideos.add(convertToVideo(video)); - } + List eventImages = convertToImages(images); + List eventVideos = convertToVideos(videos); getService().apply( new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid, createURLsFromStrings(imageURLs), createURLsFromStrings(videoURLs), @@ -3472,6 +3460,30 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } + private List convertToImages(Iterable images) throws MalformedURLException { + List eventImages = new ArrayList(); + for (ImageDTO image : images) { + try { + eventImages.add(convertToImage(image)); + } catch(Exception e) { + // broken URLs are not being stored + } + } + return eventImages; + } + + private List convertToVideos(Iterable videos) throws MalformedURLException { + List eventVideos = new ArrayList(); + 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()); From 00fcc91f5527fdece6b7327e96b62469ced0c17c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 9 Jun 2015 17:16:22 +0200 Subject: [PATCH 053/117] Implemented consistent filtering of supported video types --- .../com/sap/sailing/gwt/server/HomeServiceImpl.java | 10 +++++----- .../com/sap/sailing/gwt/server/HomeServiceUtil.java | 6 ++---- .../dispatch/event/GetEventOverviewStageAction.java | 6 +----- .../sailing/gwt/ui/shared/media/MediaConstants.java | 5 +++++ 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index d86625f6bdc..48e9c289845 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -39,6 +39,7 @@ 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.SailingImageDTO; import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; @@ -54,7 +55,6 @@ 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.ImageDescriptor; -import com.sap.sse.common.media.MediaType; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; import com.sap.sse.util.ServiceTrackerFactory; @@ -184,7 +184,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home VideoDescriptor youTubeRandomUrl = HomeServiceUtil.getRandomVideo(videosOfEvent); MimeType type = youTubeRandomUrl.getMimeType(); - if (type.mediaType == MediaType.video) { + if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.getURL().toString(), type, // youTubeRandomUrl.getCreatedAtDate().asDate() ); @@ -221,8 +221,8 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } } for (VideoDescriptor videoUrl : event.getVideos()) { - MimeType type =videoUrl.getMimeType(); - if (type.mediaType == MediaType.video) { + MimeType type = videoUrl.getMimeType(); + if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.getURL().toString(), type, // videoUrl.getCreatedAtDate().asDate() ); @@ -429,7 +429,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } for(VideoDescriptor url : event.getVideos()) { MimeType type = url.getMimeType(); - if (type.mediaType == MediaType.video) { + if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.getURL().toString(), type, null); media.addVideo(candidate); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 606a483117f..ecdf806c803 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -7,7 +7,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Random; -import java.util.Set; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; @@ -27,7 +26,6 @@ import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; import com.sap.sse.common.media.ImageDescriptor; import com.sap.sse.common.media.MediaDescriptor; -import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; public final class HomeServiceUtil { @@ -390,11 +388,11 @@ public final class HomeServiceUtil { return Util.get(urls, new Random(size).nextInt(size)); } - public static VideoDescriptor getStageVideo(Event event, String localeName, Set acceptedTypes, Collection rankedTags, boolean acceptOtherTags) { + public static VideoDescriptor getStageVideo(Event event, String localeName, Collection rankedTags, boolean acceptOtherTags) { VideoDescriptor bestMatch = null; for (VideoDescriptor videoCandidate : event.getVideos()) { - if(!acceptedTypes.contains(videoCandidate.getMimeType())) { + if(!MediaConstants.SUPPORTED_VIDEO_TYPES.contains(videoCandidate.getMimeType())) { continue; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index f9cb6174a41..84aa88cff38 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -2,8 +2,6 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; @@ -15,11 +13,9 @@ 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.MediaConstants; import com.sap.sse.common.impl.MillisecondsTimePoint; -import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; public class GetEventOverviewStageAction implements Action> { - private static final Set mimeTypes = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); private static final Collection rankedTags = Arrays.asList(MediaConstants.LIVESTREAM, MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); private static final Collection rankedTagsFinished = Arrays.asList(MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); @@ -58,7 +54,7 @@ public class GetEventOverviewStageAction implements Action tags = state == EventState.FINISHED ? rankedTagsFinished : rankedTags; - VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocaleName(), mimeTypes, tags, true); + VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocaleName(), tags, true); if(stageVideo != null) { return new EventOverviewVideoStageDTO(EventOverviewVideoStageDTO.Type.MEDIA, stageVideo.getMimeType(), stageVideo.getURL().toString()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index f2ffa6f8ae8..0ed964e12d6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -1,7 +1,11 @@ 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.MimeType; public final class MediaConstants { @@ -14,6 +18,7 @@ public final class MediaConstants { public static final String LOCALE_EN = LOCALE_PREFIX + "en"; public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor" }); public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED, LOCALE_PREFIX + "de", LOCALE_EN, LOCALE_PREFIX + "ru", LOCALE_PREFIX + "cn" }); + public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); private MediaConstants() { } From 205062743304fb6a0279aa147af472d14dd39cc9 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 9 Jun 2015 19:10:01 +0200 Subject: [PATCH 054/117] added Json serializer and deserializer code for images and videos attribute of event --- .../impl/EventBaseJsonDeserializer.java | 123 +++++++++++++++--- .../gateway/deserialization/impl/Helpers.java | 15 +++ .../impl/EventBaseJsonSerializer.java | 64 +++++++++ 3 files changed, 183 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 9139a137641..71bbd40ecf5 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -17,7 +17,13 @@ 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.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 EventBaseJsonDeserializer implements JsonDeserializer { private final JsonDeserializer venueDeserializer; @@ -28,22 +34,22 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { 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); + String logoImageURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_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 leaderboardGroups = new ArrayList(); if (leaderboardGroupsJson != null) { for (Object lgJson : leaderboardGroupsJson) { @@ -67,28 +73,28 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { throw new JsonDeserializationException("Error deserializing logo image URL for event "+name, 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))); + result.setImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_IMAGE_URLS))); } catch (MalformedURLException e) { throw new JsonDeserializationException("Error deserializing image URLs for event "+name, 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))); + result.setVideoURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_VIDEO_URLS))); } catch (MalformedURLException e) { throw new JsonDeserializationException("Error deserializing video URLs for event "+name, 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))); + result.setSponsorImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS))); } catch (MalformedURLException e) { throw new JsonDeserializationException("Error deserializing sponsor image URLs for event "+name, e); } } - JSONArray imageSizes = (JSONArray) object.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES); + JSONArray imageSizes = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES); if (imageSizes != null) { for (Object imageURLAndSizeObject : imageSizes) { JSONObject imageURLAndSizeJson = (JSONObject) imageURLAndSizeObject; @@ -103,9 +109,89 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } } } + 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); + } + } + } + return result; } + + 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); + Integer imageWidth = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH_IN_PX); + Integer imageHeight = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT_IN_PX); + Long createdAtDateInMs = (Long) imageJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); + TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs) : null; + JSONArray tags = (JSONArray) imageJson.get(EventBaseJsonSerializer.FIELD_TAGS); + List imageTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + imageTags.add((String) tagObject); + } + } + image = new ImageDescriptorImpl(imageURL, createdAtDate); + image.setCopyright(copyright); + image.setTitle(title); + image.setSubtitle(subtitle); + image.setTags(imageTags); + if (imageWidth != null && imageHeight != null) { + image.setSize(imageWidth, imageHeight); + } + } + 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); + Object mimeTypeRaw = videoJson.get(EventBaseJsonSerializer.FIELD_MIMETYPE); + MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + Long createdAtDateInMs = (Long) videoJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); + TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs) : 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 videoTags = new ArrayList(); + if (tags != null) { + for (Object tagObject : tags) { + videoTags.add((String) tagObject); + } + } + video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate); + video.setCopyright(copyright); + video.setTitle(title); + video.setSubtitle(subtitle); + video.setTags(videoTags); + video.setLengthInSeconds(lengthInSeconds); + video.setThumbnailURL(thumbnailURL); + } + return video; + } + private Iterable getURLsFromStrings(JSONArray strings) throws MalformedURLException { List result = new ArrayList(); if (strings != null) { @@ -115,5 +201,4 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } return result; } - } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/Helpers.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/Helpers.java index 499f2d60e88..6762c862c3e 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/Helpers.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/Helpers.java @@ -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()); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index 82c729f0025..9ec0dc9acab 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -12,7 +12,9 @@ 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.ImageDescriptor; import com.sap.sse.common.media.ImageSize; +import com.sap.sse.common.media.VideoDescriptor; public class EventBaseJsonSerializer implements JsonSerializer { private static final Logger logger = Logger.getLogger(EventBaseJsonSerializer.class.getName()); @@ -31,9 +33,26 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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_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 venueSerializer; private final JsonSerializer leaderboardGroupBaseSerializer; @@ -71,9 +90,54 @@ public class EventBaseJsonSerializer implements JsonSerializer { for (URL sponsorImageURL : event.getSponsorImageURLs()) { addImageSize(sponsorImageURL, imageSizes, event); } + JSONArray jsonImages = new JSONArray(); + for(ImageDescriptor imageDescriptor: event.getImages()) { + addImage(imageDescriptor, jsonImages); + } + 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_TITLE, image.getTitle()); + imageJson.put(FIELD_SUBTITLE, image.getSubtitle()); + imageJson.put(FIELD_MIMETYPE, image.getMimeType()); + 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_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()); + 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); + } + videosJson.add(videoJson); + } + /** * If eventBase knows the size of the image with URL imageURL, that size is serialized as * JSON object to imageSizes From fb80b8c2860e8e8b2af5e257d10fafc91781228e Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 10 Jun 2015 13:28:51 +0200 Subject: [PATCH 055/117] added json serialize/deserialize tests for images/videos of EventBase --- .../impl/EventBaseJsonSerializer.java | 5 +- ...JsonSerializerWithImagesAndVideosTest.java | 183 ++++++++++++++++++ 2 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index 9ec0dc9acab..14dece4d01f 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -108,7 +108,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { imageJson.put(FIELD_SOURCE_URL, image.getURL().toString()); imageJson.put(FIELD_TITLE, image.getTitle()); imageJson.put(FIELD_SUBTITLE, image.getSubtitle()); - imageJson.put(FIELD_MIMETYPE, image.getMimeType()); + 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()); @@ -127,7 +127,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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()); + 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()); @@ -135,6 +135,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { for (String tag : video.getTags()) { tags.add(tag); } + videoJson.put(FIELD_TAGS, tags); videosJson.add(videoJson); } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java new file mode 100644 index 00000000000..69132046fed --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java @@ -0,0 +1,183 @@ +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.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 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 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 images = new ArrayList(); + private List videos = new ArrayList(); + + 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.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.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); + } + + @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.emptySet()); + when(event.getVideoURLs()).thenReturn(Collections.emptySet()); + when(event.getSponsorImageURLs()).thenReturn(Collections.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.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(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(videoTitle, video1.getTitle()); + assertEquals(videoSubtitle, video1.getSubtitle()); + assertEquals(videoThumbnailURL, video1.getThumbnailURL()); + assertEquals(videoLengthInSeconds, video1.getLengthInSeconds()); + assertEquals(4, Util.size(video1.getTags())); + } + +} From 87a56ea669e4e52872ead8ebf154f829a54bcd65 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 10 Jun 2015 17:13:43 +0200 Subject: [PATCH 056/117] first draft for news providers, news service and new items API in a separate bundle project --- java/com.sap.sailing.news/.classpath | 7 +++ java/com.sap.sailing.news/.gitignore | 1 + java/com.sap.sailing.news/.project | 28 +++++++++ .../.settings/org.eclipse.jdt.core.prefs | 7 +++ .../.settings/org.eclipse.pde.core.prefs | 3 + .../com.sap.sailing.news/META-INF/MANIFEST.MF | 19 ++++++ java/com.sap.sailing.news/build.properties | 4 ++ java/com.sap.sailing.news/pom.xml | 12 ++++ .../src/com/sap/sailing/news/Activator.java | 24 ++++++++ .../com/sap/sailing/news/LimitedQueue.java | 21 +++++++ .../src/com/sap/sailing/news/NewsItem.java | 24 ++++++++ .../com/sap/sailing/news/NewsProvider.java | 14 +++++ .../sailing/news/NewsProviderRegistry.java | 10 ++++ .../src/com/sap/sailing/news/NewsService.java | 13 +++++ .../sailing/news/impl/AbstractNewsItem.java | 58 +++++++++++++++++++ .../news/impl/NewsProviderRegistryImpl.java | 31 ++++++++++ .../sailing/news/impl/NewsServiceImpl.java | 49 ++++++++++++++++ .../news/impl/SimpleDemoNewsProvider.java | 38 ++++++++++++ 18 files changed, 363 insertions(+) create mode 100644 java/com.sap.sailing.news/.classpath create mode 100644 java/com.sap.sailing.news/.gitignore create mode 100644 java/com.sap.sailing.news/.project create mode 100644 java/com.sap.sailing.news/.settings/org.eclipse.jdt.core.prefs create mode 100644 java/com.sap.sailing.news/.settings/org.eclipse.pde.core.prefs create mode 100644 java/com.sap.sailing.news/META-INF/MANIFEST.MF create mode 100644 java/com.sap.sailing.news/build.properties create mode 100644 java/com.sap.sailing.news/pom.xml create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/LimitedQueue.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java diff --git a/java/com.sap.sailing.news/.classpath b/java/com.sap.sailing.news/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/java/com.sap.sailing.news/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/java/com.sap.sailing.news/.gitignore b/java/com.sap.sailing.news/.gitignore new file mode 100644 index 00000000000..e660fd93d31 --- /dev/null +++ b/java/com.sap.sailing.news/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/java/com.sap.sailing.news/.project b/java/com.sap.sailing.news/.project new file mode 100644 index 00000000000..cba19cda41d --- /dev/null +++ b/java/com.sap.sailing.news/.project @@ -0,0 +1,28 @@ + + + com.sap.sailing.news + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/java/com.sap.sailing.news/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sailing.news/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..0c68a61dca8 --- /dev/null +++ b/java/com.sap.sailing.news/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java/com.sap.sailing.news/.settings/org.eclipse.pde.core.prefs b/java/com.sap.sailing.news/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..f29e940a005 --- /dev/null +++ b/java/com.sap.sailing.news/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/java/com.sap.sailing.news/META-INF/MANIFEST.MF b/java/com.sap.sailing.news/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..90e7b397b48 --- /dev/null +++ b/java/com.sap.sailing.news/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Shared sailing news APIs +Bundle-SymbolicName: com.sap.sailing.news +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: com.sap.sailing.news.Activator +Bundle-Vendor: SAP +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Export-Package: com.sap.sailing.news, + com.sap.sailing.news.impl +Import-Package: com.sap.sailing.domain.base.impl, + com.sap.sailing.domain.common, + com.sap.sailing.domain.common.impl, + com.sap.sailing.domain.persistence, + com.sap.sailing.server, + org.osgi.framework;version="1.5.0", + org.osgi.util.tracker;version="1.5.1" +Require-Bundle: com.sap.sse.common diff --git a/java/com.sap.sailing.news/build.properties b/java/com.sap.sailing.news/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/java/com.sap.sailing.news/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/java/com.sap.sailing.news/pom.xml b/java/com.sap.sailing.news/pom.xml new file mode 100644 index 00000000000..0748fb121e5 --- /dev/null +++ b/java/com.sap.sailing.news/pom.xml @@ -0,0 +1,12 @@ + + + 4.0.0 + + root + com.sap.sailing + 1.0.0-SNAPSHOT + + com.sap.sailing.news + eclipse-plugin + diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java new file mode 100644 index 00000000000..18e8b37e4de --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java @@ -0,0 +1,24 @@ +package com.sap.sailing.news; + +import java.util.logging.Logger; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +import com.sap.sailing.news.impl.NewsProviderRegistryImpl; +import com.sap.sailing.news.impl.NewsServiceImpl; + +public class Activator implements BundleActivator { + private static final Logger logger = Logger.getLogger(Activator.class.getName()); + + public void start(BundleContext context) throws Exception { + NewsProviderRegistry providerRegistry = new NewsProviderRegistryImpl(); + NewsService newsService = new NewsServiceImpl(providerRegistry); + context.registerService(NewsService.class, newsService, null); + context.registerService(NewsProviderRegistry.class, providerRegistry, null); + logger.info("News Service registered."); + } + + public void stop(BundleContext bundleContext) throws Exception { + } +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/LimitedQueue.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/LimitedQueue.java new file mode 100644 index 00000000000..5c330de04c4 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/LimitedQueue.java @@ -0,0 +1,21 @@ +package com.sap.sailing.news; + +import java.util.LinkedList; + +public class LimitedQueue extends LinkedList { + private static final long serialVersionUID = 9026209104040359183L; + private int limit; + + public LimitedQueue(int limit) { + this.limit = limit; + } + + @Override + public boolean add(E o) { + boolean added = super.add(o); + while (added && size() > limit) { + super.remove(); + } + return added; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java new file mode 100644 index 00000000000..53cc7d7c17d --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java @@ -0,0 +1,24 @@ +package com.sap.sailing.news; + +import java.net.URL; +import java.util.Date; +import java.util.UUID; + +/** + * An interface for a generic news item + * @author Frank + * + */ +public interface NewsItem { + UUID getId(); + + String getCategory(); + + String getTitle(); + + String getMessage(); + + URL getRelatedItemLink(); + + Date getCreatedAtDate(); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java new file mode 100644 index 00000000000..3a1a899d344 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java @@ -0,0 +1,14 @@ +package com.sap.sailing.news; + +import java.util.Date; +import java.util.Iterator; + +public interface NewsProvider { + Iterator getNews(); + + Iterator getNews(Date startingFrom); + + boolean hasNews(Date startingFrom); + + boolean hasNews(); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java new file mode 100644 index 00000000000..a4e98b8d954 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java @@ -0,0 +1,10 @@ +package com.sap.sailing.news; + +public interface NewsProviderRegistry { + boolean registerNewsProvider(NewsProvider provider); + + boolean deregisterNewsProvider(NewsProvider provider); + + Iterable getNewsProvider(); +} + \ No newline at end of file diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java new file mode 100644 index 00000000000..585ee05a75e --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java @@ -0,0 +1,13 @@ +package com.sap.sailing.news; + +import java.util.Date; + +public interface NewsService { + Iterable getAllNews(); + + Iterable getNews(Date startingFrom); + + Iterable getNewsByCategory(String category); + + Iterable getNewsByCategory(Date startingFrom, String category); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java new file mode 100644 index 00000000000..36168f415c7 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java @@ -0,0 +1,58 @@ +package com.sap.sailing.news.impl; + +import java.net.URL; +import java.util.Date; +import java.util.UUID; + +import com.sap.sailing.news.NewsItem; + +public class AbstractNewsItem implements NewsItem { + private final UUID id; + + private String category; + + private String title; + + private String message; + + private URL relatedItemLink; + + private Date createdAtDate; + + public AbstractNewsItem(String title, String message, Date createdAtDate, String category) { + this(title, message, createdAtDate, category, null); + } + + public AbstractNewsItem(String title, String message, Date createdAtDate, String category, URL relatedItemLink) { + this.title = title; + this.message = message; + this.category = category; + this.createdAtDate = createdAtDate; + this.relatedItemLink = relatedItemLink; + this.id = UUID.randomUUID(); + } + + public String getCategory() { + return category; + } + + public String getTitle() { + return title; + } + + public String getMessage() { + return message; + } + + public URL getRelatedItemLink() { + return relatedItemLink; + } + + public Date getCreatedAtDate() { + return createdAtDate; + } + + public UUID getId() { + return id; + } +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java new file mode 100644 index 00000000000..343db870b42 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java @@ -0,0 +1,31 @@ +package com.sap.sailing.news.impl; + +import java.util.HashSet; +import java.util.Set; + +import com.sap.sailing.news.NewsProvider; +import com.sap.sailing.news.NewsProviderRegistry; + +public class NewsProviderRegistryImpl implements NewsProviderRegistry { + private Set newsProvider; + + public NewsProviderRegistryImpl() { + newsProvider = new HashSet(); + } + + @Override + public boolean registerNewsProvider(NewsProvider provider) { + return newsProvider.add(provider); + } + + @Override + public boolean deregisterNewsProvider(NewsProvider provider) { + return newsProvider.remove(provider); + } + + @Override + public Iterable getNewsProvider() { + return newsProvider; + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java new file mode 100644 index 00000000000..41348a0a77b --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java @@ -0,0 +1,49 @@ +package com.sap.sailing.news.impl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import com.sap.sailing.news.NewsItem; +import com.sap.sailing.news.NewsProvider; +import com.sap.sailing.news.NewsProviderRegistry; +import com.sap.sailing.news.NewsService; +import com.sap.sse.common.Util; + +public class NewsServiceImpl implements NewsService { + private final NewsProviderRegistry providerRegistry; + + public NewsServiceImpl(NewsProviderRegistry providerRegistry) { + this.providerRegistry = providerRegistry; + } + + @Override + public Iterable getAllNews() { + List result = new ArrayList<>(); + for(NewsProvider provider: providerRegistry.getNewsProvider()) { + Iterator news = provider.getNews(); + } + return result; + } + + @Override + public Iterable getNews(Date startingFrom) { + List result = new ArrayList<>(); + for(NewsProvider provider: providerRegistry.getNewsProvider()) { + Iterator news = provider.getNews(startingFrom); + } + return result; + } + + @Override + public Iterable getNewsByCategory(String category) { + return getAllNews(); + } + + @Override + public Iterable getNewsByCategory(Date startingFrom, String category) { + return getNews(startingFrom); + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java new file mode 100644 index 00000000000..ca305897251 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java @@ -0,0 +1,38 @@ +package com.sap.sailing.news.impl; + +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; + +import com.sap.sailing.news.LimitedQueue; +import com.sap.sailing.news.NewsItem; +import com.sap.sailing.news.NewsProvider; + +public class SimpleDemoNewsProvider implements NewsProvider { + private final LinkedList newsQueue; + + public SimpleDemoNewsProvider() { + newsQueue = new LimitedQueue(10); + } + + @Override + public Iterator getNews() { + return newsQueue.iterator(); + } + + @Override + public Iterator getNews(Date startingFrom) { + return newsQueue.iterator(); + } + + @Override + public boolean hasNews(Date startingFrom) { + return newsQueue.size() > 0; + } + + @Override + public boolean hasNews() { + return newsQueue.size() > 0; + } + +} From c69bb5447af83b1017e8d53a4123c6e6d6c76a1b Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 10 Jun 2015 17:14:53 +0200 Subject: [PATCH 057/117] added com.sap.sailing.news to main pom.xml --- java/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/pom.xml b/java/pom.xml index 220fed91e88..39a382ba66f 100755 --- a/java/pom.xml +++ b/java/pom.xml @@ -50,6 +50,7 @@ com.sap.sailing.domain.swisstimingadapter com.sap.sailing.domain.swisstimingadapter.persistence com.sap.sailing.domain.swisstimingreplayadapter + com.sap.sailing.news com.sap.sailing.declination com.sap.sailing.udpconnector com.sap.sailing.expeditionconnector From 0dab46f602bf1a5c97431ae0014cd675f0832274 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 13:12:53 +0200 Subject: [PATCH 058/117] Added locale field for media --- .../com/sap/sse/gwt/client/media/AbstractMediaDTO.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java index 8111fd3fc3b..914371e3a15 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -21,6 +21,8 @@ public abstract class AbstractMediaDTO implements IsSerializable { protected List tags = new ArrayList(); protected String sourceRef; + + private String locale; /** for GWT */ protected AbstractMediaDTO() { @@ -90,4 +92,11 @@ public abstract class AbstractMediaDTO implements IsSerializable { this.sourceRef = sourceRef; } + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } } From 08cb8316bfebad47a8a1a5c2221d5ba3f1168085 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 13:36:43 +0200 Subject: [PATCH 059/117] Added locale field to media model --- .../gwt/ui/server/SailingServiceImpl.java | 18 ++++++++++++++++++ .../common/media/AbstractMediaDescriptor.java | 13 +++++++++++++ .../sap/sse/common/media/MediaDescriptor.java | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index da637907ae0..189e6077a38 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3491,6 +3491,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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); } @@ -3510,6 +3511,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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); } @@ -3523,6 +3525,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S result.setSubtitle(image.getSubtitle()); result.setMimeType(image.getMimeType()); result.setSizeInPx(image.getWidthInPx(), image.getHeightInPx()); + result.setLocale(toLocaleName(image.getLocale())); List tags = new ArrayList(); for(String tag: image.getTags()) { tags.add(tag); @@ -3539,6 +3542,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S result.setSubtitle(video.getSubtitle()); result.setThumbnailRef(video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null); result.setLengthInSeconds(video.getLengthInSeconds()); + result.setLocale(toLocaleName(video.getLocale())); List tags = new ArrayList(); for(String tag: video.getTags()) { tags.add(tag); @@ -3546,6 +3550,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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()); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java index 7862e2b2a69..a7df1a2584f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java @@ -3,6 +3,7 @@ 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; @@ -30,6 +31,8 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial protected Set tags = new LinkedHashSet(); protected URL url; + + protected Locale locale; /** * Media item with minimal set of information @@ -115,4 +118,14 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial public void setCopyright(String copyright) { this.copyright = copyright; } + + @Override + public Locale getLocale() { + return locale; + } + + @Override + public void setLocale(Locale locale) { + this.locale = locale; + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java index afe6c8d43ce..5616c761950 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java @@ -2,6 +2,7 @@ package com.sap.sse.common.media; import java.io.Serializable; import java.net.URL; +import java.util.Locale; import com.sap.sse.common.TimePoint; @@ -28,4 +29,7 @@ public interface MediaDescriptor extends Serializable { String getCopyright(); void setCopyright(String copyright); + + Locale getLocale(); + void setLocale(Locale locale); } From 9bcd3f61e17bc42c1ebfa7db4f718a82ab040e93 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 13:59:49 +0200 Subject: [PATCH 060/117] Implemented language selection for video list of event --- .../gwt/ui/adminconsole/VideoDialog.java | 43 ++++++++++++++++--- .../gwt/ui/adminconsole/VideoEditDialog.java | 1 + .../ui/adminconsole/VideosListComposite.java | 8 ++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index a250cb6f3e3..5682a23d45a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -5,6 +5,7 @@ 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; @@ -15,6 +16,7 @@ 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; @@ -24,6 +26,7 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.media.VideoDTO; public abstract class VideoDialog extends DataEntryDialog { + private static final String NO_LOCALE_TEXT = "---"; protected final StringMessages stringMessages; protected final URLFieldWithFileUpload videoURLAndUploadComposite; protected final Date creationDate; @@ -32,6 +35,7 @@ public abstract class VideoDialog extends DataEntryDialog { protected TextBox subtitleTextBox; protected TextBox copyrightTextBox; protected final ListBox mimeTypeListBox; + protected final ListBox localeListBox; protected IntegerBox lengthIntegerBox; protected final URLFieldWithFileUpload thumbnailURLAndUploadComposite; protected StringListInlineEditorComposite tagsListEditor; @@ -73,6 +77,14 @@ public abstract class VideoDialog extends DataEntryDialog { 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() { @Override @@ -93,6 +105,7 @@ public abstract class VideoDialog extends DataEntryDialog { result.setTitle(titleTextBox.getValue()); result.setSubtitle(subtitleTextBox.getValue()); result.setCopyright(copyrightTextBox.getValue()); + result.setLocale(getSelectedLocale()); List tags = new ArrayList(); for (String tag: tagsListEditor.getValue()) { tags.add(tag); @@ -119,6 +132,20 @@ public abstract class VideoDialog extends DataEntryDialog { 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(); @@ -128,7 +155,7 @@ public abstract class VideoDialog extends DataEntryDialog { panel.add(additionalWidget); } - Grid formGrid = new Grid(9, 2); + Grid formGrid = new Grid(10, 2); panel.add(formGrid); formGrid.setWidget(0, 0, new Label("Created at:")); @@ -145,13 +172,15 @@ public abstract class VideoDialog extends DataEntryDialog { formGrid.setWidget(4, 1, subtitleTextBox); formGrid.setWidget(5, 0, new Label("Copyright:")); formGrid.setWidget(5, 1, copyrightTextBox); - formGrid.setWidget(6, 0, new Label("Tags:")); - formGrid.setWidget(6, 1, tagsListEditor); + 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(7, 0, new Label("Video-Length (s):")); - formGrid.setWidget(7, 1, lengthIntegerBox); - formGrid.setWidget(8, 0, new Label("Thumbnail-URL:")); - formGrid.setWidget(8, 1, thumbnailURLAndUploadComposite); + 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; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java index b8e63113d73..c8c2f10f5a4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java @@ -23,5 +23,6 @@ public class VideoEditDialog extends VideoDialog { tags.addAll(video.getTags()); tagsListEditor.setValue(tags); setSelectedMimeType(video.getMimeType()); + setSelectedLocale(video.getLocale()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java index b9ed5d13892..ee17228b92c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java @@ -143,6 +143,13 @@ public class VideosListComposite extends Composite { return video.getMimeType() != null ? video.getMimeType().name() : ""; } }; + + TextColumn localeColumn = new TextColumn() { + @Override + public String getValue(VideoDTO video) { + return video.getLocale() != null ? video.getLocale() : ""; + } + }; SafeHtmlCell tagsCell = new SafeHtmlCell(); Column tagsColumn = new Column(tagsCell) { @@ -187,6 +194,7 @@ public class VideosListComposite extends Composite { 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)); From 09055c450acd49b669dd99cfc8b708c1b7c6fab9 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 14:00:43 +0200 Subject: [PATCH 061/117] Implemented stage video selection based on video's locale attribute --- .../sailing/gwt/server/HomeServiceUtil.java | 33 +++++++++---------- .../event/GetEventOverviewStageAction.java | 2 +- .../gwt/ui/shared/media/MediaConstants.java | 4 +-- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index ecdf806c803..6644e7952f5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -6,6 +6,7 @@ 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 com.sap.sailing.domain.base.Competitor; @@ -29,6 +30,7 @@ import com.sap.sse.common.media.MediaDescriptor; import com.sap.sse.common.media.VideoDescriptor; public final class HomeServiceUtil { + private HomeServiceUtil() { } @@ -388,7 +390,7 @@ public final class HomeServiceUtil { return Util.get(urls, new Random(size).nextInt(size)); } - public static VideoDescriptor getStageVideo(Event event, String localeName, Collection rankedTags, boolean acceptOtherTags) { + public static VideoDescriptor getStageVideo(Event event, Locale locale, Collection rankedTags, boolean acceptOtherTags) { VideoDescriptor bestMatch = null; for (VideoDescriptor videoCandidate : event.getVideos()) { @@ -400,7 +402,7 @@ public final class HomeServiceUtil { continue; } - LocaleMatch localeMatch = matchLocale(videoCandidate, localeName); + LocaleMatch localeMatch = matchLocale(videoCandidate, locale); if(localeMatch == LocaleMatch.NO_MATCH) { continue; } @@ -411,7 +413,7 @@ public final class HomeServiceUtil { } int compareByTag = compareByTag(videoCandidate, bestMatch, rankedTags); - if(compareByTag > 0 || (compareByTag == 0 && isBetter(videoCandidate, bestMatch, localeName))) { + if(compareByTag > 0 || (compareByTag == 0 && isBetter(videoCandidate, bestMatch, locale))) { bestMatch = videoCandidate; continue; } @@ -431,9 +433,9 @@ public final class HomeServiceUtil { return 0; } - private static boolean isBetter(VideoDescriptor candidate, VideoDescriptor reference, String localeName) { - LocaleMatch localeMatch = matchLocale(candidate, localeName); - LocaleMatch localeMatchRef = matchLocale(reference, localeName); + 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; } @@ -460,20 +462,15 @@ public final class HomeServiceUtil { PERFECT, NOT_TAGGED, EN_FALLBACK, NO_MATCH } - private static LocaleMatch matchLocale(VideoDescriptor videoCandidate, String localeName) { - boolean hasLocaleTag = false; - boolean hasEn = false; - for(String tag : videoCandidate.getTags()) { - if(tag.equals(MediaConstants.LOCALE_PREFIX + localeName)) { - return LocaleMatch.PERFECT; - } - hasLocaleTag |= tag.startsWith(MediaConstants.LOCALE_PREFIX); - hasEn |= tag.equals(MediaConstants.LOCALE_EN); - } - if(!hasLocaleTag) { + private static LocaleMatch matchLocale(VideoDescriptor videoCandidate, Locale locale) { + Locale localeOfCandidate = videoCandidate.getLocale(); + if(localeOfCandidate == null) { return LocaleMatch.NOT_TAGGED; } - if(hasEn) { + if(videoCandidate.getLocale().equals(locale)) { + return LocaleMatch.PERFECT; + } + if(videoCandidate.getLocale().equals(Locale.ENGLISH)) { return LocaleMatch.EN_FALLBACK; } return LocaleMatch.NO_MATCH; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 84aa88cff38..894a51a9b94 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -54,7 +54,7 @@ public class GetEventOverviewStageAction implements Action tags = state == EventState.FINISHED ? rankedTagsFinished : rankedTags; - VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocaleName(), tags, true); + VideoDescriptor stageVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocale(), tags, true); if(stageVideo != null) { return new EventOverviewVideoStageDTO(EventOverviewVideoStageDTO.Type.MEDIA, stageVideo.getMimeType(), stageVideo.getURL().toString()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index 0ed964e12d6..03e705a33ea 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -14,10 +14,8 @@ public final class MediaConstants { public static final String HIGHLIGHT = "Highlight"; public static final String LIVESTREAM = "Livestream"; public static final String FEATURED = "Featured"; - public static final String LOCALE_PREFIX = "Locale_"; - public static final String LOCALE_EN = LOCALE_PREFIX + "en"; public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor" }); - public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED, LOCALE_PREFIX + "de", LOCALE_EN, LOCALE_PREFIX + "ru", LOCALE_PREFIX + "cn" }); + public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED }); public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); private MediaConstants() { From c8d1439b9c451d8ec5296bbe65fccc2b5bc9d42d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 14:33:44 +0200 Subject: [PATCH 062/117] The old video/image link lists are automatically filled from the new Media model when saving an event -> this is relevant to not lose data when downgrading to an old version --- .../ui/adminconsole/EventListComposite.java | 4 +- .../StructureImportManagementPanel.java | 3 +- .../sailing/gwt/ui/client/SailingService.java | 6 +-- .../gwt/ui/client/SailingServiceAsync.java | 6 +-- .../gwt/ui/server/SailingServiceImpl.java | 41 +++++++++++-------- .../gwt/ui/shared/media/MediaConstants.java | 3 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index edcba5bcfc1..4b976c37b41 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -492,7 +492,6 @@ public class EventListComposite extends Composite implements EventsRefresher, Le updatedEvent.startDate, updatedEvent.endDate, updatedEvent.venue, updatedEvent.isPublic, updatedEventLeaderboardGroupIds, updatedEvent.getOfficialWebsiteURL(), updatedEvent.getLogoImageURL(), - updatedEvent.getImageURLs(), updatedEvent.getVideoURLs(), updatedEvent.getSponsorImageURLs(), updatedEvent.getImages(), updatedEvent.getVideos(), new AsyncCallback() { @Override @@ -564,8 +563,7 @@ 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.getImages(), newEvent.getVideos(), + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImages(), newEvent.getVideos(), newEvent.getLogoImageURL(), newEvent.getOfficialWebsiteURL(), new AsyncCallback() { @Override public void onFailure(Throwable t) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java index e9fa6391bb4..e4ee01bc61c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java @@ -246,8 +246,7 @@ 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.getImages(), newEvent.getVideos(), newEvent.getLogoImageURL(), + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImages(), newEvent.getVideos(), newEvent.getLogoImageURL(), newEvent.getOfficialWebsiteURL(), new AsyncCallback() { @Override public void onFailure(Throwable t) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 5f9b628e507..279f6a49688 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -296,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 leaderboardGroupIds, String officialWebsiteURL, - String logoImageURL, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs, Iterable images, Iterable videos) throws Exception; + String logoImageURL, Iterable images, Iterable videos) throws Exception; EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, Iterable imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + boolean isPublic, List courseAreaNames, Iterable images, Iterable videos, String logoImageURL, String officialWebsiteURL) throws Exception; void removeEvent(UUID eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 7fa37e45a6d..3f6a088f5c8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -367,13 +367,11 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM void removeEvents(Collection eventIds, AsyncCallback asyncCallback); void createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, - List courseAreaNames, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs, Iterable images, Iterable videos, String logoImageURL, String officialWebsiteURL, AsyncCallback callback); + List courseAreaNames, Iterable images, Iterable videos, String logoImageURL, String officialWebsiteURL, AsyncCallback callback); void updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, - String logoImageURL, Iterable imageURLs, Iterable videoURLs, - Iterable sponsorImageURLs, Iterable images, Iterable videos, AsyncCallback callback); + String logoImageURL, Iterable images, Iterable videos, AsyncCallback callback); void createCourseArea(UUID eventId, String courseAreaName, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 189e6077a38..c5913070dfd 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -324,6 +324,7 @@ import com.sap.sailing.gwt.ui.shared.RegattaLogEventDTO; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO.ScoreCorrectionEntryDTO; +import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sailing.gwt.ui.shared.RemoteSailingServerReferenceDTO; import com.sap.sailing.gwt.ui.shared.ReplicaDTO; import com.sap.sailing.gwt.ui.shared.ReplicationMasterDTO; @@ -441,6 +442,7 @@ 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.AbstractMediaDTO; import com.sap.sse.gwt.client.media.ImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.server.filestorage.FileStorageServiceDTOUtils; @@ -3300,21 +3302,20 @@ 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 leaderboardGroupIds, String officialWebsiteURLString, - String logoImageURLString, Iterable imageURLStrings, Iterable videoURLStrings, - Iterable sponsorImageURLStrings, Iterable images, Iterable videos) throws MalformedURLException { + String logoImageURLString, Iterable images, Iterable 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 imageURLs = createURLsFromStrings(imageURLStrings); - List videoURLs = createURLsFromStrings(videoURLStrings); - List sponsorimagieURLs = createURLsFromStrings(sponsorImageURLStrings); + List imageURLs = createURLsFromMedia(images, MediaConstants.SPONSOR, null); + List videoURLs = createURLsFromMedia(videos, null, null); + List sponsorImageURLs = createURLsFromMedia(images, null, MediaConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, imageURLs, videoURLs, - sponsorimagieURLs, eventImages, eventVideos)); + sponsorImageURLs, eventImages, eventVideos)); return getEventById(eventId, false); } @@ -3323,29 +3324,36 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S * @return * @throws MalformedURLException */ - private List createURLsFromStrings(Iterable urlStrings) throws MalformedURLException { - List imageURLs = new ArrayList<>(); - for (String imageURLString : urlStrings) { - imageURLs.add(new URL(imageURLString)); + private List createURLsFromMedia(Iterable media, String blacklistTag, String whilelistTag) throws MalformedURLException { + List result = new ArrayList<>(); + for (AbstractMediaDTO mediaEntry : media) { + if(blacklistTag != null && mediaEntry.getTags().contains(blacklistTag)) { + continue; + } + if(whilelistTag != null && !mediaEntry.getTags().contains(whilelistTag)) { + continue; + } + result.add(new URL(mediaEntry.getSourceRef())); } - return imageURLs; + return result; } @Override public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, Iterable imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + boolean isPublic, List courseAreaNames, Iterable images, Iterable videos, String logoImageURLAsString, String officialWebsiteURLAsString) throws MalformedURLException { UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; + List imageURLs = createURLsFromMedia(images, MediaConstants.SPONSOR, null); + List videoURLs = createURLsFromMedia(videos, null, null); + List sponsorImageURLs = createURLsFromMedia(images, null, MediaConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid, - createURLsFromStrings(imageURLs), createURLsFromStrings(videoURLs), - createURLsFromStrings(sponsorImageURLs), + imageURLs, videoURLs, sponsorImageURLs, eventImages, eventVideos, logoImageURLAsString == null ? null : new URL(logoImageURLAsString), officialWebsiteURLAsString == null ? null : new URL(officialWebsiteURLAsString))); @@ -4193,8 +4201,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } 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.getImages(), newEvent.getVideos()); + newEvent.getOfficialWebsiteURL(), newEvent.getImages(), newEvent.getVideos()); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index 03e705a33ea..46efef132c4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -11,10 +11,11 @@ public final class MediaConstants { public static final String STAGE = "Stage"; public static final String TEASER = "Teaser"; + public static final String SPONSOR = "Sponsor"; public static final String HIGHLIGHT = "Highlight"; public static final String LIVESTREAM = "Livestream"; public static final String FEATURED = "Featured"; - public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, "Sponsor" }); + public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, SPONSOR }); public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED }); public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); From 87aaea0280b428103364de491705a48d04432945 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 14:40:46 +0200 Subject: [PATCH 063/117] Using correct Event ID of Kieler Woche 2015 --- .../main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 0db0d71e9cf..478f84f70b1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -345,8 +345,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/"); } From 8beb344d5c390e5b2db48f2cc2e54c1dda1c4e40 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 11 Jun 2015 14:59:20 +0200 Subject: [PATCH 064/117] changed generic news service to an event specific newsServce --- .../META-INF/MANIFEST.MF | 3 +- .../sailing/gwt/server/HomeServiceImpl.java | 63 +++++++++++++------ .../sailing/gwt/ui/client/HomeService.java | 7 ++- .../gwt/ui/client/HomeServiceAsync.java | 5 ++ .../com.sap.sailing.news/META-INF/MANIFEST.MF | 11 ++-- .../src/com/sap/sailing/news/Activator.java | 17 ++--- .../com/sap/sailing/news/EventNewsItem.java | 12 ++++ .../sap/sailing/news/EventNewsProvider.java | 16 +++++ .../news/EventNewsProviderRegistry.java | 10 +++ .../sap/sailing/news/EventNewsService.java | 16 +++++ .../com/sap/sailing/news/NewsProvider.java | 14 ----- .../sailing/news/NewsProviderRegistry.java | 10 --- .../src/com/sap/sailing/news/NewsService.java | 13 ---- .../news/impl/AbstractEventNewsItem.java | 26 ++++++++ .../impl/EventNewsProviderRegistryImpl.java | 31 +++++++++ .../news/impl/EventNewsServiceImpl.java | 51 +++++++++++++++ .../news/impl/NewsProviderRegistryImpl.java | 31 --------- .../sailing/news/impl/NewsServiceImpl.java | 49 --------------- .../impl/SimpleDemoEventNewsProvider.java | 46 ++++++++++++++ .../news/impl/SimpleDemoNewsProvider.java | 38 ----------- 20 files changed, 279 insertions(+), 190 deletions(-) create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsItem.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProvider.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProviderRegistry.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsService.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsProviderRegistryImpl.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java diff --git a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF index 5dc0cd4fa7b..adfc93badd7 100644 --- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF @@ -47,7 +47,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sse.security.common, com.sap.sse.filestorage, org.apache.shiro.core;bundle-version="1.2.2", - com.sap.sse.gwt.theme + com.sap.sse.gwt.theme, + com.sap.sailing.news Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator Bundle-ActivationPolicy: lazy Import-Package: javax.jms;version="1.1.0", diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 0db0d71e9cf..22483a81efb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -32,6 +32,8 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.gwt.ui.client.HomeService; import com.sap.sailing.gwt.ui.server.Activator; import com.sap.sailing.gwt.ui.server.ProxiedRemoteServiceServlet; +import com.sap.sailing.gwt.ui.shared.dispatch.news.InfoNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListEventDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; @@ -49,6 +51,8 @@ import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; import com.sap.sailing.gwt.ui.shared.start.EventStageDTO; import com.sap.sailing.gwt.ui.shared.start.StageEventType; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; @@ -66,9 +70,35 @@ import com.sap.sse.util.ServiceTrackerFactory; * The server side implementation of the RPC service. */ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements HomeService { + 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; + private static final int MAX_VIDEO_COUNT = 3; + + private final ServiceTracker racingEventServiceTracker; + private final ServiceTracker eventNewsServiceTracker; + + public HomeServiceImpl() { + BundleContext context = Activator.getDefault(); + + racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); + eventNewsServiceTracker = ServiceTrackerFactory.createAndOpen(context, EventNewsService.class); + } + + protected RacingEventService getService() { + return racingEventServiceTracker.getService(); + } + + protected EventNewsService getEventNewsService() { + return eventNewsServiceTracker.getService(); + } + private interface EventVisitor { void visit(EventBase event, boolean onRemoteServer, URL baseURL); } + private static class EventHolder { EventBase event; boolean onRemoteServer; @@ -92,25 +122,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; - private static final int MAX_VIDEO_COUNT = 3; - - private final ServiceTracker racingEventServiceTracker; - - public HomeServiceImpl() { - BundleContext context = Activator.getDefault(); - - racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); - } - - protected RacingEventService getService() { - return racingEventServiceTracker.getService(); // grab the service - } - public void forAllPublicEvents(EventVisitor visitor) throws MalformedURLException { URL requestedBaseURL = getRequestBaseURL(); for (Event event : getService().getAllEvents()) { @@ -424,6 +435,20 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home return dto; } + @Override + public List getNewsForEvent(UUID eventId, Date lastNewsDate) { + List result = new ArrayList(); + + Event event = getService().getEvent(eventId); + List newsItems = getEventNewsService().getNews(event, lastNewsDate); + + for(EventNewsItem newsItem: newsItems) { + NewsEntryDTO newsDTO = new InfoNewsEntryDTO(newsItem.getTitle(), newsItem.getMessage(), newsItem.getCreatedAtDate()); + result.add(newsDTO); + } + return result; + } + @Override public MediaDTO getMediaForEvent(UUID eventId) { Event event = getService().getEvent(eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java index 304c9d0d1d4..baa4a9ef4c0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java @@ -1,8 +1,11 @@ package com.sap.sailing.gwt.ui.client; +import java.util.Date; +import java.util.List; import java.util.UUID; import com.google.gwt.user.client.rpc.RemoteService; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; @@ -17,7 +20,9 @@ public interface HomeService extends RemoteService { MediaDTO getMediaForEvent(UUID eventId); MediaDTO getMediaForEventSeries(UUID seriesId); - + + List getNewsForEvent(UUID eventId, Date lastNewsDate); + EventListViewDTO getEventListView() throws Exception; StartViewDTO getStartView() throws Exception; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java index 7198af22700..4b95ea0b330 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java @@ -1,8 +1,11 @@ package com.sap.sailing.gwt.ui.client; +import java.util.Date; +import java.util.List; import java.util.UUID; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; @@ -18,6 +21,8 @@ public interface HomeServiceAsync { void getEventSeriesViewById(UUID id, AsyncCallback asyncCallback); + void getNewsForEvent(UUID eventId, Date lastNewsDate, AsyncCallback> callback); + void getMediaForEvent(UUID eventId, AsyncCallback callback); void getMediaForEventSeries(UUID seriesId, AsyncCallback callback); diff --git a/java/com.sap.sailing.news/META-INF/MANIFEST.MF b/java/com.sap.sailing.news/META-INF/MANIFEST.MF index 90e7b397b48..788cae34614 100644 --- a/java/com.sap.sailing.news/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.news/META-INF/MANIFEST.MF @@ -9,11 +9,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: com.sap.sailing.news, com.sap.sailing.news.impl -Import-Package: com.sap.sailing.domain.base.impl, - com.sap.sailing.domain.common, - com.sap.sailing.domain.common.impl, - com.sap.sailing.domain.persistence, - com.sap.sailing.server, - org.osgi.framework;version="1.5.0", +Import-Package: org.osgi.framework;version="1.5.0", org.osgi.util.tracker;version="1.5.1" -Require-Bundle: com.sap.sse.common +Require-Bundle: com.sap.sse.common, + com.sap.sailing.server, + com.sap.sailing.domain diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java index 18e8b37e4de..ff34db323c8 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java @@ -5,18 +5,21 @@ import java.util.logging.Logger; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import com.sap.sailing.news.impl.NewsProviderRegistryImpl; -import com.sap.sailing.news.impl.NewsServiceImpl; +import com.sap.sailing.news.impl.EventNewsProviderRegistryImpl; +import com.sap.sailing.news.impl.EventNewsServiceImpl; +import com.sap.sailing.news.impl.SimpleDemoEventNewsProvider; public class Activator implements BundleActivator { private static final Logger logger = Logger.getLogger(Activator.class.getName()); public void start(BundleContext context) throws Exception { - NewsProviderRegistry providerRegistry = new NewsProviderRegistryImpl(); - NewsService newsService = new NewsServiceImpl(providerRegistry); - context.registerService(NewsService.class, newsService, null); - context.registerService(NewsProviderRegistry.class, providerRegistry, null); - logger.info("News Service registered."); + EventNewsProviderRegistry providerRegistry = new EventNewsProviderRegistryImpl(); + EventNewsService newsService = new EventNewsServiceImpl(providerRegistry); + context.registerService(EventNewsService.class, newsService, null); + context.registerService(EventNewsProviderRegistry.class, providerRegistry, null); + + providerRegistry.registerNewsProvider(new SimpleDemoEventNewsProvider()); + logger.info("EventNews Service registered."); } public void stop(BundleContext bundleContext) throws Exception { diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsItem.java new file mode 100644 index 00000000000..86a9ac7eec3 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsItem.java @@ -0,0 +1,12 @@ +package com.sap.sailing.news; + +import java.util.UUID; + +/** + * An interface for event related news item + * @author Frank + * + */ +public interface EventNewsItem extends NewsItem { + UUID getEventUUID(); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProvider.java new file mode 100644 index 00000000000..b8e81be838f --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProvider.java @@ -0,0 +1,16 @@ +package com.sap.sailing.news; + +import java.util.Collection; +import java.util.Date; + +import com.sap.sailing.domain.base.Event; + +public interface EventNewsProvider { + Collection getNews(Event event); + + Collection getNews(Event event, Date startingFrom); + + boolean hasNews(Event event, Date startingFrom); + + boolean hasNews(Event event); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProviderRegistry.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProviderRegistry.java new file mode 100644 index 00000000000..3fccf34d024 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsProviderRegistry.java @@ -0,0 +1,10 @@ +package com.sap.sailing.news; + +public interface EventNewsProviderRegistry { + boolean registerNewsProvider(EventNewsProvider provider); + + boolean deregisterNewsProvider(EventNewsProvider provider); + + Iterable getEventNewsProvider(); +} + \ No newline at end of file diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsService.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsService.java new file mode 100644 index 00000000000..c7a7218041b --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/EventNewsService.java @@ -0,0 +1,16 @@ +package com.sap.sailing.news; + +import java.util.Date; +import java.util.List; + +import com.sap.sailing.domain.base.Event; + +public interface EventNewsService { + List getNews(Event event); + + List getNews(Event event, Date startingFrom); + + List getNewsByCategory(Event event, String category); + + List getNewsByCategory(Event event, Date startingFrom, String category); +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java deleted file mode 100644 index 3a1a899d344..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProvider.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.sap.sailing.news; - -import java.util.Date; -import java.util.Iterator; - -public interface NewsProvider { - Iterator getNews(); - - Iterator getNews(Date startingFrom); - - boolean hasNews(Date startingFrom); - - boolean hasNews(); -} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java deleted file mode 100644 index a4e98b8d954..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsProviderRegistry.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sailing.news; - -public interface NewsProviderRegistry { - boolean registerNewsProvider(NewsProvider provider); - - boolean deregisterNewsProvider(NewsProvider provider); - - Iterable getNewsProvider(); -} - \ No newline at end of file diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java deleted file mode 100644 index 585ee05a75e..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsService.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.sap.sailing.news; - -import java.util.Date; - -public interface NewsService { - Iterable getAllNews(); - - Iterable getNews(Date startingFrom); - - Iterable getNewsByCategory(String category); - - Iterable getNewsByCategory(Date startingFrom, String category); -} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java new file mode 100644 index 00000000000..21efebe2d4f --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java @@ -0,0 +1,26 @@ +package com.sap.sailing.news.impl; + +import java.net.URL; +import java.util.Date; +import java.util.UUID; + +import com.sap.sailing.news.EventNewsItem; + +public class AbstractEventNewsItem extends AbstractNewsItem implements EventNewsItem { + private UUID eventId; + + public AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category, URL relatedItemLink) { + super(title, message, createdAtDate, category, relatedItemLink); + this.eventId = eventId; + } + + public AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category) { + super(title, message, createdAtDate, category); + this.eventId = eventId; + } + + @Override + public UUID getEventUUID() { + return eventId; + } +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsProviderRegistryImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsProviderRegistryImpl.java new file mode 100644 index 00000000000..23d9c22520b --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsProviderRegistryImpl.java @@ -0,0 +1,31 @@ +package com.sap.sailing.news.impl; + +import java.util.HashSet; +import java.util.Set; + +import com.sap.sailing.news.EventNewsProvider; +import com.sap.sailing.news.EventNewsProviderRegistry; + +public class EventNewsProviderRegistryImpl implements EventNewsProviderRegistry { + private Set newsProvider; + + public EventNewsProviderRegistryImpl() { + newsProvider = new HashSet(); + } + + @Override + public boolean registerNewsProvider(EventNewsProvider provider) { + return newsProvider.add(provider); + } + + @Override + public boolean deregisterNewsProvider(EventNewsProvider provider) { + return newsProvider.remove(provider); + } + + @Override + public Iterable getEventNewsProvider() { + return newsProvider; + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java new file mode 100644 index 00000000000..81468634aba --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java @@ -0,0 +1,51 @@ +package com.sap.sailing.news.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.EventNewsProvider; +import com.sap.sailing.news.EventNewsProviderRegistry; +import com.sap.sailing.news.EventNewsService; + +public class EventNewsServiceImpl implements EventNewsService { + private final EventNewsProviderRegistry providerRegistry; + + public EventNewsServiceImpl(EventNewsProviderRegistry providerRegistry) { + this.providerRegistry = providerRegistry; + } + + @Override + public List getNews(Event event) { + List result = new ArrayList<>(); + for(EventNewsProvider provider: providerRegistry.getEventNewsProvider()) { + Collection news = provider.getNews(event); + result.addAll(news); + } + return result; + } + + @Override + public List getNews(Event event, Date startingFrom) { + List result = new ArrayList<>(); + for(EventNewsProvider provider: providerRegistry.getEventNewsProvider()) { + Collection news = provider.getNews(event, startingFrom); + result.addAll(news); + } + return result; + } + + @Override + public List getNewsByCategory(Event event, String category) { + return getNews(event); + } + + @Override + public List getNewsByCategory(Event event, Date startingFrom, String category) { + return getNews(event, startingFrom); + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java deleted file mode 100644 index 343db870b42..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsProviderRegistryImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.sap.sailing.news.impl; - -import java.util.HashSet; -import java.util.Set; - -import com.sap.sailing.news.NewsProvider; -import com.sap.sailing.news.NewsProviderRegistry; - -public class NewsProviderRegistryImpl implements NewsProviderRegistry { - private Set newsProvider; - - public NewsProviderRegistryImpl() { - newsProvider = new HashSet(); - } - - @Override - public boolean registerNewsProvider(NewsProvider provider) { - return newsProvider.add(provider); - } - - @Override - public boolean deregisterNewsProvider(NewsProvider provider) { - return newsProvider.remove(provider); - } - - @Override - public Iterable getNewsProvider() { - return newsProvider; - } - -} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java deleted file mode 100644 index 41348a0a77b..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/NewsServiceImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.sap.sailing.news.impl; - -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import com.sap.sailing.news.NewsItem; -import com.sap.sailing.news.NewsProvider; -import com.sap.sailing.news.NewsProviderRegistry; -import com.sap.sailing.news.NewsService; -import com.sap.sse.common.Util; - -public class NewsServiceImpl implements NewsService { - private final NewsProviderRegistry providerRegistry; - - public NewsServiceImpl(NewsProviderRegistry providerRegistry) { - this.providerRegistry = providerRegistry; - } - - @Override - public Iterable getAllNews() { - List result = new ArrayList<>(); - for(NewsProvider provider: providerRegistry.getNewsProvider()) { - Iterator news = provider.getNews(); - } - return result; - } - - @Override - public Iterable getNews(Date startingFrom) { - List result = new ArrayList<>(); - for(NewsProvider provider: providerRegistry.getNewsProvider()) { - Iterator news = provider.getNews(startingFrom); - } - return result; - } - - @Override - public Iterable getNewsByCategory(String category) { - return getAllNews(); - } - - @Override - public Iterable getNewsByCategory(Date startingFrom, String category) { - return getNews(startingFrom); - } - -} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java new file mode 100644 index 00000000000..5511e718901 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java @@ -0,0 +1,46 @@ +package com.sap.sailing.news.impl; + +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; + +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.EventNewsProvider; +import com.sap.sailing.news.LimitedQueue; + +public class SimpleDemoEventNewsProvider implements EventNewsProvider { + private final LinkedList newsQueue; + + public SimpleDemoEventNewsProvider() { + newsQueue = new LimitedQueue<>(10); + } + + @Override + public Collection getNews(Event event) { +// Iterable leaderboardGroups = event.getLeaderboardGroups(); +// for(LeaderboardGroup leaderboardGroup: leaderboardGroups) { +// for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) { +// TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification(); +// } +// } + + return newsQueue.subList(0, newsQueue.size()); + } + + @Override + public Collection getNews(Event event, Date startingFrom) { + return newsQueue.subList(0, newsQueue.size()); + } + + @Override + public boolean hasNews(Event event, Date startingFrom) { + return newsQueue.size() > 0; + } + + @Override + public boolean hasNews(Event event) { + return newsQueue.size() > 0; + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java deleted file mode 100644 index ca305897251..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoNewsProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.sap.sailing.news.impl; - -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; - -import com.sap.sailing.news.LimitedQueue; -import com.sap.sailing.news.NewsItem; -import com.sap.sailing.news.NewsProvider; - -public class SimpleDemoNewsProvider implements NewsProvider { - private final LinkedList newsQueue; - - public SimpleDemoNewsProvider() { - newsQueue = new LimitedQueue(10); - } - - @Override - public Iterator getNews() { - return newsQueue.iterator(); - } - - @Override - public Iterator getNews(Date startingFrom) { - return newsQueue.iterator(); - } - - @Override - public boolean hasNews(Date startingFrom) { - return newsQueue.size() > 0; - } - - @Override - public boolean hasNews() { - return newsQueue.size() > 0; - } - -} From 8f8fa42263a6bfe9a6183aa47ec4877050eb88be Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 11 Jun 2015 15:13:33 +0200 Subject: [PATCH 065/117] added com.sap.sailing.news bundle to launch configs --- java/com.sap.sailing.server/SailingServer (No Proxy).launch | 2 +- .../SailingServer (No Proxy, Cached MTB).launch | 2 +- .../SailingServer (No Proxy, Jetty on 8889).launch | 2 +- ...SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch | 4 ++-- .../SailingServer (No Proxy, Jetty on 8890).launch | 2 +- .../SailingServer (No Proxy, Remote Debug SAP VM).launch | 4 ++-- .../SailingServer (No Proxy, winddbTest).launch | 2 +- java/com.sap.sailing.server/SailingServer (Proxy).launch | 2 +- .../SailingServer (Proxy, Jetty on 8889).launch | 2 +- .../SailingServer (Proxy, Remote Debug SAP VM).launch | 4 ++-- .../SailingServer (Proxy, SwissTiming Live Simulation).launch | 2 +- .../SailingServer (Proxy, winddbTest).launch | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index 7614e7a8e9a..62feacb163b 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -34,5 +34,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch index c71cbc26452..568a0fb6aef 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch @@ -33,5 +33,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch index 34fea4ab561..7bdb8892027 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch @@ -27,6 +27,6 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch index 8960a922fc4..f217788eb09 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch @@ -16,7 +16,7 @@ - + @@ -27,6 +27,6 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch index fe8ccfd0d3c..2dd0f73aea5 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch @@ -27,6 +27,6 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch index c5041dbd0f6..680a7d606b5 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch @@ -16,7 +16,7 @@ - + @@ -27,5 +27,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch index 6a403e984d0..c79588fae06 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch @@ -33,5 +33,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy).launch b/java/com.sap.sailing.server/SailingServer (Proxy).launch index 9c04071ec1e..7441e7a94ce 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy).launch @@ -34,6 +34,6 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch index 59419fdd57d..08f7149dd98 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch @@ -27,6 +27,6 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch index 6d4f97df3be..0c026c8faa5 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch @@ -17,7 +17,7 @@ - + @@ -27,5 +27,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch index 1c196a6a607..f6cc5fe138d 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch @@ -26,5 +26,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch b/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch index 0e91cb26dc2..164247e4a42 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch @@ -28,6 +28,6 @@ - + From 783a46eb4e03dd03981ed7587db06db36de056d8 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 16:32:07 +0200 Subject: [PATCH 066/117] Initial implementation to generate sample news entries --- .../sailing/gwt/server/HomeServiceImpl.java | 24 ------ .../sailing/gwt/ui/client/HomeService.java | 5 -- .../gwt/ui/client/HomeServiceAsync.java | 5 -- .../ui/server/dispatch/DispatchRPCImpl.java | 5 +- .../ui/shared/dispatch/DispatchContext.java | 3 + .../shared/dispatch/DispatchContextImpl.java | 9 ++- .../event/GetEventOverviewStageAction.java | 80 ++++++++++--------- .../dispatch/news/InfoNewsEntryDTO.java | 12 +-- .../news/LeaderboardNewsEntryDTO.java | 6 +- .../news/impl/AbstractEventNewsItem.java | 2 +- .../sailing/news/impl/InfoEventNewsItem.java | 17 ++++ .../impl/SimpleDemoEventNewsProvider.java | 23 +++++- 12 files changed, 108 insertions(+), 83 deletions(-) create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/InfoEventNewsItem.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index 22483a81efb..aa6a230e203 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -32,8 +32,6 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.gwt.ui.client.HomeService; import com.sap.sailing.gwt.ui.server.Activator; import com.sap.sailing.gwt.ui.server.ProxiedRemoteServiceServlet; -import com.sap.sailing.gwt.ui.shared.dispatch.news.InfoNewsEntryDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListEventDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; @@ -51,8 +49,6 @@ import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; import com.sap.sailing.gwt.ui.shared.start.EventStageDTO; import com.sap.sailing.gwt.ui.shared.start.StageEventType; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; -import com.sap.sailing.news.EventNewsItem; -import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; @@ -78,23 +74,17 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home private static final int MAX_VIDEO_COUNT = 3; private final ServiceTracker racingEventServiceTracker; - private final ServiceTracker eventNewsServiceTracker; public HomeServiceImpl() { BundleContext context = Activator.getDefault(); racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); - eventNewsServiceTracker = ServiceTrackerFactory.createAndOpen(context, EventNewsService.class); } protected RacingEventService getService() { return racingEventServiceTracker.getService(); } - protected EventNewsService getEventNewsService() { - return eventNewsServiceTracker.getService(); - } - private interface EventVisitor { void visit(EventBase event, boolean onRemoteServer, URL baseURL); } @@ -435,20 +425,6 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home return dto; } - @Override - public List getNewsForEvent(UUID eventId, Date lastNewsDate) { - List result = new ArrayList(); - - Event event = getService().getEvent(eventId); - List newsItems = getEventNewsService().getNews(event, lastNewsDate); - - for(EventNewsItem newsItem: newsItems) { - NewsEntryDTO newsDTO = new InfoNewsEntryDTO(newsItem.getTitle(), newsItem.getMessage(), newsItem.getCreatedAtDate()); - result.add(newsDTO); - } - return result; - } - @Override public MediaDTO getMediaForEvent(UUID eventId) { Event event = getService().getEvent(eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java index baa4a9ef4c0..e18d41f1e20 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java @@ -1,11 +1,8 @@ package com.sap.sailing.gwt.ui.client; -import java.util.Date; -import java.util.List; import java.util.UUID; import com.google.gwt.user.client.rpc.RemoteService; -import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; @@ -21,8 +18,6 @@ public interface HomeService extends RemoteService { MediaDTO getMediaForEventSeries(UUID seriesId); - List getNewsForEvent(UUID eventId, Date lastNewsDate); - EventListViewDTO getEventListView() throws Exception; StartViewDTO getStartView() throws Exception; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java index 4b95ea0b330..3be0108d7e8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java @@ -1,11 +1,8 @@ package com.sap.sailing.gwt.ui.client; -import java.util.Date; -import java.util.List; import java.util.UUID; import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; @@ -20,8 +17,6 @@ public interface HomeServiceAsync { void getEventViewById(UUID id, AsyncCallback callback); void getEventSeriesViewById(UUID id, AsyncCallback asyncCallback); - - void getNewsForEvent(UUID eventId, Date lastNewsDate, AsyncCallback> callback); void getMediaForEvent(UUID eventId, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java index 3514b566ec4..f5b63215fe3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java @@ -12,6 +12,7 @@ import com.sap.sailing.gwt.ui.shared.dispatch.RequestWrapper; import com.sap.sailing.gwt.ui.shared.dispatch.Result; import com.sap.sailing.gwt.ui.shared.dispatch.ResultWrapper; import com.sap.sailing.gwt.ui.shared.dispatch.rpc.DispatchRPC; +import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.util.ServiceTrackerFactory; @@ -19,16 +20,18 @@ public class DispatchRPCImpl extends ProxiedRemoteServiceServlet implements Disp private static final long serialVersionUID = -245230476512348999L; private final ServiceTracker racingEventServiceTracker; + private final ServiceTracker eventNewsServiceTracker; public DispatchRPCImpl() { final BundleContext context = Activator.getDefault(); racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); + eventNewsServiceTracker = ServiceTrackerFactory.createAndOpen(context, EventNewsService.class); } @Override public > ResultWrapper execute(RequestWrapper request) throws DispatchException { - R executionResult = request.getAction().execute(new DispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService(), request.getClientLocaleName())); + R executionResult = request.getAction().execute(new DispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService(), eventNewsServiceTracker.getService(), request.getClientLocaleName())); return new ResultWrapper(executionResult); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java index 8ea041e4819..ae000b8a3cb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java @@ -3,12 +3,15 @@ package com.sap.sailing.gwt.ui.shared.dispatch; import java.util.Date; import java.util.Locale; +import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; public interface DispatchContext { RacingEventService getRacingEventService(); + + EventNewsService getEventNewsService(); String getClientLocaleName(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java index 1813050dcaf..a99966322fa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java @@ -3,18 +3,21 @@ package com.sap.sailing.gwt.ui.shared.dispatch; import java.util.Date; import java.util.Locale; +import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; public class DispatchContextImpl implements DispatchContext { private final RacingEventService racingEventService; + private final EventNewsService eventNewsService; private final Date currentClientTime; // private final Date currentServerTime = new Date(); private String clientLocaleName; - public DispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, String clientLocaleName) { + public DispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, EventNewsService eventNewsService, String clientLocaleName) { this.currentClientTime = currentClientTime; this.racingEventService = racingEventService; + this.eventNewsService = eventNewsService; this.clientLocaleName = clientLocaleName; } @@ -23,6 +26,10 @@ public class DispatchContextImpl implements DispatchContext { return racingEventService; } + public EventNewsService getEventNewsService() { + return eventNewsService; + } + @Override public Date getCurrentClientTime() { return currentClientTime; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index de2c5d47694..e136eea7570 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -1,23 +1,20 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.net.URL; -import java.util.Date; +import java.util.List; import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.domain.common.LeaderboardNameConstants; -import com.sap.sailing.domain.common.dto.CompetitorDTOImpl; import com.sap.sailing.gwt.server.HomeServiceUtil; 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.dispatch.news.InfoNewsEntryDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.RaceCompetitorNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.impl.InfoEventNewsItem; import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MimeType; @@ -48,7 +45,7 @@ public class GetEventOverviewStageAction implements Action(ttl, stage); } @@ -129,37 +126,46 @@ public class GetEventOverviewStageAction implements Action newsItems = dispatchContext.getEventNewsService().getNews(event, event.getStartDate().asDate()); + + for(EventNewsItem newsItem: newsItems) { + if(newsItem instanceof InfoEventNewsItem) { + stage.addNews(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem)); + } } - sb.append(raceName); - if(fleetName != null && !fleetName.isEmpty() && !LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { - sb.append(" - ").append(fleetName); - } - return sb.toString(); +// TODO test contents +// +// boolean singleRegatta = HomeServiceUtil.isSingleRegatta(event); +// +// stage.addNews(new InfoNewsEntryDTO("Sturm", "Heute keine Rennen mehr", new Date(new Date().getTime() - 125000))); +// stage.addNews(new InfoNewsEntryDTO("Abendbespaßung", "Es gibt Freibier und Wurst!!!", new Date())); +// stage.addNews(new LeaderboardNewsEntryDTO("Test LB", "505 m", BoatClassMasterdata._5O5.getDisplayName(), new Date(new Date().getTime() - 120000), LeaderboardNewsEntryDTO.Type.NEW_RESULTS)); +// +// LeaderboardNewsEntryDTO lbEntryWithExternalLink = new LeaderboardNewsEntryDTO("Test LB", "Some Regatta", BoatClassMasterdata.LASER_RADIAL.getDisplayName(), new Date(new Date().getTime() - 270000), LeaderboardNewsEntryDTO.Type.NEW_RESULTS); +// lbEntryWithExternalLink.setExternalURL("http://www.sap.com/"); +// stage.addNews(lbEntryWithExternalLink); +// +// CompetitorDTOImpl testCompetitor = new CompetitorDTOImpl("Peter Mayer", null, null, null, null, null, null, null, null, null, null, null, null); +// String regattaName = "470 Men"; +// String race6 = constructRaceName(regattaName, "R6", "Gold", singleRegatta); +// stage.addNews(new RaceCompetitorNewsEntryDTO(regattaName, "470 R6", race6, BoatClassMasterdata.PIRATE.getDisplayName(), new Date(new Date().getTime() - 1888000), testCompetitor, RaceCompetitorNewsEntryDTO.Type.CRASH)); +// String race7 = constructRaceName(regattaName, "R7", "Gold", singleRegatta); +// stage.addNews(new RaceCompetitorNewsEntryDTO(regattaName, "470 R7", race7, BoatClassMasterdata.PIRATE.getDisplayName(), new Date(new Date().getTime() - 1337000), testCompetitor, RaceCompetitorNewsEntryDTO.Type.WINNER)); } +// +// private String constructRaceName(String regattaDisplayName, String raceName, String fleetName, boolean singleRegatta) { +// StringBuilder sb = new StringBuilder(); +// if(!singleRegatta) { +// sb.append(regattaDisplayName).append(" - "); +// } +// sb.append(raceName); +// if(fleetName != null && !fleetName.isEmpty() && !LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { +// sb.append(" - ").append(fleetName); +// } +// return sb.toString(); +// } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java index a9c3b9a2378..0847e00aad9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; -import java.util.Date; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.news.impl.InfoEventNewsItem; public class InfoNewsEntryDTO extends NewsEntryDTO { @@ -11,10 +12,11 @@ public class InfoNewsEntryDTO extends NewsEntryDTO { private InfoNewsEntryDTO() { } - public InfoNewsEntryDTO(String title, String subtitle, Date timestamp) { - super(timestamp); - this.title = title; - this.subtitle = subtitle; + @GwtIncompatible + public InfoNewsEntryDTO(InfoEventNewsItem item) { + super(item.getCreatedAtDate()); + this.title = item.getTitle(); + this.subtitle = item.getMessage(); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java index 6d3261135ee..028892132cb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java @@ -5,7 +5,7 @@ import java.util.Date; public class LeaderboardNewsEntryDTO extends NewsEntryDTO { public enum Type { - NEW_RESULTS + RESULTS_UPDATE } private String leaderboardName; @@ -39,8 +39,8 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { @Override public String getMessage() { switch (type) { - case NEW_RESULTS: - return "New results are available"; + case RESULTS_UPDATE: + return "Result update"; } return ""; } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java index 21efebe2d4f..1dd93a2abde 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractEventNewsItem.java @@ -6,7 +6,7 @@ import java.util.UUID; import com.sap.sailing.news.EventNewsItem; -public class AbstractEventNewsItem extends AbstractNewsItem implements EventNewsItem { +public abstract class AbstractEventNewsItem extends AbstractNewsItem implements EventNewsItem { private UUID eventId; public AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category, URL relatedItemLink) { diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/InfoEventNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/InfoEventNewsItem.java new file mode 100644 index 00000000000..f0b6f7c76c0 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/InfoEventNewsItem.java @@ -0,0 +1,17 @@ +package com.sap.sailing.news.impl; + +import java.net.URL; +import java.util.Date; +import java.util.UUID; + +public class InfoEventNewsItem extends AbstractEventNewsItem { + public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category, + URL relatedItemLink) { + super(eventId, title, message, createdAtDate, category, relatedItemLink); + } + + public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category) { + super(eventId, title, message, createdAtDate, category); + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java index 5511e718901..8331877fdb3 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java @@ -3,6 +3,9 @@ package com.sap.sailing.news.impl; import java.util.Collection; import java.util.Date; import java.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; import com.sap.sailing.domain.base.Event; import com.sap.sailing.news.EventNewsItem; @@ -10,12 +13,30 @@ import com.sap.sailing.news.EventNewsProvider; import com.sap.sailing.news.LimitedQueue; public class SimpleDemoEventNewsProvider implements EventNewsProvider { - private final LinkedList newsQueue; + private final LinkedList newsQueue; + + private final Timer timer = new Timer(); public SimpleDemoEventNewsProvider() { newsQueue = new LimitedQueue<>(10); + + final UUID eventId = UUID.fromString("406cffc2-b491-4f7e-b78e-a21abd97006a"); +// final UUID eventId = UUID.fromString("406cffc2-b491-4f7e-b78e-a21abd97006a"); + + timer.scheduleAtFixedRate(new TimerTask() { + int counter=1; + @Override + public void run() { + newsQueue.add(new InfoEventNewsItem(eventId, "Test Entry " + counter, "Content for Test Entry "+counter, new Date(), null)); + counter++; + } + }, 5_000, 30_000); } + protected void finalize() throws Throwable { + timer.cancel(); + }; + @Override public Collection getNews(Event event) { // Iterable leaderboardGroups = event.getLeaderboardGroups(); From 396f2d6d03b692aa4b427b36878069f512ea2936 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 11 Jun 2015 17:22:21 +0200 Subject: [PATCH 067/117] added a language locale attribute to media domain objects --- .../domain/persistence/impl/DomainObjectFactoryImpl.java | 9 +++++++-- .../sap/sailing/domain/persistence/impl/FieldNames.java | 4 ++-- .../domain/persistence/impl/MongoObjectFactoryImpl.java | 5 +++-- .../test/TestStoringAndLoadingEventsAndRegattas.java | 4 ++++ .../deserialization/impl/EventBaseJsonDeserializer.java | 7 +++++++ .../serialization/impl/EventBaseJsonSerializer.java | 3 +++ .../EventDataJsonSerializerWithImagesAndVideosTest.java | 7 +++++++ .../com/sap/sse/common/media/ImageDescriptorImpl.java | 2 +- .../com/sap/sse/gwt/client/media/AbstractMediaDTO.java | 2 +- 9 files changed, 35 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index ad33b2d64ab..79571ec4c37 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -2098,8 +2099,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { String title = (String) dbObject.get(FieldNames.IMAGE_TITLE.name()); String subtitle = (String) dbObject.get(FieldNames.IMAGE_SUBTITLE.name()); String copyright = (String) dbObject.get(FieldNames.IMAGE_COPYRIGHT.name()); - //Object mimeTypeRaw = dbObject.get(FieldNames.IMAGE_MIMETYPE.name()); - //MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + String localeRaw = (String) dbObject.get(FieldNames.IMAGE_LOCALE.name()); + Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; Integer imageWidth = (Integer) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); Integer imageHeight = (Integer) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.IMAGE_CREATEDATDATE); @@ -2114,6 +2115,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { image.setCopyright(copyright); image.setTitle(title); image.setSubtitle(subtitle); + image.setLocale(locale); image.setTags(imageTags); if (imageWidth != null && imageHeight != null) { image.setSize(imageWidth, imageHeight); @@ -2131,6 +2133,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { String copyright = (String) dbObject.get(FieldNames.VIDEO_COPYRIGHT.name()); Object mimeTypeRaw = dbObject.get(FieldNames.VIDEO_MIMETYPE.name()); MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); + String localeRaw = (String) dbObject.get(FieldNames.VIDEO_LOCALE.name()); + Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.VIDEO_CREATEDATDATE); BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.VIDEO_TAGS.name()); Integer lengthInSeconds = (Integer) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); @@ -2145,6 +2149,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { video.setCopyright(copyright); video.setTitle(title); video.setSubtitle(subtitle); + video.setLocale(locale); video.setTags(videoTags); video.setLengthInSeconds(lengthInSeconds); video.setThumbnailURL(thumbnailURL); diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java index c31c87c3318..fc0c675b804 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -134,10 +134,10 @@ public enum FieldNames { 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_TITLE, IMAGE_SUBTITLE, IMAGE_MIMETYPE, IMAGE_COPYRIGHT, IMAGE_CREATEDATDATE, + 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_TITLE, VIDEO_SUBTITLE, VIDEO_MIMETYPE, VIDEO_COPYRIGHT, VIDEO_CREATEDATDATE, + VIDEO_URL, VIDEO_LOCALE, VIDEO_TITLE, VIDEO_SUBTITLE, VIDEO_MIMETYPE, VIDEO_COPYRIGHT, VIDEO_CREATEDATDATE, VIDEO_TAGS, VIDEO_THUMBNAIL_URL, VIDEO_LENGTH_IN_SECONDS; } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 98dfdcef926..9e12f84d253 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -1421,9 +1421,9 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { 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_MIMETYPE.name(), image.getMimeType().name()); 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()); @@ -1439,10 +1439,11 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { 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().name()); + 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); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 2eed6cf4c57..7f300ad846d 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -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; @@ -278,6 +279,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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"; @@ -297,6 +299,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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); @@ -320,6 +323,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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()); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 71bbd40ecf5..cd6b856b4c2 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -4,6 +4,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.UUID; import org.json.simple.JSONArray; @@ -138,6 +139,8 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { 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; Integer imageWidth = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH_IN_PX); Integer imageHeight = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT_IN_PX); Long createdAtDateInMs = (Long) imageJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); @@ -151,6 +154,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } image = new ImageDescriptorImpl(imageURL, createdAtDate); image.setCopyright(copyright); + image.setLocale(locale); image.setTitle(title); image.setSubtitle(subtitle); image.setTags(imageTags); @@ -168,6 +172,8 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { 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); Long createdAtDateInMs = (Long) videoJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); @@ -183,6 +189,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } video = new VideoDescriptorImpl(videoURL, mimeType, createdAtDate); video.setCopyright(copyright); + video.setLocale(locale); video.setTitle(title); video.setSubtitle(subtitle); video.setTags(videoTags); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index 14dece4d01f..8ca830dacfd 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -43,6 +43,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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"; @@ -106,6 +107,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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()); @@ -124,6 +126,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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()); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java index 69132046fed..6f320bf225a 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java @@ -11,6 +11,7 @@ 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; @@ -44,6 +45,7 @@ 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"); @@ -57,6 +59,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { 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"; @@ -75,6 +78,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { 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); @@ -88,6 +92,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, mimeType, createdAt); video1.setCopyright(copyright2); + video1.setLocale(locale2); video1.setTitle(videoTitle); video1.setSubtitle(videoSubtitle); video1.setThumbnailURL(videoThumbnailURL); @@ -161,6 +166,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { 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()); @@ -173,6 +179,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { 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()); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java index b3c6b71ac05..48f7c10896b 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java @@ -19,7 +19,7 @@ public class ImageDescriptorImpl extends AbstractMediaDescriptor implements Imag public ImageDescriptorImpl(URL imageURL, TimePoint createdAtDate) { super(imageURL, MimeType.image, createdAtDate); } - + @Override public Integer getWidthInPx() { return widthInPx; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java index 914371e3a15..bb6b91bfb19 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -22,7 +22,7 @@ public abstract class AbstractMediaDTO implements IsSerializable { protected String sourceRef; - private String locale; + protected String locale; /** for GWT */ protected AbstractMediaDTO() { From bdcf580f943c467a53fc2dfb3c5c736cd5e66fb7 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 11 Jun 2015 17:55:23 +0200 Subject: [PATCH 068/117] Initial implementation to get Leaderboard update news --- .../event/GetEventOverviewStageAction.java | 10 ++- .../news/AbstractRaceNewsEntryDTO.java | 9 +-- .../dispatch/news/InfoNewsEntryDTO.java | 9 +-- .../news/LeaderboardNewsEntryDTO.java | 25 +++---- .../ui/shared/dispatch/news/NewsEntryDTO.java | 9 ++- .../com.sap.sailing.news/META-INF/MANIFEST.MF | 3 +- .../src/com/sap/sailing/news/Activator.java | 2 + .../src/com/sap/sailing/news/NewsItem.java | 2 +- .../sailing/news/impl/AbstractNewsItem.java | 15 ++++ .../news/impl/EventNewsServiceImpl.java | 13 +++- .../LeaderboardUpdateEventNewsProvider.java | 68 +++++++++++++++++++ .../news/impl/LeaderboardUpdateNewsItem.java | 23 +++++++ 12 files changed, 146 insertions(+), 42 deletions(-) create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateNewsItem.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index e136eea7570..0ab9f043c59 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -11,10 +11,12 @@ 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.dispatch.news.InfoNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; import com.sap.sailing.news.EventNewsItem; import com.sap.sailing.news.impl.InfoEventNewsItem; +import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MimeType; @@ -129,15 +131,17 @@ public class GetEventOverviewStageAction implements Action newsItems = dispatchContext.getEventNewsService().getNews(event, event.getStartDate().asDate()); + List newsItems = dispatchContext.getEventNewsService().getNews(event); for(EventNewsItem newsItem: newsItems) { if(newsItem instanceof InfoEventNewsItem) { stage.addNews(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem)); } + if(newsItem instanceof LeaderboardUpdateNewsItem) { + stage.addNews(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem)); + } } -// TODO test contents +// TODO remove test contents // // boolean singleRegatta = HomeServiceUtil.isSingleRegatta(event); // diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java index 592b2df0d14..d2e51a41d81 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java @@ -6,18 +6,16 @@ public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO { private String regattaName; private String trackedRaceName; - private String raceTitle; private String boatClass; protected AbstractRaceNewsEntryDTO() { } public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp) { - super(timestamp); + super(raceTitle, timestamp); this.regattaName = regattaName; this.trackedRaceName = trackedRaceName; this.boatClass = boatClass; - this.raceTitle = raceTitle; } @Override @@ -25,11 +23,6 @@ public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO { return boatClass; } - @Override - public String getTitle() { - return raceTitle; - } - public String getRegattaName() { return regattaName; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java index 0847e00aad9..a1fc4309fc4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java @@ -5,7 +5,6 @@ import com.sap.sailing.news.impl.InfoEventNewsItem; public class InfoNewsEntryDTO extends NewsEntryDTO { - private String title; private String subtitle; @SuppressWarnings("unused") @@ -14,16 +13,10 @@ public class InfoNewsEntryDTO extends NewsEntryDTO { @GwtIncompatible public InfoNewsEntryDTO(InfoEventNewsItem item) { - super(item.getCreatedAtDate()); - this.title = item.getTitle(); + super(item.getTitle(), item.getCreatedAtDate()); this.subtitle = item.getMessage(); } - @Override - public String getTitle() { - return title; - } - @Override public String getMessage() { return subtitle; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java index 028892132cb..08e2077c967 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; -import java.util.Date; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; public class LeaderboardNewsEntryDTO extends NewsEntryDTO { @@ -9,7 +10,6 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { } private String leaderboardName; - private String leaderboardDisplayName; private String boatClassName; private String externalURL; private Type type; @@ -18,19 +18,14 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { private LeaderboardNewsEntryDTO() { } - public LeaderboardNewsEntryDTO(String leaderboardName, String leaderboardDisplayName, String boatClassName, Date timestamp, Type type) { - super(timestamp); - this.boatClassName = boatClassName; - this.type = type; - this.setLeaderboardName(leaderboardName); - this.leaderboardDisplayName = leaderboardDisplayName; + @GwtIncompatible + public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item) { + super(item.getTitle(), item.getCreatedAtDate()); + this.boatClassName = item.getBoatClass(); + this.type = Type.RESULTS_UPDATE; + this.leaderboardName = item.getLeaderboardName(); } - @Override - public String getTitle() { - return leaderboardDisplayName; - } - @Override public String getBoatClass() { return boatClassName; @@ -56,8 +51,4 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { public String getLeaderboardName() { return leaderboardName; } - - public void setLeaderboardName(String leaderboardName) { - this.leaderboardName = leaderboardName; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java index b6035df84c1..f0c74bb1df7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java @@ -7,15 +7,20 @@ import com.google.gwt.user.client.rpc.IsSerializable; public abstract class NewsEntryDTO implements IsSerializable { private Date timestamp; + + private String title; protected NewsEntryDTO() { } - public NewsEntryDTO(Date timestamp) { + public NewsEntryDTO(String title, Date timestamp) { + this.title = title; this.timestamp = timestamp; } - public abstract String getTitle(); + public String getTitle() { + return title; + } public abstract String getMessage(); diff --git a/java/com.sap.sailing.news/META-INF/MANIFEST.MF b/java/com.sap.sailing.news/META-INF/MANIFEST.MF index 788cae34614..7a55d57aa39 100644 --- a/java/com.sap.sailing.news/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.news/META-INF/MANIFEST.MF @@ -13,4 +13,5 @@ Import-Package: org.osgi.framework;version="1.5.0", org.osgi.util.tracker;version="1.5.1" Require-Bundle: com.sap.sse.common, com.sap.sailing.server, - com.sap.sailing.domain + com.sap.sailing.domain, + com.sap.sailing.domain.common diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java index ff34db323c8..d4b9f01eebb 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java @@ -7,6 +7,7 @@ import org.osgi.framework.BundleContext; import com.sap.sailing.news.impl.EventNewsProviderRegistryImpl; import com.sap.sailing.news.impl.EventNewsServiceImpl; +import com.sap.sailing.news.impl.LeaderboardUpdateEventNewsProvider; import com.sap.sailing.news.impl.SimpleDemoEventNewsProvider; public class Activator implements BundleActivator { @@ -19,6 +20,7 @@ public class Activator implements BundleActivator { context.registerService(EventNewsProviderRegistry.class, providerRegistry, null); providerRegistry.registerNewsProvider(new SimpleDemoEventNewsProvider()); + providerRegistry.registerNewsProvider(new LeaderboardUpdateEventNewsProvider()); logger.info("EventNews Service registered."); } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java index 53cc7d7c17d..df47e9e43fa 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/NewsItem.java @@ -9,7 +9,7 @@ import java.util.UUID; * @author Frank * */ -public interface NewsItem { +public interface NewsItem extends Comparable { UUID getId(); String getCategory(); diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java index 36168f415c7..1528859b722 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/AbstractNewsItem.java @@ -55,4 +55,19 @@ public class AbstractNewsItem implements NewsItem { public UUID getId() { return id; } + + @Override + public int compareTo(NewsItem o) { + Date otherCreatedAtDate = o.getCreatedAtDate(); + if(createdAtDate == otherCreatedAtDate) { + return 0; + } + if(createdAtDate == null) { + return 1; + } + if(otherCreatedAtDate == null) { + return -1; + } + return -createdAtDate.compareTo(otherCreatedAtDate); + } } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java index 81468634aba..abf923c1bf5 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/EventNewsServiceImpl.java @@ -2,6 +2,7 @@ package com.sap.sailing.news.impl; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -25,7 +26,11 @@ public class EventNewsServiceImpl implements EventNewsService { Collection news = provider.getNews(event); result.addAll(news); } - return result; + Collections.sort(result); + if(result.size() <= 15) { + return result; + } + return result.subList(0, 16); } @Override @@ -35,7 +40,11 @@ public class EventNewsServiceImpl implements EventNewsService { Collection news = provider.getNews(event, startingFrom); result.addAll(news); } - return result; + Collections.sort(result); + if(result.size() <= 15) { + return result; + } + return result.subList(0, 16); } @Override diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java new file mode 100644 index 00000000000..54305106f5d --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java @@ -0,0 +1,68 @@ +package com.sap.sailing.news.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.EventNewsProvider; +import com.sap.sse.common.TimePoint; + +public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider { + + @Override + public Collection getNews(Event event) { + List result = new LinkedList<>(); + Iterable leaderboardGroups = event.getLeaderboardGroups(); + for(LeaderboardGroup leaderboardGroup: leaderboardGroups) { + for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) { + TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification(); + if(timePointOfLatestModification == null) { + continue; + } + + String displayName = leaderboard.getDisplayName() != null ?leaderboard.getDisplayName() :leaderboard.getName(); + String boatClassName= null; + if(leaderboard instanceof RegattaLeaderboard) { + BoatClass boatClass = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass(); + if(boatClass != null) { + boatClassName = boatClass.getDisplayName(); + } + } + result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName)); + } + } + + Collections.sort(result); + + if(result.size() <= 10) { + return result; + } + return result.subList(0, 11); + } + + @Override + public Collection getNews(Event event, Date startingFrom) { + // TODO correct implementation + return getNews(event); + } + + @Override + public boolean hasNews(Event event, Date startingFrom) { + // TODO correct implementation + return true; + } + + @Override + public boolean hasNews(Event event) { + return true; + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateNewsItem.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateNewsItem.java new file mode 100644 index 00000000000..6a64cacbfce --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateNewsItem.java @@ -0,0 +1,23 @@ +package com.sap.sailing.news.impl; + +import java.util.Date; +import java.util.UUID; + +public class LeaderboardUpdateNewsItem extends AbstractEventNewsItem { + private String leaderboardName; + private String boatClass; + + public LeaderboardUpdateNewsItem(UUID eventId, Date updateDate, String leaderboardName, String leaderboardDisplayName, String boatClass) { + super(eventId, leaderboardDisplayName, null, updateDate, null, null); + this.leaderboardName = leaderboardName; + this.boatClass = boatClass; + } + + public String getLeaderboardName() { + return leaderboardName; + } + + public String getBoatClass() { + return boatClass; + } +} From c7cfa2cad955030ed11abbd489364f2c931d49db Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 12 Jun 2015 09:59:41 +0200 Subject: [PATCH 069/117] Initial implementation to load news from JSON --- .../partials/updatesBox/UpdatesBoxItem.java | 62 +++++----- .../news/AbstractRaceNewsEntryDTO.java | 5 +- .../dispatch/news/InfoNewsEntryDTO.java | 2 +- .../news/LeaderboardNewsEntryDTO.java | 11 +- .../ui/shared/dispatch/news/NewsEntryDTO.java | 17 ++- .../com.sap.sailing.news/META-INF/MANIFEST.MF | 4 +- .../src/com/sap/sailing/news/Activator.java | 5 +- .../news/impl/JsonEventNewsProvider.java | 113 ++++++++++++++++++ .../src/com/sap/sailing/news/impl/news.json | 28 +++++ 9 files changed, 201 insertions(+), 46 deletions(-) create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java create mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index b17a889fd3f..7f2a265fcb2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -60,41 +60,43 @@ public class UpdatesBoxItem extends Widget { timestampUi.setInnerText(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_MEDIUM).format(timestamp)); } - String directLink = null; - PlaceNavigation placeNavigation = null; - if(entry instanceof LeaderboardNewsEntryDTO) { - directLink = ((LeaderboardNewsEntryDTO) entry).getExternalURL(); - placeNavigation = presenter.getRegattaNavigation(((LeaderboardNewsEntryDTO) entry).getLeaderboardName()); - } else if(entry instanceof AbstractRaceNewsEntryDTO) { - AbstractRaceNewsEntryDTO raceEntry = (AbstractRaceNewsEntryDTO) entry; - if(raceEntry.getTrackedRaceName() != null) { - directLink = presenter.getRaceViewerURL(raceEntry.getRegattaName(), raceEntry.getTrackedRaceName()); - } - } + String directLink = entry.getExternalURL(); if(directLink != null) { link.setHref(directLink); link.setTarget("_blank"); - } else if(placeNavigation != null) { - link.setHref(placeNavigation.getTargetUrl()); - Event.sinkEvents(link, Event.ONCLICK); - final PlaceNavigation pn = placeNavigation; - Event.setEventListener(link, new EventListener() { - @Override - public void onBrowserEvent(Event event) { - if(LinkUtil.handleLinkClick(event)) { - event.preventDefault(); - pn.goToPlace(); - } - } - }); } else { - link.removeFromParent(); - while(link.hasChildNodes()) { - Node firstChild = link.getChild(0); - firstChild.removeFromParent(); - getElement().appendChild(firstChild); + PlaceNavigation placeNavigation = null; + if(entry instanceof LeaderboardNewsEntryDTO) { + directLink = ((LeaderboardNewsEntryDTO) entry).getExternalURL(); + placeNavigation = presenter.getRegattaNavigation(((LeaderboardNewsEntryDTO) entry).getLeaderboardName()); + } else if(entry instanceof AbstractRaceNewsEntryDTO) { + AbstractRaceNewsEntryDTO raceEntry = (AbstractRaceNewsEntryDTO) entry; + if(raceEntry.getTrackedRaceName() != null) { + directLink = presenter.getRaceViewerURL(raceEntry.getRegattaName(), raceEntry.getTrackedRaceName()); + } + } + if(placeNavigation != null) { + link.setHref(placeNavigation.getTargetUrl()); + Event.sinkEvents(link, Event.ONCLICK); + final PlaceNavigation pn = placeNavigation; + Event.setEventListener(link, new EventListener() { + @Override + public void onBrowserEvent(Event event) { + if(LinkUtil.handleLinkClick(event)) { + event.preventDefault(); + pn.goToPlace(); + } + } + }); + } else { + link.removeFromParent(); + while(link.hasChildNodes()) { + Node firstChild = link.getChild(0); + firstChild.removeFromParent(); + getElement().appendChild(firstChild); + } + addStyleName(UpdatesBoxResources.INSTANCE.css().updatesbox_item()); } - addStyleName(UpdatesBoxResources.INSTANCE.css().updatesbox_item()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java index d2e51a41d81..0c82cecc687 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java @@ -2,6 +2,8 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; import java.util.Date; +import com.google.gwt.core.shared.GwtIncompatible; + public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO { private String regattaName; @@ -11,8 +13,9 @@ public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO { protected AbstractRaceNewsEntryDTO() { } + @GwtIncompatible public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp) { - super(raceTitle, timestamp); + super(raceTitle, timestamp, null); this.regattaName = regattaName; this.trackedRaceName = trackedRaceName; this.boatClass = boatClass; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java index a1fc4309fc4..c42da127637 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java @@ -13,7 +13,7 @@ public class InfoNewsEntryDTO extends NewsEntryDTO { @GwtIncompatible public InfoNewsEntryDTO(InfoEventNewsItem item) { - super(item.getTitle(), item.getCreatedAtDate()); + super(item.getTitle(), item.getCreatedAtDate(), item.getRelatedItemLink()); this.subtitle = item.getMessage(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java index 08e2077c967..6694525b716 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java @@ -11,7 +11,6 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { private String leaderboardName; private String boatClassName; - private String externalURL; private Type type; @SuppressWarnings("unused") @@ -20,7 +19,7 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { @GwtIncompatible public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item) { - super(item.getTitle(), item.getCreatedAtDate()); + super(item.getTitle(), item.getCreatedAtDate(), null); this.boatClassName = item.getBoatClass(); this.type = Type.RESULTS_UPDATE; this.leaderboardName = item.getLeaderboardName(); @@ -40,14 +39,6 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { return ""; } - public String getExternalURL() { - return externalURL; - } - - public void setExternalURL(String externalURL) { - this.externalURL = externalURL; - } - public String getLeaderboardName() { return leaderboardName; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java index f0c74bb1df7..95e98bb0cba 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java @@ -1,7 +1,9 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; +import java.net.URL; import java.util.Date; +import com.google.gwt.core.shared.GwtIncompatible; import com.google.gwt.user.client.rpc.IsSerializable; public abstract class NewsEntryDTO implements IsSerializable { @@ -10,12 +12,21 @@ public abstract class NewsEntryDTO implements IsSerializable { private String title; + private String externalURL; + protected NewsEntryDTO() { } - public NewsEntryDTO(String title, Date timestamp) { + @GwtIncompatible + public NewsEntryDTO(String title, Date timestamp, URL externalURL) { + this(title, timestamp, externalURL == null ? null : externalURL.toString()); + } + + @GwtIncompatible + private NewsEntryDTO(String title, Date timestamp, String externalURL) { this.title = title; this.timestamp = timestamp; + this.externalURL = externalURL; } public String getTitle() { @@ -29,4 +40,8 @@ public abstract class NewsEntryDTO implements IsSerializable { public Date getTimestamp() { return timestamp; } + + public String getExternalURL() { + return externalURL; + } } diff --git a/java/com.sap.sailing.news/META-INF/MANIFEST.MF b/java/com.sap.sailing.news/META-INF/MANIFEST.MF index 7a55d57aa39..25142f906b9 100644 --- a/java/com.sap.sailing.news/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.news/META-INF/MANIFEST.MF @@ -9,7 +9,9 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: com.sap.sailing.news, com.sap.sailing.news.impl -Import-Package: org.osgi.framework;version="1.5.0", +Import-Package: org.json.simple, + org.json.simple.parser, + org.osgi.framework;version="1.5.0", org.osgi.util.tracker;version="1.5.1" Require-Bundle: com.sap.sse.common, com.sap.sailing.server, diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java index d4b9f01eebb..57ca7be7ba3 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java @@ -7,8 +7,8 @@ import org.osgi.framework.BundleContext; import com.sap.sailing.news.impl.EventNewsProviderRegistryImpl; import com.sap.sailing.news.impl.EventNewsServiceImpl; +import com.sap.sailing.news.impl.JsonEventNewsProvider; import com.sap.sailing.news.impl.LeaderboardUpdateEventNewsProvider; -import com.sap.sailing.news.impl.SimpleDemoEventNewsProvider; public class Activator implements BundleActivator { private static final Logger logger = Logger.getLogger(Activator.class.getName()); @@ -19,7 +19,8 @@ public class Activator implements BundleActivator { context.registerService(EventNewsService.class, newsService, null); context.registerService(EventNewsProviderRegistry.class, providerRegistry, null); - providerRegistry.registerNewsProvider(new SimpleDemoEventNewsProvider()); +// providerRegistry.registerNewsProvider(new SimpleDemoEventNewsProvider()); + providerRegistry.registerNewsProvider(new JsonEventNewsProvider()); providerRegistry.registerNewsProvider(new LeaderboardUpdateEventNewsProvider()); logger.info("EventNews Service registered."); } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java new file mode 100644 index 00000000000..ed71edcc7e6 --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java @@ -0,0 +1,113 @@ +package com.sap.sailing.news.impl; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.EventNewsProvider; + +public class JsonEventNewsProvider implements EventNewsProvider { + private static final int UPDATE_INTERVAL = 60_000; + private static final int CONNECTION_TIMEOUT = 15_000; + + private static final Logger logger = Logger.getLogger(JsonEventNewsProvider.class.getName()); + + // TODO fmittag: use correct URL + private static final URL url = JsonEventNewsProvider.class.getResource("news.json"); + + private List news = new LinkedList<>(); + private long nextUpdate = 0; + + public JsonEventNewsProvider() { + } + + private synchronized void update() { + if(nextUpdate >= System.currentTimeMillis()) { + // update already done + return; + } + nextUpdate = System.currentTimeMillis() + UPDATE_INTERVAL; + + try { + BufferedReader bufferedReader = null; + try { + logger.fine("Updating news from URL "+url); + URLConnection urlConnection = url.openConnection(); + urlConnection.setConnectTimeout(CONNECTION_TIMEOUT); + urlConnection.connect(); + bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); + JSONParser parser = new JSONParser(); + Object newsAsObject = parser.parse(bufferedReader); + JSONArray newsAsJsonArray = (JSONArray) newsAsObject; + List newNews = new LinkedList<>(); + for (Object eventAsObject : newsAsJsonArray) { + JSONObject eventAsJson = (JSONObject) eventAsObject; + String eventIdAsString = (String) eventAsJson.get("event"); + Number timestamp = (Number) eventAsJson.get("timestamp"); + String title = (String) eventAsJson.get("tite"); + String message = (String) eventAsJson.get("message"); + String newsURL = (String) eventAsJson.get("url"); + UUID eventId = UUID.fromString(eventIdAsString); + InfoEventNewsItem newsItem = new InfoEventNewsItem(eventId, title, message, new Date(timestamp.longValue()), null, newsURL == null ? null : new URL(newsURL)); + newNews.add(newsItem); + } + news = newNews; + } finally { + if (bufferedReader != null) { + bufferedReader.close(); + } + } + } catch (IOException | ParseException e) { + logger.log(Level.INFO, "Exception trying to fetch news from " + url, e); + } + } + + @Override + public Collection getNews(Event event) { + if(nextUpdate < System.currentTimeMillis()) { + update(); + } + + UUID eventId = event.getId(); + List result = new LinkedList<>(); + for(InfoEventNewsItem newsEntry: news) { + if(eventId.equals(newsEntry.getEventUUID())) { + result.add(newsEntry); + } + } + + return result; + } + + @Override + public Collection getNews(Event event, Date startingFrom) { + return getNews(event); + } + + @Override + public boolean hasNews(Event event, Date startingFrom) { + return news.size() > 0; + } + + @Override + public boolean hasNews(Event event) { + return news.size() > 0; + } + +} diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json new file mode 100644 index 00000000000..6d7906a9e6b --- /dev/null +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json @@ -0,0 +1,28 @@ +[ + { + "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", + "timestamp": 1434030000000, + "tite": "Test KW2015 1", + "message": "Test KW2015 1 content", + "url": "http://www.sapsailing.com/" + }, + { + "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", + "timestamp": 1434050000000, + "tite": "Test KW2015 2", + "message": "Test KW2015 2 content" + }, + { + "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", + "timestamp": 1434030000000, + "tite": "Test local 1", + "message": "Test local 1 content", + "url": "http://www.sapsailing.com/" + }, + { + "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", + "timestamp": 1434050000000, + "tite": "Test local 2", + "message": "Test local 2 content" + } +] \ No newline at end of file From 32b77348f0df020335689224fb166f1a39326459 Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 12 Jun 2015 15:02:45 +0200 Subject: [PATCH 070/117] moved some media tag constants to com.sap.see.common.media --- .../sap/sailing/gwt/server/HomeServiceUtil.java | 17 +++++++++-------- .../gwt/ui/server/SailingServiceImpl.java | 10 +++++----- .../event/GetEventOverviewStageAction.java | 6 +++--- .../gwt/ui/shared/media/MediaConstants.java | 11 +++-------- .../sap/sse/common/media/MediaTagConstants.java | 10 ++++++++++ 5 files changed, 30 insertions(+), 24 deletions(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 6644e7952f5..20f244f25c5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -27,6 +27,7 @@ import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; 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 { @@ -120,7 +121,7 @@ public final class HomeServiceUtil { ImageHolder(ImageDescriptor image) { this.image = image; - this.stage = image == null ? false : hasTag(image, MediaConstants.STAGE); + 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; @@ -177,7 +178,7 @@ public final class HomeServiceUtil { // search for name pattern for (ImageDescriptor imageUrl : event.getImages()) { - if (hasTag(imageUrl, MediaConstants.TEASER)) { + if (hasTag(imageUrl, MediaTagConstants.TEASER)) { return imageUrl; } } @@ -256,13 +257,13 @@ public final class HomeServiceUtil { } private static boolean isBetterStageImage(ImageDescriptor candidate, ImageDescriptor reference) { - boolean stage = hasTag(candidate, MediaConstants.STAGE); - boolean stageRef = hasTag(reference, MediaConstants.STAGE); + boolean stage = hasTag(candidate, MediaTagConstants.STAGE); + boolean stageRef = hasTag(reference, MediaTagConstants.STAGE); if(stage != stageRef) { return stage; } - boolean teaser = hasTag(candidate, MediaConstants.TEASER); - boolean teaserRef = hasTag(reference, MediaConstants.TEASER); + boolean teaser = hasTag(candidate, MediaTagConstants.TEASER); + boolean teaserRef = hasTag(reference, MediaTagConstants.TEASER); if(teaser != teaserRef) { return !teaser; } @@ -292,7 +293,7 @@ public final class HomeServiceUtil { boolean first = true; for (Iterator iter = imageURLs.iterator(); iter.hasNext(); ) { ImageDescriptor image = iter.next(); - if(hasTag(image, MediaConstants.TEASER)) { + if(hasTag(image, MediaTagConstants.TEASER)) { continue; } if ((first && !iter.hasNext()) || !Util.equalsWithNull(image, stageImage)) { @@ -362,7 +363,7 @@ public final class HomeServiceUtil { public static boolean hasPhotos(Event event) { for(ImageDescriptor image : event.getImages()) { - if(!hasTag(image, MediaConstants.TEASER)) { + if(!hasTag(image, MediaTagConstants.TEASER)) { return true; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index c5913070dfd..9dd06f864a4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -324,7 +324,6 @@ import com.sap.sailing.gwt.ui.shared.RegattaLogEventDTO; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO.ScoreCorrectionEntryDTO; -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sailing.gwt.ui.shared.RemoteSailingServerReferenceDTO; import com.sap.sailing.gwt.ui.shared.ReplicaDTO; import com.sap.sailing.gwt.ui.shared.ReplicationMasterDTO; @@ -434,6 +433,7 @@ 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.MediaTagConstants; import com.sap.sse.common.media.MediaUtils; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; @@ -3307,9 +3307,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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 imageURLs = createURLsFromMedia(images, MediaConstants.SPONSOR, null); + List imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); List videoURLs = createURLsFromMedia(videos, null, null); - List sponsorImageURLs = createURLsFromMedia(images, null, MediaConstants.SPONSOR); + List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( @@ -3346,9 +3346,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; - List imageURLs = createURLsFromMedia(images, MediaConstants.SPONSOR, null); + List imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); List videoURLs = createURLsFromMedia(videos, null, null); - List sponsorImageURLs = createURLsFromMedia(images, null, MediaConstants.SPONSOR); + List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 894a51a9b94..056ef9f861f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -11,13 +11,13 @@ 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.MediaConstants; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.VideoDescriptor; public class GetEventOverviewStageAction implements Action> { - private static final Collection rankedTags = Arrays.asList(MediaConstants.LIVESTREAM, MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); - private static final Collection rankedTagsFinished = Arrays.asList(MediaConstants.FEATURED, MediaConstants.HIGHLIGHT); + private static final Collection rankedTags = Arrays.asList(MediaTagConstants.LIVESTREAM, MediaTagConstants.FEATURED, MediaTagConstants.HIGHLIGHT); + private static final Collection rankedTagsFinished = Arrays.asList(MediaTagConstants.FEATURED, MediaTagConstants.HIGHLIGHT); private UUID eventId; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index 46efef132c4..f20064406f0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -5,18 +5,13 @@ 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 String STAGE = "Stage"; - public static final String TEASER = "Teaser"; - public static final String SPONSOR = "Sponsor"; - public static final String HIGHLIGHT = "Highlight"; - public static final String LIVESTREAM = "Livestream"; - public static final String FEATURED = "Featured"; - public static final List imageTagSuggestions = Arrays.asList(new String[] { STAGE, TEASER, SPONSOR }); - public static final List videoTagSuggestions = Arrays.asList(new String[] { LIVESTREAM, HIGHLIGHT, FEATURED }); + public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER, MediaTagConstants.SPONSOR }); + public static final List videoTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.LIVESTREAM, MediaTagConstants.HIGHLIGHT,MediaTagConstants.FEATURED }); public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); private MediaConstants() { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java new file mode 100644 index 00000000000..3e6d6fcd26c --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.media; + +public interface MediaTagConstants { + static final String STAGE = "Stage"; + 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"; +} From 7092a5c22f33287307ee5ada356aaf5d58160092 Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Fri, 12 Jun 2015 15:15:47 +0200 Subject: [PATCH 071/117] Hotfix to be able to start the old RCApp without crashes --- .../res/values/themes.xml | 14 +++++++++----- .../com.sap.sailing.racecommittee.app/build.gradle | 4 ++-- .../app/ui/activities/RacingActivity.java | 7 +++---- .../app/ui/activities/SessionActivity.java | 8 +++++--- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/mobile/com.sap.sailing.android.shared/res/values/themes.xml b/mobile/com.sap.sailing.android.shared/res/values/themes.xml index 2eefe3b7581..918e28f7383 100644 --- a/mobile/com.sap.sailing.android.shared/res/values/themes.xml +++ b/mobile/com.sap.sailing.android.shared/res/values/themes.xml @@ -5,11 +5,11 @@ false - - + \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/build.gradle b/mobile/com.sap.sailing.racecommittee.app/build.gradle index e6d4fd72c22..f1a47789178 100644 --- a/mobile/com.sap.sailing.racecommittee.app/build.gradle +++ b/mobile/com.sap.sailing.racecommittee.app/build.gradle @@ -46,12 +46,12 @@ android { versionNameSuffix ".debug" signingConfig signingConfigs.stg_debug - minifyEnabled true + minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-project.txt", "../proguard-mobile.txt" } release { - minifyEnabled true + minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-project.txt", "../proguard-mobile.txt" } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java index 6a957f11c71..bab2771fb3b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java @@ -5,14 +5,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import android.app.ActionBar; -import android.app.ActionBar.OnNavigationListener; import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; +import android.support.v7.app.ActionBar; import android.util.Log; import android.view.Window; import android.widget.ArrayAdapter; @@ -46,7 +45,7 @@ public class RacingActivity extends SessionActivity implements RaceInfoListener private static final int RacesLoaderId = 0; - private class FilterModeSelectionBinder implements OnNavigationListener { + private class FilterModeSelectionBinder implements ActionBar.OnNavigationListener { private ManagedRaceListFragment targetList; private ActionBar actionBar; @@ -206,7 +205,7 @@ public class RacingActivity extends SessionActivity implements RaceInfoListener } private void setupActionBar(CourseArea courseArea) { - ActionBar actionBar = getActionBar(); + ActionBar actionBar = getSupportActionBar(); AbstractLogEventAuthor author = preferences.getAuthor(); String title = String.format(getString(R.string.racingview_header), courseArea.getName()); title += " (" + author.getName() + ")"; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/SessionActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/SessionActivity.java index e9f5ccb7593..ca4e38ddfab 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/SessionActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/SessionActivity.java @@ -1,12 +1,12 @@ package com.sap.sailing.racecommittee.app.ui.activities; -import android.app.ActionBar; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.os.Bundle; +import android.support.v7.app.ActionBar; import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.android.shared.logging.ExLog; @@ -19,8 +19,10 @@ public abstract class SessionActivity extends BaseActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } } @Override From 0e85f3c32ddfd133872d724df74fbb75107c804f Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 12 Jun 2015 17:39:29 +0200 Subject: [PATCH 072/117] removed methods to add or remove imageURL, sponsorImageURL and videoURLs as they are now derived always from the corresponding images and videos --- .../impl/DomainObjectFactoryImpl.java | 30 ------- .../sap/sailing/domain/base/EventBase.java | 42 --------- .../domain/base/impl/EventBaseImpl.java | 87 ++++++++++--------- .../test/CalculateImageSizeFromUrlTest.java | 17 ---- .../sailing/domain/base/impl/EventImpl.java | 30 +------ .../gwt/ui/server/SailingServiceImpl.java | 31 +------ ...estStoringAndLoadingEventsAndRegattas.java | 50 +++++++++-- .../impl/EventBaseJsonDeserializer.java | 47 ---------- .../test/EventDataJsonSerializerTest.java | 4 + ...tDataJsonSerializerWithNullValuesTest.java | 4 + ...NullStartAndEndDataJsonSerializerTest.java | 4 + .../server/test/MasterDataImportTest.java | 13 +-- .../server/test/SearchServiceTest.java | 8 +- .../sailing/server/RacingEventService.java | 6 +- .../server/impl/RacingEventServiceImpl.java | 20 +---- .../CreateEvent.java | 11 +-- .../UpdateEvent.java | 11 +-- 17 files changed, 115 insertions(+), 300 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 79571ec4c37..ca1da867877 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -1053,36 +1053,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+name+". Ignoring this URL."); } } - BasicDBList imageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); - if (imageURLs != null) { - for (Object imageURL : imageURLs) { - try { - result.addImageURL(new URL((String) imageURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing image URL "+imageURL+" for event "+name+". Ignoring this image URL."); - } - } - } - BasicDBList videoURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); - if (videoURLs != null) { - for (Object videoURL : videoURLs) { - try { - result.addVideoURL(new URL((String) videoURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing video URL "+videoURL+" for event "+name+". Ignoring this video URL."); - } - } - } - BasicDBList sponsorImageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); - if (sponsorImageURLs != null) { - for (Object sponsorImageURL : sponsorImageURLs) { - try { - result.addSponsorImageURL(new URL((String) sponsorImageURL)); - } catch (MalformedURLException e) { - logger.severe("Error parsing sponsor image URL "+sponsorImageURL+" for event "+name+". Ignoring this sponsor image URL."); - } - } - } BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); if (images != null) { for (Object imageObject : images) { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index a151375553a..a2a5668b5bf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -49,10 +49,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable getImageURLs(); - void addImageURL(URL imageURL); - - void removeImageURL(URL imageURL); - /** * An event may have zero or more sponsors, each of which usually want to see their logo on the web page. * @@ -60,20 +56,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable 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 - * sponsorImageURLs. - * - * @param sponsorImageURLs - * if null, the internal sequence of sponsorship image URLs is cleared but remains valid (non- - * null) - */ - void setSponsorImageURLs(Iterable sponsorImageURLs); - /** * An optional logo image; may return null. */ @@ -81,16 +63,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi void setLogoImageURL(URL logoImageURL); - /** - * Replaces the {@link #getImageURLs() current contents of the image URL sequence} by the image URLs in - * imageURLs. - * - * @param imageURLs - * if null, the internal sequence of image URLs is cleared but remains valid (non- - * null) - */ - void setImageURLs(Iterable imageURLs); - /** * Returns a non-null live but unmodifiable collection of URLs pointing to video resources that can be * used to represent the event, e.g., on a web page. @@ -98,21 +70,7 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi * @return a non-null value which may be empty */ Iterable 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 - * videoURLs. - * - * @param videoURLs - * if null, the internal sequence of image URLs is cleared but remains valid (non- - * null) - */ - void setVideoURLs(Iterable videoURLs); - /** * @return the URL of the event's official web site, or null if such a site does not exist or its URL * is not known diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index da81953006a..adcf351a5ac 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -3,7 +3,9 @@ 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.UUID; import java.util.concurrent.ConcurrentLinkedQueue; @@ -12,6 +14,8 @@ import com.sap.sailing.domain.base.Venue; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; 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 abstract class EventBaseImpl implements EventBase { @@ -52,6 +56,7 @@ public abstract class EventBaseImpl implements EventBase { this.sponsorImageURLs = new ConcurrentLinkedQueue(); this.images = new ConcurrentLinkedQueue(); this.videos = new ConcurrentLinkedQueue(); + syncImageAndVideoURLsForBackwardCompatibility(); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { @@ -143,20 +148,7 @@ public abstract class EventBaseImpl implements EventBase { return Collections.unmodifiableCollection(imageURLs); } - @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 imageURLs) { + protected void setImageURLs(Iterable imageURLs) { this.imageURLs.clear(); if (imageURLs != null) { Util.addAll(imageURLs, this.imageURLs); @@ -168,20 +160,7 @@ public abstract class EventBaseImpl implements EventBase { 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 videoURLs) { + private void setVideoURLs(Iterable videoURLs) { this.videoURLs.clear(); if (videoURLs != null) { Util.addAll(videoURLs, this.videoURLs); @@ -193,20 +172,7 @@ public abstract class EventBaseImpl implements EventBase { return Collections.unmodifiableCollection(sponsorImageURLs); } - @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 sponsorImageURLs) { + protected void setSponsorImageURLs(Iterable sponsorImageURLs) { this.sponsorImageURLs.clear(); if (sponsorImageURLs != null) { Util.addAll(sponsorImageURLs, this.sponsorImageURLs); @@ -242,12 +208,14 @@ public abstract class EventBaseImpl implements EventBase { public void addImage(ImageDescriptor image) { if (!images.contains(image)) { images.add(image); + syncImageURLsFromImagesForBackwardCompatibility(); } } @Override public void removeImage(ImageDescriptor image) { images.remove(image); + syncImageURLsFromImagesForBackwardCompatibility(); } @Override @@ -255,6 +223,7 @@ public abstract class EventBaseImpl implements EventBase { this.images.clear(); if (images != null) { Util.addAll(images, this.images); + syncImageURLsFromImagesForBackwardCompatibility(); } } @@ -267,12 +236,14 @@ public abstract class EventBaseImpl implements EventBase { public void addVideo(VideoDescriptor video) { if (!videos.contains(video)) { videos.add(video); + syncVideoURLsFromVideosForBackwardCompatibility(); } } @Override public void removeVideo(VideoDescriptor video) { videos.remove(video); + syncVideoURLsFromVideosForBackwardCompatibility(); } @Override @@ -280,6 +251,38 @@ public abstract class EventBaseImpl implements EventBase { this.videos.clear(); if (videos != null) { Util.addAll(videos, this.videos); + syncVideoURLsFromVideosForBackwardCompatibility(); } } + + private void syncImageURLsFromImagesForBackwardCompatibility() { + List imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); + List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); + setImageURLs(imageURLs); + setSponsorImageURLs(sponsorImageURLs); + } + + private void syncVideoURLsFromVideosForBackwardCompatibility() { + List videoURLs = createURLsFromMedia(videos, null, null); + setVideoURLs(videoURLs); + } + + private void syncImageAndVideoURLsForBackwardCompatibility() { + syncImageURLsFromImagesForBackwardCompatibility(); + syncVideoURLsFromVideosForBackwardCompatibility(); + } + + private List createURLsFromMedia(Iterable media, String blacklistTag, String whitelistTag) { + List result = new ArrayList<>(); + for (MediaDescriptor mediaEntry : media) { + if (blacklistTag != null && Util.contains(mediaEntry.getTags(), blacklistTag)) { + continue; + } + if (whitelistTag != null && !Util.contains(mediaEntry.getTags(), whitelistTag)) { + continue; + } + result.add(mediaEntry.getURL()); + } + return result; + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java index 189d2d08dcb..4612ea26bf5 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java @@ -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)); - } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java index 19d1fa73ce0..156c317ffc6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java @@ -150,12 +150,6 @@ public class EventImpl extends EventBaseImpl implements Event { return imageSizeCalculator.get(); } - @Override - public void addImageURL(URL imageURL) { - super.addImageURL(imageURL); - refreshImageSizeFetcher(imageURL); - } - private void refreshImageSizeFetcher(URL imageURL) { if (imageURL != null) { removeImageSizeFetcher(imageURL); @@ -163,20 +157,13 @@ public class EventImpl extends EventBaseImpl implements Event { } } - @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 imageURLs) { + protected void setImageURLs(Iterable imageURLs) { super.setImageURLs(imageURLs); if (imageURLs != null) { for (URL imageURL : imageURLs) { @@ -185,20 +172,7 @@ public class EventImpl extends EventBaseImpl implements Event { } } - @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 sponsorImageURLs) { + protected void setSponsorImageURLs(Iterable sponsorImageURLs) { super.setSponsorImageURLs(sponsorImageURLs); if (sponsorImageURLs != null) { for (URL imageURL : sponsorImageURLs) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 9dd06f864a4..de926139f81 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -433,7 +433,6 @@ 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.MediaTagConstants; import com.sap.sse.common.media.MediaUtils; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; @@ -442,7 +441,6 @@ 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.AbstractMediaDTO; import com.sap.sse.gwt.client.media.ImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.server.filestorage.FileStorageServiceDTOUtils; @@ -3307,37 +3305,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S 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 imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); - List videoURLs = createURLsFromMedia(videos, null, null); - List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), - isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, imageURLs, videoURLs, - sponsorImageURLs, eventImages, eventVideos)); + isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, eventImages, eventVideos)); return getEventById(eventId, false); } - /** - * @param urlStrings - * @return - * @throws MalformedURLException - */ - private List createURLsFromMedia(Iterable media, String blacklistTag, String whilelistTag) throws MalformedURLException { - List result = new ArrayList<>(); - for (AbstractMediaDTO mediaEntry : media) { - if(blacklistTag != null && mediaEntry.getTags().contains(blacklistTag)) { - continue; - } - if(whilelistTag != null && !mediaEntry.getTags().contains(whilelistTag)) { - continue; - } - result.add(new URL(mediaEntry.getSourceRef())); - } - return result; - } - @Override public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, List courseAreaNames, Iterable images, Iterable videos, @@ -3346,14 +3321,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; - List imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); - List videoURLs = createURLsFromMedia(videos, null, null); - List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid, - imageURLs, videoURLs, sponsorImageURLs, eventImages, eventVideos, logoImageURLAsString == null ? null : new URL(logoImageURLAsString), officialWebsiteURLAsString == null ? null : new URL(officialWebsiteURLAsString))); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 7f300ad846d..376f92c6694 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -143,12 +143,6 @@ 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); @@ -188,9 +182,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 @@ -330,6 +321,47 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest assertEquals(3, Util.size(loadedVideo1.getTags())); } + @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); + event.addImage(image1); + + ImageDescriptor image2 = new ImageDescriptorImpl(sponsorImageURL, createdAt); + event.addImage(image2); + image2.addTag("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.getImageURLs())); + assertEquals(1, Util.size(loadedEvent.getSponsorImageURLs())); + assertEquals(1, Util.size(loadedEvent.getVideos())); + assertEquals(1, Util.size(loadedEvent.getVideoURLs())); + } + + @Test public void testLoadStoreRegattaConfiguration() { diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index cd6b856b4c2..63938a54f22 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -14,7 +14,6 @@ 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.domain.base.impl.StrippedEventImpl; -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; @@ -74,42 +73,6 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { throw new JsonDeserializationException("Error deserializing logo image URL for event "+name, e); } } - if (eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URLS) != null) { - try { - result.setImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_IMAGE_URLS))); - } catch (MalformedURLException e) { - throw new JsonDeserializationException("Error deserializing image URLs for event "+name, e); - } - } - if (eventJson.get(EventBaseJsonSerializer.FIELD_VIDEO_URLS) != null) { - try { - result.setVideoURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_VIDEO_URLS))); - } catch (MalformedURLException e) { - throw new JsonDeserializationException("Error deserializing video URLs for event "+name, e); - } - } - if (eventJson.get(EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS) != null) { - try { - result.setSponsorImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS))); - } catch (MalformedURLException e) { - throw new JsonDeserializationException("Error deserializing sponsor image URLs for event "+name, e); - } - } - JSONArray imageSizes = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES); - if (imageSizes != null) { - for (Object imageURLAndSizeObject : imageSizes) { - JSONObject imageURLAndSizeJson = (JSONObject) imageURLAndSizeObject; - try { - result.setImageSize( - new URL((String) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URL)), - new ImageSizeImpl( - ((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH)).intValue(), - ((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT)).intValue())); - } catch (MalformedURLException e) { - throw new JsonDeserializationException(e); - } - } - } JSONArray imagesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGES); if (imagesJson != null) { for (Object imageJson : imagesJson) { @@ -198,14 +161,4 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } return video; } - - private Iterable getURLsFromStrings(JSONArray strings) throws MalformedURLException { - List result = new ArrayList(); - if (strings != null) { - for (Object string : strings) { - result.add(new URL(string.toString())); - } - } - return result; - } } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java index 9351a3dcd5b..04f590c68d3 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java @@ -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(); @@ -70,6 +72,8 @@ public class EventDataJsonSerializerTest { when(event.getImageURLs()).thenReturn(Collections.emptySet()); when(event.getVideoURLs()).thenReturn(Collections.emptySet()); when(event.getSponsorImageURLs()).thenReturn(Collections.emptySet()); + when(event.getImages()).thenReturn(Collections.emptySet()); + when(event.getVideos()).thenReturn(Collections.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()); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java index 3bee26cc81a..98e786ed6bb 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java @@ -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(); @@ -65,6 +67,8 @@ public class EventDataJsonSerializerWithNullValuesTest { when(event.getImageURLs()).thenReturn(Collections.emptySet()); when(event.getVideoURLs()).thenReturn(Collections.emptySet()); when(event.getSponsorImageURLs()).thenReturn(Collections.emptySet()); + when(event.getImages()).thenReturn(Collections.emptySet()); + when(event.getVideos()).thenReturn(Collections.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()); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java index ddfc72afdf7..0d4763a4c35 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java @@ -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 { @@ -74,6 +76,8 @@ public class EventWithNullStartAndEndDataJsonSerializerTest { when(event.getImageURLs()).thenReturn(Collections.emptySet()); when(event.getVideoURLs()).thenReturn(Collections.emptySet()); when(event.getSponsorImageURLs()).thenReturn(Collections.emptySet()); + when(event.getImages()).thenReturn(Collections.emptySet()); + when(event.getVideos()).thenReturn(Collections.emptySet()); doReturn(expectedLeaderboardGroups).when(event).getLeaderboardGroups(); // ... and the serializer itself. diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index 879448b4f33..98a87800c54 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -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; @@ -1328,12 +1327,8 @@ public class MasterDataImportTest { InterruptedException, ClassNotFoundException { RacingEventService sourceService = new RacingEventServiceImpl(); - Iterable imageURLs = new HashSet<>(); - Iterable videoURLs = new HashSet<>(); - Iterable sponsorImageURLs = new HashSet<>(); Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null, - new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), imageURLs, - videoURLs, sponsorImageURLs, + new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoImageURL */ null, /* officialWebsiteURL */ null); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); @@ -1397,12 +1392,8 @@ public class MasterDataImportTest { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); - Iterable imageURLs = new HashSet<>(); - Iterable videoURLs = new HashSet<>(); - Iterable sponsorImageURLs = new HashSet<>(); Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null, - new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), imageURLs, - videoURLs, sponsorImageURLs, + new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoImageURL */ null, /* officialWebsiteURL */ null); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java index a1751a5fa21..0a580da67d7 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java @@ -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; @@ -121,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.emptySet(), - Collections.emptySet(), /* sponsorImageURLs */ Collections.emptySet(), - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + "Kiel", true, UUID.randomUUID(), /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoImageURLAsString */ null, /* officialWebsiteURLAsString */ null)); kiel = pfingstbusch.getVenue(); final CourseAreaImpl kielAlpha = new CourseAreaImpl("Alpha", UUID.randomUUID()); @@ -157,8 +154,7 @@ 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.emptySet(), - Collections.emptySet(), /* sponsorImageURLs */ Collections.emptySet(), + "Flensburg", true, UUID.randomUUID(), /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoimageURL */ null, /* officialWebsiteURLAsString */ null)); flensburg = aalEvent.getVenue(); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index 55b20ed8323..c19f8dddd99 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -371,8 +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 leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, - Iterable images, Iterable videos); + URL logoImageURL, Iterable images, Iterable videos); /** * Renames a sailing event. If a sailing event by the name oldName does not exist in {@link #getEvents()}, @@ -467,8 +466,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch ConcurrentHashMap getPersistentRegattasForRaceIDs(); Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, - Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL); + boolean isPublic, UUID id, Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL); void setRegattaForRace(Regatta regatta, String raceIdAsString); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 94af6175092..6ac0281c953 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -2574,13 +2574,9 @@ 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. emptyList(), - /* videoURLs */Collections. emptyList(), /* sponsorImageURLs */Collections. emptyList(), - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), + id, /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoImageURL */ null, /* officialWebsiteURL */null); - replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, /* imageURLs */ - id, Collections. emptyList(), - /* videoURLs */Collections. emptyList(), /* sponsorImageURLs */Collections. emptyList(), + replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id, /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* logoimageURL */null, /* officialWebsiteURLAsString */null)); return result; @@ -2593,15 +2589,11 @@ 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 imageURLs, - Iterable videoURLs, Iterable sponsorImageURLs, Iterable images, Iterable videos, + TimePoint endDate, String venue, boolean isPublic, UUID id, Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL) { 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); @@ -2621,8 +2613,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 leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, - Iterable images, Iterable videos) { + URL logoImageURL, Iterable images, Iterable videos) { final Event event = eventsById.get(id); if (event == null) { throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist."); @@ -2646,9 +2637,6 @@ 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 diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java index 7490157d029..9b5e369c10d 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java @@ -25,17 +25,13 @@ public class CreateEvent extends AbstractEventOperation { private final boolean isPublic; private final String eventName; private final String eventDescription; - private final Iterable videoURLs; - private final Iterable imageURLs; - private final Iterable sponsorImageURLs; private final Iterable images; private final Iterable videos; private final URL logoImageURL; private final URL officialWebsiteURL; public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, - Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL) { + boolean isPublic, UUID id, Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -43,9 +39,6 @@ public class CreateEvent extends AbstractEventOperation { this.endDate = endDate; this.venue = venue; this.isPublic = isPublic; - this.imageURLs = imageURLs; - this.videoURLs = videoURLs; - this.sponsorImageURLs = sponsorImageURLs; this.images = images; this.videos = videos; this.logoImageURL = logoImageURL; @@ -71,7 +64,7 @@ public class CreateEvent extends AbstractEventOperation { @Override public Event internalApplyTo(RacingEventService toState) { return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic, - getId(), imageURLs, videoURLs, sponsorImageURLs, images, videos, logoImageURL, officialWebsiteURL); + getId(), images, videos, logoImageURL, officialWebsiteURL); } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java index c8c17174f0f..ebb953c9939 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java @@ -20,16 +20,12 @@ public class UpdateEvent extends AbstractEventOperation { private final String eventDescription; private final URL officialWebsiteURL; private final URL logoImageURL; - private final Iterable imageURLs; - private final Iterable videoURLs; - private final Iterable sponsorImageURLs; private final Iterable images; private final Iterable videos; public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL logoImageURL, - URL officialWebsiteURL, Iterable imageURLs, Iterable videoURLs, Iterable sponsorImageURLs, - Iterable images, Iterable videos) { + URL officialWebsiteURL, Iterable images, Iterable videos) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -40,9 +36,6 @@ public class UpdateEvent extends AbstractEventOperation { this.leaderboardGroupIds = leaderboardGroupIds; this.officialWebsiteURL = officialWebsiteURL; this.logoImageURL = logoImageURL; - this.imageURLs = imageURLs; - this.videoURLs = videoURLs; - this.sponsorImageURLs = sponsorImageURLs; this.images = images; this.videos = videos; } @@ -62,7 +55,7 @@ public class UpdateEvent extends AbstractEventOperation { @Override public Void internalApplyTo(RacingEventService toState) { toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic, - leaderboardGroupIds, officialWebsiteURL, logoImageURL, imageURLs, videoURLs, sponsorImageURLs, images, videos); + leaderboardGroupIds, officialWebsiteURL, logoImageURL, images, videos); return null; } } From 8125b4f3d4814b8e0116886884cfafc3fae082ac Mon Sep 17 00:00:00 2001 From: fmittag Date: Sun, 14 Jun 2015 14:27:53 +0200 Subject: [PATCH 073/117] bigger cleanup of image and video management of an event --- .../gwt/client/eventlogo/EventLogo.java | 7 +- .../impl/DomainObjectFactoryImpl.java | 151 ++++++++++++------ .../impl/MongoObjectFactoryImpl.java | 4 + .../sap/sailing/domain/base/EventBase.java | 48 +++++- .../domain/base/impl/EventBaseImpl.java | 44 ++--- .../sailing/domain/base/impl/EventImpl.java | 6 +- .../ui/adminconsole/EventCreateDialog.java | 4 +- .../adminconsole/EventDetailsComposite.java | 24 ++- .../gwt/ui/adminconsole/EventDialog.java | 34 +--- .../gwt/ui/adminconsole/EventEditDialog.java | 12 -- .../ui/adminconsole/EventListComposite.java | 7 +- .../ui/adminconsole/ImageCreateDialog.java | 11 +- .../ui/adminconsole/ImagesListComposite.java | 40 ++++- .../ui/adminconsole/RegattaImportDialog.java | 17 +- .../StructureImportManagementPanel.java | 5 +- .../sailing/gwt/ui/client/SailingService.java | 5 +- .../gwt/ui/client/SailingServiceAsync.java | 5 +- .../gwt/ui/server/SailingServiceImpl.java | 41 +---- .../sailing/gwt/ui/shared/EventBaseDTO.java | 48 ++---- .../gwt/ui/shared/media/MediaConstants.java | 2 +- ...estStoringAndLoadingEventsAndRegattas.java | 3 +- .../impl/EventBaseJsonDeserializer.java | 89 +++++++++-- .../impl/EventBaseJsonSerializer.java | 43 ++--- .../test/EventDataJsonSerializerTest.java | 1 + ...JsonSerializerWithImagesAndVideosTest.java | 1 + ...tDataJsonSerializerWithNullValuesTest.java | 25 ++- ...NullStartAndEndDataJsonSerializerTest.java | 2 + .../server/test/MasterDataImportTest.java | 8 +- .../server/test/SearchServiceTest.java | 8 +- .../sailing/server/RacingEventService.java | 5 +- .../server/impl/RacingEventServiceImpl.java | 15 +- .../CreateEvent.java | 8 +- .../UpdateEvent.java | 8 +- .../common/media/AbstractMediaDescriptor.java | 5 + .../sap/sse/common/media/MediaDescriptor.java | 3 +- .../sse/common/media/MediaTagConstants.java | 1 + .../gwt/client/media/AbstractMediaDTO.java | 4 + 37 files changed, 411 insertions(+), 333 deletions(-) diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java index 27c06e0ee36..39971c2fd18 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java @@ -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() { @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); } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index ca1da867877..b4a99fafea5 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -194,6 +194,7 @@ import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.media.ImageDescriptor; import com.sap.sse.common.media.ImageDescriptorImpl; 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; @@ -1045,14 +1046,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL."); } } - String logoImageURLAsString = (String) eventDBObject.get(FieldNames.EVENT_LOGO_IMAGE_URL.name()); - if (logoImageURLAsString != null) { - try { - result.setLogoImageURL(new URL(logoImageURLAsString)); - } catch (MalformedURLException e) { - logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+name+". Ignoring this URL."); - } - } + loadLegacyImageAndVideoURLs(result, eventDBObject); BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); if (images != null) { for (Object imageObject : images) { @@ -2141,62 +2135,129 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } /** - * Migrates images and videos stored as pure URLs to the new richer format once + * Migrates images and videos stored as pure URLs to the new richer media format * @param event the event to migrate */ + @SuppressWarnings("deprecation") private void migrateImagesAndVideosOfEvent(Event event) { boolean changedAnything = false; - changedAnything |= migrateImagesOfEvent(event, event.getImageURLs(), false); - changedAnything |= migrateImagesOfEvent(event, event.getSponsorImageURLs(), true); - - for(URL url: event.getVideoURLs()) { - if(hasMedia(event.getVideos(), url)) { - continue; + List newImages = new ArrayList<>(); + for (URL url : event.getImageURLs()) { + if (!hasMedia(event.getImages(), url)) { + ImageDescriptor image = migrateImageURLtoImage(url, event.getStartDate()); + 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); + } + newImages.add(image); + changedAnything = true; + } + } + for (URL url : event.getSponsorImageURLs()) { + if (!hasMedia(event.getImages(), url)) { + ImageDescriptor image = migrateImageURLtoImage(url, event.getStartDate()); + image.addTag(MediaTagConstants.SPONSOR); + newImages.add(image); + changedAnything = true; } - changedAnything = true; - MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); - VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, MillisecondsTimePoint.now()); - event.addVideo(video); } - if(changedAnything) { + if (event.getLogoImageURL() != null && !hasMedia(event.getImages(), event.getLogoImageURL())) { + ImageDescriptor image = migrateImageURLtoImage(event.getLogoImageURL(), event.getStartDate()); + image.addTag(MediaTagConstants.LOGO); + newImages.add(image); + changedAnything = true; + } + + List newVideos = new ArrayList(); + for (URL url : event.getVideoURLs()) { + if (!hasMedia(event.getVideos(), url)) { + MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); + VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, event.getStartDate()); + newVideos.add(video); + changedAnything = true; + } + } + + if (changedAnything) { + for (VideoDescriptor newVideo : newVideos) { + event.addVideo(newVideo); + } + for (ImageDescriptor newImage : newImages) { + event.addImage(newImage); + } new MongoObjectFactoryImpl(database).storeEvent(event); } } - private boolean migrateImagesOfEvent(Event event, Iterable images, boolean sponsor) { - boolean changedAnything = false; - for(URL url: event.getImageURLs()) { - String urlAsString = url.toString(); - if(hasMedia(event.getImages(), url)) { - continue; + /** + * Legacy code to support conversion of old image and video URLs + * @param event + * @param eventDBObject + */ + @SuppressWarnings("deprecation") + private void loadLegacyImageAndVideoURLs(Event event, DBObject eventDBObject) { + String logoImageURLAsString = (String) eventDBObject.get(FieldNames.EVENT_LOGO_IMAGE_URL.name()); + if (logoImageURLAsString != null) { + try { + event.setLogoImageURL(new URL(logoImageURLAsString)); + } catch (MalformedURLException e) { + logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+event.getName()+". Ignoring this URL."); } - changedAnything = true; - ImageDescriptorImpl image = new ImageDescriptorImpl(url, MillisecondsTimePoint.now()); - - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if(imageDimensions != null) { - image.setSize(imageDimensions); - } - - if(sponsor) { - image.addTag("Sponsor"); - } else { - if(urlAsString.toLowerCase().indexOf("stage") > 0) { - image.addTag("Stage"); - } else if(urlAsString.toLowerCase().indexOf("eventteaser") > 0) { - image.addTag("Teaser"); + } + BasicDBList imageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); + if (imageURLs != null) { + List urls = new ArrayList<>(); + for (Object imageURL : imageURLs) { + try { + urls.add(new URL((String) imageURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing image URL "+imageURL+" for event "+event.getName()+". Ignoring this image URL."); } } - event.addImage(image); + event.setImageURLs(urls); } - return changedAnything; + BasicDBList videoURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); + if (videoURLs != null) { + List urls = new ArrayList<>(); + for (Object videoURL : videoURLs) { + try { + urls.add(new URL((String) videoURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing video URL "+videoURL+" for event "+event.getName()+". Ignoring this video URL."); + } + } + event.setVideoURLs(urls); + } + BasicDBList sponsorImageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); + if (sponsorImageURLs != null) { + List urls = new ArrayList<>(); + for (Object sponsorImageURL : sponsorImageURLs) { + try { + urls.add(new URL((String) sponsorImageURL)); + } catch (MalformedURLException e) { + logger.severe("Error parsing sponsor image URL "+sponsorImageURL+" for event "+event.getName()+". Ignoring this sponsor image URL."); + } + } + event.setSponsorImageURLs(urls); + } + } + + private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt) { + ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if (imageDimensions != null) { + image.setSize(imageDimensions); + } + return image; } private boolean hasMedia(Iterable media, URL url) { - for(MediaDescriptor mediaEntry : media) { - if(url.equals(mediaEntry.getURL())) { + for (MediaDescriptor mediaEntry : media) { + if (url.equals(mediaEntry.getURL())) { return true; } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 9e12f84d253..5ecab343599 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -516,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()); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index a2a5668b5bf..8ca8d0b4c72 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -42,6 +42,7 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi void setPublic(boolean isPublic); /** + * @deprecated * Returns a non-null live but unmodifiable collection of URLs pointing to image resources that can be * used to represent the event, e.g., on a web page. * @@ -50,20 +51,48 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi Iterable getImageURLs(); /** + * @deprecated + * Replaces the {@link #getImageURLs() current contents of the image URL sequence} by the image URLs in + * imageURLs. + * + * @param imageURLs + * if null, the internal sequence of image URLs is cleared but remains valid (non- + * null) + */ + void setImageURLs(Iterable imageURLs); + + /** + * @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-null but possibly empty */ Iterable getSponsorImageURLs(); - + /** + * @deprecated + * Replaces the {@link #getSponsorImageURLs() current contents of the sponsorship image URL sequence} by the image URLs in + * sponsorImageURLs. + * + * @param sponsorImageURLs + * if null, the internal sequence of sponsorship image URLs is cleared but remains valid (non- + * null) + */ + void setSponsorImageURLs(Iterable sponsorImageURLs); + + /** + * @deprecated * An optional logo image; may return null. */ URL getLogoImageURL(); - - void setLogoImageURL(URL logoImageURL); - + /** + * @deprecated + */ + void setLogoImageURL(URL logoImageURL); + + /** + * @deprecated * Returns a non-null live but unmodifiable collection of URLs pointing to video resources that can be * used to represent the event, e.g., on a web page. * @@ -71,6 +100,17 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable getVideoURLs(); + /** + * @deprecated + * Replaces the {@link #getVideoURLs() current contents of the video URL sequence} by the video URLs in + * videoURLs. + * + * @param videoURLs + * if null, the internal sequence of image URLs is cleared but remains valid (non- + * null) + */ + void setVideoURLs(Iterable videoURLs); + /** * @return the URL of the event's official web site, or null if such a site does not exist or its URL * is not known diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index adcf351a5ac..71a19adb66b 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -14,7 +14,6 @@ import com.sap.sailing.domain.base.Venue; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; 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; @@ -148,7 +147,8 @@ public abstract class EventBaseImpl implements EventBase { return Collections.unmodifiableCollection(imageURLs); } - protected void setImageURLs(Iterable imageURLs) { + @Override + public void setImageURLs(Iterable imageURLs) { this.imageURLs.clear(); if (imageURLs != null) { Util.addAll(imageURLs, this.imageURLs); @@ -160,7 +160,8 @@ public abstract class EventBaseImpl implements EventBase { return Collections.unmodifiableCollection(videoURLs); } - private void setVideoURLs(Iterable videoURLs) { + @Override + public void setVideoURLs(Iterable videoURLs) { this.videoURLs.clear(); if (videoURLs != null) { Util.addAll(videoURLs, this.videoURLs); @@ -172,7 +173,8 @@ public abstract class EventBaseImpl implements EventBase { return Collections.unmodifiableCollection(sponsorImageURLs); } - protected void setSponsorImageURLs(Iterable sponsorImageURLs) { + @Override + public void setSponsorImageURLs(Iterable sponsorImageURLs) { this.sponsorImageURLs.clear(); if (sponsorImageURLs != null) { Util.addAll(sponsorImageURLs, this.sponsorImageURLs); @@ -256,14 +258,28 @@ public abstract class EventBaseImpl implements EventBase { } private void syncImageURLsFromImagesForBackwardCompatibility() { - List imageURLs = createURLsFromMedia(images, MediaTagConstants.SPONSOR, null); - List sponsorImageURLs = createURLsFromMedia(images, null, MediaTagConstants.SPONSOR); + List imageURLs = new ArrayList<>(); + List sponsorImageURLs = new ArrayList<>(); + URL logoImageURL = null; + for (ImageDescriptor image : images) { + if (image.hasTag(MediaTagConstants.SPONSOR)) { + sponsorImageURLs.add(image.getURL()); + } else if (image.hasTag(MediaTagConstants.LOGO)) { + logoImageURL = image.getURL(); + } else { + imageURLs.add(image.getURL()); + } + } setImageURLs(imageURLs); setSponsorImageURLs(sponsorImageURLs); + setLogoImageURL(logoImageURL); } private void syncVideoURLsFromVideosForBackwardCompatibility() { - List videoURLs = createURLsFromMedia(videos, null, null); + List videoURLs = new ArrayList<>(); + for (VideoDescriptor video : videos) { + videoURLs.add(video.getURL()); + } setVideoURLs(videoURLs); } @@ -271,18 +287,4 @@ public abstract class EventBaseImpl implements EventBase { syncImageURLsFromImagesForBackwardCompatibility(); syncVideoURLsFromVideosForBackwardCompatibility(); } - - private List createURLsFromMedia(Iterable media, String blacklistTag, String whitelistTag) { - List result = new ArrayList<>(); - for (MediaDescriptor mediaEntry : media) { - if (blacklistTag != null && Util.contains(mediaEntry.getTags(), blacklistTag)) { - continue; - } - if (whitelistTag != null && !Util.contains(mediaEntry.getTags(), whitelistTag)) { - continue; - } - result.add(mediaEntry.getURL()); - } - return result; - } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java index 156c317ffc6..08f69d2ea88 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java @@ -163,7 +163,8 @@ public class EventImpl extends EventBaseImpl implements Event { } } - protected void setImageURLs(Iterable imageURLs) { + @Override + public void setImageURLs(Iterable imageURLs) { super.setImageURLs(imageURLs); if (imageURLs != null) { for (URL imageURL : imageURLs) { @@ -172,7 +173,8 @@ public class EventImpl extends EventBaseImpl implements Event { } } - protected void setSponsorImageURLs(Iterable sponsorImageURLs) { + @Override + public void setSponsorImageURLs(Iterable sponsorImageURLs) { super.setSponsorImageURLs(sponsorImageURLs); if (sponsorImageURLs != null) { for (URL imageURL : sponsorImageURLs) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index 0d01b9e47e1..3945c293834 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -9,6 +9,7 @@ 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 { @@ -30,10 +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.emptyList()); + videosListComposite.fillVideos(Collections.emptyList()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java index a779a8b589c..d6f5334575c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java @@ -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 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 imageURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getImageURLs(), imageURLStringsAsList); + for(ImageDTO image: event.getImages()) { + imageURLStringsAsList.add(image.getSourceRef()); + } imageURLList.setValues(imageURLStringsAsList); List videoURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getVideoURLs(), videoURLStringsAsList); + for(VideoDTO video: event.getVideos()) { + videoURLStringsAsList.add(video.getSourceRef()); + } videoURLList.setValues(videoURLStringsAsList); - List sponsorImageURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList); - sponsorImageURLList.setValues(sponsorImageURLStringsAsList); List leaderboardGroupNamesAsList = new ArrayList<>(); for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { leaderboardGroupNamesAsList.add(leaderboardGroupDTO.getName()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 99e2c3a034e..428762287a4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -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; @@ -43,11 +42,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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 availableLeaderboardGroups; protected ImagesListComposite imagesListComposite; @@ -137,21 +132,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ SuggestedCourseAreaNames.suggestedCourseAreaNames, stringMessages.enterCourseAreaName(), 50)); courseAreaNameList.addValueChangeHandler(valueChangeHandler); - final List imageSuggestionURLs = Arrays.asList(new String[] { "http://", "https://", "http://www.", "https://www" }); - imageURLList = new StringListInlineEditorComposite(Collections. emptyList(), - new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), - /* suggestValues */ imageSuggestionURLs, stringMessages.enterImageURL(), 80)); - imageURLList.addValueChangeHandler(valueChangeHandler); - List videoURLSuggestions = new ArrayList<>(imageSuggestionURLs); - videoURLSuggestions.add("http://www.youtube.com/watch?v="); - videoURLList = new StringListInlineEditorComposite(Collections. emptyList(), - new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), - /* suggestValues */ videoURLSuggestions, stringMessages.enterVideoURL(), 80)); - videoURLList.addValueChangeHandler(valueChangeHandler); - sponsorImageURLList = new StringListInlineEditorComposite(Collections. emptyList(), - new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), - /* suggestValues */ imageSuggestionURLs, stringMessages.enterSponsorImageURL(), 80)); - sponsorImageURLList.addValueChangeHandler(valueChangeHandler); List leaderboardGroupNames = new ArrayList<>(); for(LeaderboardGroupDTO leaderboardGroupDTO: availableLeaderboardGroups) { leaderboardGroupNames.add(leaderboardGroupDTO.getName()); @@ -177,7 +157,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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(); @@ -189,15 +168,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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); - } for(ImageDTO image: imagesListComposite.getAllImages()) { result.addImage(image); } @@ -217,7 +187,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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() + ":")); @@ -234,8 +204,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap 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"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index e875e941820..ec9b7a269ed 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -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 otherExistingEvents, List availableLeaderboardGroups, StringMessages stringMessages, DialogCallback callback) { @@ -37,18 +36,7 @@ public class EventEditDialog extends EventDialog { } officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL()); officialWebsiteURLEntryField.setVisibleLength(50); - logoImageURLEntryField = createTextBox(event.getLogoImageURL()); - logoImageURLEntryField.setVisibleLength(50); courseAreaNameList.setValue(courseAreaNames); - List imageURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getImageURLs(), imageURLStringsAsList); - imageURLList.setValue(imageURLStringsAsList); - List videoURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getVideoURLs(), videoURLStringsAsList); - videoURLList.setValue(videoURLStringsAsList); - List sponsorImageURLStringsAsList = new ArrayList<>(); - Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList); - sponsorImageURLList.setValue(sponsorImageURLStringsAsList); List leaderboardGroupNames = new ArrayList<>(); for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { leaderboardGroupNames.add(leaderboardGroupDTO.getName()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index 4b976c37b41..082ea76cc48 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -491,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.getImages(), updatedEvent.getVideos(), + updatedEvent.getOfficialWebsiteURL(), updatedEvent.getImages(), updatedEvent.getVideos(), new AsyncCallback() { @Override public void onFailure(Throwable t) { @@ -563,8 +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.getImages(), newEvent.getVideos(), - newEvent.getLogoImageURL(), newEvent.getOfficialWebsiteURL(), new AsyncCallback() { + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), + newEvent.getImages(), newEvent.getVideos(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java index 2b98b8c85c2..c3304669cc6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.Collections; +import java.util.ArrayList; +import java.util.List; import com.google.gwt.user.client.ui.Label; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -8,7 +9,7 @@ import com.sap.sse.gwt.client.media.ImageDTO; public class ImageCreateDialog extends ImageDialog { - public ImageCreateDialog(StringMessages stringMessages, DialogCallback callback) { + public ImageCreateDialog(String initialTag, StringMessages stringMessages, DialogCallback callback) { super(new ImageParameterValidator(stringMessages), stringMessages, callback); createdAtLabel = new Label(creationDate.toString()); titleTextBox = createTextBox(null); @@ -19,6 +20,10 @@ public class ImageCreateDialog extends ImageDialog { copyrightTextBox.setVisibleLength(50); widthInPxBox = createIntegerBox(null, 10); heightInPxBox = createIntegerBox(null, 10); - tagsListEditor.setValue(Collections.emptyList()); + List tags = new ArrayList<>(); + if(initialTag != null && !initialTag.isEmpty()) { + tags.add(initialTag); + } + tagsListEditor.setValue(tags); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index 7312df6e505..c4c7a0087aa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -28,6 +28,7 @@ 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; @@ -74,15 +75,42 @@ public class ImagesListComposite extends Composite { imagesControlsPanel.setSpacing(5); panel.add(imagesControlsPanel); - Button createImageBtn = new Button("Add image"); - createImageBtn.addClickHandler(new ClickHandler() { + Button addPhotoBtn = new Button("Add photo"); + addPhotoBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(); + openCreateImageDialog(null); } }); - imagesControlsPanel.add(createImageBtn); + 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(); imageListDataProvider = new ListDataProvider(); imageTable = createImagesTable(); @@ -230,8 +258,8 @@ public class ImagesListComposite extends Composite { return result; } - private void openCreateImageDialog() { - ImageCreateDialog dialog = new ImageCreateDialog(stringMessages, new DialogCallback() { + private void openCreateImageDialog(String initialTag) { + ImageCreateDialog dialog = new ImageCreateDialog(initialTag, stringMessages, new DialogCallback() { @Override public void cancel() { } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaImportDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaImportDialog.java index 30b093196d8..8a5c64fdc6a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaImportDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaImportDialog.java @@ -30,14 +30,11 @@ public class RegattaImportDialog extends DataEntryDialog{ 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 validator, com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback callback) { @@ -53,7 +50,7 @@ public class RegattaImportDialog extends DataEntryDialog{ 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{ 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{ 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{ 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"; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java index e4ee01bc61c..2dfebccfcfc 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java @@ -246,8 +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.getImages(), newEvent.getVideos(), newEvent.getLogoImageURL(), - newEvent.getOfficialWebsiteURL(), new AsyncCallback() { + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), + newEvent.getImages(), newEvent.getVideos(), + new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError(stringMessages.errorTryingToCreateNewEvent(newEvent.getName(), t.getMessage())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 279f6a49688..4963289df96 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -296,11 +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 leaderboardGroupIds, String officialWebsiteURL, - String logoImageURL, Iterable images, Iterable videos) throws Exception; + Iterable images, Iterable videos) throws Exception; EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, Iterable images, Iterable videos, - String logoImageURL, String officialWebsiteURL) throws Exception; + boolean isPublic, List courseAreaNames, String officialWebsiteURL, Iterable images, Iterable videos) throws Exception; void removeEvent(UUID eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 3f6a088f5c8..3048991ff99 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -367,11 +367,12 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM void removeEvents(Collection eventIds, AsyncCallback asyncCallback); void createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, - List courseAreaNames, Iterable images, Iterable videos, String logoImageURL, String officialWebsiteURL, AsyncCallback callback); + List courseAreaNames, String officialWebsiteURL, Iterable images, Iterable videos, + AsyncCallback callback); void updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, - String logoImageURL, Iterable images, Iterable videos, AsyncCallback callback); + Iterable images, Iterable videos, AsyncCallback callback); void createCourseArea(UUID eventId, String courseAreaName, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index de926139f81..b0b45cf4d5d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3300,23 +3300,21 @@ 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 leaderboardGroupIds, String officialWebsiteURLString, - String logoImageURLString, Iterable images, Iterable videos) throws MalformedURLException { + Iterable images, Iterable 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 eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), - isPublic, leaderboardGroupIds, logoImageURL, officialWebsiteURL, eventImages, eventVideos)); + isPublic, leaderboardGroupIds, officialWebsiteURL, eventImages, eventVideos)); return getEventById(eventId, false); } @Override public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, Iterable images, Iterable videos, - String logoImageURLAsString, String officialWebsiteURLAsString) + boolean isPublic, List courseAreaNames, String officialWebsiteURLAsString, Iterable images, Iterable videos) throws MalformedURLException { UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; @@ -3325,9 +3323,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List eventVideos = convertToVideos(videos); getService().apply( new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid, - eventImages, eventVideos, - 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); } @@ -3406,23 +3402,6 @@ 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(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(ImageDescriptor image: event.getImages()) { eventDTO.addImage(convertToImageDTO(image)); } @@ -3431,14 +3410,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } - 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 convertToImages(Iterable images) throws MalformedURLException { List eventImages = new ArrayList(); for (ImageDTO image : images) { @@ -4171,8 +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.getImages(), newEvent.getVideos()); + newEvent.isPublic, eventLeaderboardGroupUUIDs, newEvent.getOfficialWebsiteURL(), + newEvent.getImages(), newEvent.getVideos()); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 418699ecd20..940c015ac8d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -10,6 +10,7 @@ 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; @@ -24,10 +25,6 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { private String description; private List leaderboardGroups; - private List imageURLs = new ArrayList<>(); - private List videoURLs = new ArrayList<>(); - private List sponsorImageURLs = new ArrayList<>(); - private String logoImageURL; private String officialWebsiteURL; private List images = new ArrayList<>(); private List videos = new ArrayList<>(); @@ -66,6 +63,17 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { this.imageSizes = new HashMap(); } + 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))) { @@ -82,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; } @@ -111,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 getImageURLs() { - return imageURLs; - } - - public List getVideoURLs() { - return videoURLs; - } - - public List getSponsorImageURLs() { - return sponsorImageURLs; - } - public Iterable getLeaderboardGroups() { return leaderboardGroups; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index f20064406f0..cb7c5aecdbc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -10,7 +10,7 @@ import com.sap.sse.common.media.MimeType; public final class MediaConstants { - public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER, MediaTagConstants.SPONSOR }); + public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER, MediaTagConstants.SPONSOR, MediaTagConstants.LOGO }); public static final List videoTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.LIVESTREAM, MediaTagConstants.HIGHLIGHT,MediaTagConstants.FEATURED }); public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 376f92c6694..b8a0de0489c 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -144,7 +144,6 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest event.addLeaderboardGroup(lg2); event.setDescription(eventDescription); 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 +168,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 lgIter = loadedEvent.getLeaderboardGroups().iterator(); assertSame(lg1, lgIter.next()); @@ -321,6 +319,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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. diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 63938a54f22..0c17a99091b 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -3,8 +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; @@ -14,13 +16,18 @@ 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.domain.base.impl.StrippedEventImpl; +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.Util.Pair; 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.MediaUtils; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; import com.sap.sse.common.media.VideoDescriptorImpl; @@ -39,7 +46,6 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { 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); - String logoImageURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL); Number startDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_START_DATE); Number endDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_END_DATE); final Venue venue; @@ -66,13 +72,6 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { throw new JsonDeserializationException("Error deserializing official website URL for event "+name, e); } } - if (logoImageURLAsString != null) { - try { - result.setLogoImageURL(new URL(logoImageURLAsString)); - } catch (MalformedURLException e) { - throw new JsonDeserializationException("Error deserializing logo image URL for event "+name, e); - } - } JSONArray imagesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGES); if (imagesJson != null) { for (Object imageJson : imagesJson) { @@ -91,10 +90,63 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } } } - + // 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 { + String logoImageURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL); + if (logoImageURLAsString != null) { + try { + event.setLogoImageURL(new URL(logoImageURLAsString)); + } catch (MalformedURLException e) { + throw new JsonDeserializationException("Error deserializing logo image URL for event "+event.getName(), e); + } + } + if (eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URLS) != null) { + try { + event.setImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_IMAGE_URLS))); + } catch (MalformedURLException e) { + throw new JsonDeserializationException("Error deserializing image URLs for event "+event.getName(), e); + } + } + if (eventJson.get(EventBaseJsonSerializer.FIELD_VIDEO_URLS) != null) { + try { + event.setVideoURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_VIDEO_URLS))); + } catch (MalformedURLException e) { + throw new JsonDeserializationException("Error deserializing video URLs for event "+event.getName(), e); + } + } + if (eventJson.get(EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS) != null) { + try { + event.setSponsorImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS))); + } catch (MalformedURLException e) { + throw new JsonDeserializationException("Error deserializing sponsor image URLs for event "+event.getName(), e); + } + } + // handle images sizes coming from an old server instance not having images and videos in the rich format + Map imageSizes = new HashMap();; + JSONArray imageSizesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_SIZES); + if (imageSizesJson != null) { + for (Object imageURLAndSizeObject : imageSizesJson) { + JSONObject imageURLAndSizeJson = (JSONObject) imageURLAndSizeObject; + try { + imageSizes.put( + new URL((String) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URL)), + new ImageSizeImpl( + ((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH)).intValue(), + ((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT)).intValue())); + } catch (MalformedURLException e) { + throw new JsonDeserializationException(e); + } + } + } + } + private ImageDescriptor loadImage(JSONObject imageJson) { ImageDescriptor image = null; URL imageURL = Helpers.getURLField(imageJson, EventBaseJsonSerializer.FIELD_SOURCE_URL); @@ -161,4 +213,23 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } return video; } + + private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt, ImageSize size) { + ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if (imageDimensions != null) { + image.setSize(imageDimensions); + } + return image; + } + + private Iterable getURLsFromStrings(JSONArray strings) throws MalformedURLException { + List result = new ArrayList(); + if (strings != null) { + for (Object string : strings) { + result.add(new URL(string.toString())); + } + } + return result; + } } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index 8ca830dacfd..6155f8b61d7 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -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; @@ -13,12 +10,9 @@ 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.ImageDescriptor; -import com.sap.sse.common.media.ImageSize; import com.sap.sse.common.media.VideoDescriptor; public class EventBaseJsonSerializer implements JsonSerializer { - 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"; @@ -62,16 +56,17 @@ public class EventBaseJsonSerializer implements JsonSerializer { 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())); @@ -82,14 +77,8 @@ public class EventBaseJsonSerializer implements JsonSerializer { } JSONArray imageSizes = new JSONArray(); result.put(FIELD_IMAGE_SIZES, imageSizes); - for (URL imageURL : event.getImageURLs()) { - addImageSize(imageURL, imageSizes, event); - } - if (event.getLogoImageURL() != null) { - addImageSize(event.getLogoImageURL(), imageSizes, event); - } - for (URL sponsorImageURL : event.getSponsorImageURLs()) { - addImageSize(sponsorImageURL, imageSizes, event); + for (ImageDescriptor image : event.getImages()) { + addImageSize(image, imageSizes); } JSONArray jsonImages = new JSONArray(); for(ImageDescriptor imageDescriptor: event.getImages()) { @@ -143,24 +132,16 @@ public class EventBaseJsonSerializer implements JsonSerializer { } /** - * If eventBase knows the size of the image with URL imageURL, that size is serialized as + * For backward compatibility the size of an image is also serialized as * JSON object to imageSizes */ - 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()); } } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java index 04f590c68d3..0ea003c6dfd 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java @@ -57,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 ... diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java index 6f320bf225a..d4d833b9be9 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java @@ -104,6 +104,7 @@ public class EventDataJsonSerializerWithImagesAndVideosTest { videos.add(video1); } + @SuppressWarnings("deprecation") @Before public void setUp() { // Event and its basic attributes ... diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java index 98e786ed6bb..b9622aeda1c 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java @@ -52,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 ... @@ -83,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())); } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java index 0d4763a4c35..6caf3c22561 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java @@ -57,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 ... @@ -95,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); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index 98a87800c54..cd6423286a8 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -1329,8 +1329,8 @@ public class MasterDataImportTest { Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null, new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoImageURL */ null, /* officialWebsiteURL */ null); + /* officialWebsiteURL */ null, /* images */Collections. emptyList(), + /* videos */Collections. emptyList()); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); Regatta regatta = sourceService.createRegatta( @@ -1394,8 +1394,8 @@ public class MasterDataImportTest { Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */ null, new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoImageURL */ null, /* officialWebsiteURL */ null); + /* officialWebsiteURL */ null, /* images */Collections. emptyList(), + /* videos */Collections. emptyList()); CourseArea defaultCourseArea = sourceService.addCourseArea(event.getId(), "ECHO", UUID.randomUUID()); List raceColumnNames = new ArrayList(); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java index 0a580da67d7..0933a8d1256 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java @@ -120,8 +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(), /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoImageURLAsString */ null, /* officialWebsiteURLAsString */ null)); + "Kiel", true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /* images */Collections. emptyList(), /* videos */Collections. 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(), - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoimageURL */ null, /* officialWebsiteURLAsString */ null)); + "Flensburg", true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, + /* images */Collections. emptyList(), /* videos */Collections. emptyList())); flensburg = aalEvent.getVenue(); final CourseAreaImpl flensburgStandard = new CourseAreaImpl("Standard", UUID.randomUUID()); flensburg.addCourseArea(flensburgStandard); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index c19f8dddd99..ccfc26062cd 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -371,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 leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable images, Iterable videos); + Iterable images, Iterable videos); /** * Renames a sailing event. If a sailing event by the name oldName does not exist in {@link #getEvents()}, @@ -466,7 +466,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch ConcurrentHashMap getPersistentRegattasForRaceIDs(); Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL); + boolean isPublic, UUID id, URL officialWebsiteURL, Iterable images, + Iterable videos); void setRegattaForRace(Regatta regatta, String raceIdAsString); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 6ac0281c953..4ce6bd25815 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -2574,11 +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, /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoImageURL */ null, /* officialWebsiteURL */null); + id, /* officialWebsiteURL */null, /* images */Collections. emptyList(), + /* videos */Collections. emptyList()); replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id, - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* logoimageURL */null, /* officialWebsiteURLAsString */null)); + /* officialWebsiteURLAsString */null, /* images */Collections. emptyList(), /* videos */Collections. emptyList())); return result; } @@ -2589,12 +2588,11 @@ 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 images, Iterable videos, - URL logoImageURL, URL officialWebsiteURL) { + TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, Iterable images, + Iterable videos) { Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id); addEvent(result); result.setDescription(eventDescription); - result.setLogoImageURL(logoImageURL); result.setOfficialWebsiteURL(officialWebsiteURL); result.setImages(images); result.setVideos(videos); @@ -2613,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 leaderboardGroupIds, URL officialWebsiteURL, - URL logoImageURL, Iterable images, Iterable videos) { + Iterable images, Iterable videos) { final Event event = eventsById.get(id); if (event == null) { throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist."); @@ -2636,7 +2634,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } event.setLeaderboardGroups(leaderboardGroups); event.setOfficialWebsiteURL(officialWebsiteURL); - event.setLogoImageURL(logoImageURL); event.setImages(images); event.setVideos(videos); // TODO consider use diffutils to compute diff between old and new leaderboard groups list and apply the patch diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java index 9b5e369c10d..6f3e88beb25 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java @@ -27,11 +27,10 @@ public class CreateEvent extends AbstractEventOperation { private final String eventDescription; private final Iterable images; private final Iterable videos; - private final URL logoImageURL; private final URL officialWebsiteURL; public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, Iterable images, Iterable videos, URL logoImageURL, URL officialWebsiteURL) { + boolean isPublic, UUID id, URL officialWebsiteURL, Iterable images, Iterable videos) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -39,10 +38,9 @@ public class CreateEvent extends AbstractEventOperation { this.endDate = endDate; this.venue = venue; this.isPublic = isPublic; + this.officialWebsiteURL = officialWebsiteURL; this.images = images; this.videos = videos; - this.logoImageURL = logoImageURL; - this.officialWebsiteURL = officialWebsiteURL; } @Override @@ -64,7 +62,7 @@ public class CreateEvent extends AbstractEventOperation { @Override public Event internalApplyTo(RacingEventService toState) { return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic, - getId(), images, videos, logoImageURL, officialWebsiteURL); + getId(), officialWebsiteURL, images, videos); } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java index ebb953c9939..3f40e452ace 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java @@ -19,13 +19,12 @@ public class UpdateEvent extends AbstractEventOperation { private final String eventName; private final String eventDescription; private final URL officialWebsiteURL; - private final URL logoImageURL; private final Iterable images; private final Iterable videos; public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, - String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL logoImageURL, - URL officialWebsiteURL, Iterable images, Iterable videos) { + String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, + Iterable images, Iterable videos) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -35,7 +34,6 @@ public class UpdateEvent extends AbstractEventOperation { this.isPublic = isPublic; this.leaderboardGroupIds = leaderboardGroupIds; this.officialWebsiteURL = officialWebsiteURL; - this.logoImageURL = logoImageURL; this.images = images; this.videos = videos; } @@ -55,7 +53,7 @@ public class UpdateEvent extends AbstractEventOperation { @Override public Void internalApplyTo(RacingEventService toState) { toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic, - leaderboardGroupIds, officialWebsiteURL, logoImageURL, images, videos); + leaderboardGroupIds, officialWebsiteURL, images, videos); return null; } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java index a7df1a2584f..5621e82192a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java @@ -128,4 +128,9 @@ public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serial public void setLocale(Locale locale) { this.locale = locale; } + + @Override + public boolean hasTag(String tagName) { + return tags.contains(tagName); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java index 5616c761950..6f777b7b6be 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java @@ -19,7 +19,8 @@ public interface MediaDescriptor extends Serializable { Iterable getTags(); void setTags(Iterable tags); boolean addTag(String tagName); - boolean removeTag(String tagName); + boolean removeTag(String tagName); + boolean hasTag(String tagName); String getSubtitle(); void setSubtitle(String subtitle); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java index 3e6d6fcd26c..d3fad2bb576 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java @@ -2,6 +2,7 @@ package com.sap.sse.common.media; public interface MediaTagConstants { 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"; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java index bb6b91bfb19..0c9d8fb67b6 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -78,6 +78,10 @@ public abstract class AbstractMediaDTO implements IsSerializable { return tags; } + public boolean hasTag(String tagName) { + return tags.contains(tagName); + } + public void setTags(Iterable tags) { for(String tag: tags) { this.tags.add(tag); From 9decf43909a3bd539b00bcd0c8ae01bcff19532f Mon Sep 17 00:00:00 2001 From: fmittag Date: Sun, 14 Jun 2015 16:19:10 +0200 Subject: [PATCH 074/117] reworked images and videos of event -> removed double maintenance of imageURLs, videoURLs, sponsorImageURLs -> they are now always calculated from images and videos --- .../SailingDashboardsGWT sdm.launch | 2 +- .../impl/DomainObjectFactoryImpl.java | 128 +++---------- .../sap/sailing/domain/base/EventBase.java | 49 +---- .../domain/base/impl/EventBaseImpl.java | 171 ++++++++++-------- .../domain/base/impl/StrippedEventImpl.java | 16 -- .../com/sap/sailing/domain/base/Event.java | 20 -- .../sailing/domain/base/impl/EventImpl.java | 90 --------- .../ui/adminconsole/ImagesListComposite.java | 4 +- .../gwt/ui/shared/media/MediaConstants.java | 3 +- ...estStoringAndLoadingEventsAndRegattas.java | 6 +- .../impl/EventBaseJsonDeserializer.java | 27 ++- .../sse/common/media/MediaTagConstants.java | 1 + 12 files changed, 143 insertions(+), 374 deletions(-) diff --git a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch index aefd1e3ffb6..3df14c0b671 100755 --- a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch +++ b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch @@ -43,5 +43,5 @@ - + diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index b4a99fafea5..0db1e4dae6d 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -185,7 +185,6 @@ import com.sap.sse.common.TimeRange; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.Util; -import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Triple; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; @@ -193,9 +192,6 @@ import com.sap.sse.common.impl.RGBColor; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.media.ImageDescriptor; import com.sap.sse.common.media.ImageDescriptorImpl; -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; @@ -982,7 +978,10 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { try { for (DBObject object : eventCollection.find()) { Event event = loadEvent(object); - migrateImagesAndVideosOfEvent(event); + boolean hasMigratedSomething = loadLegacyImageAndVideoURLs(event, object); + if(hasMigratedSomething) { + new MongoObjectFactoryImpl(database).storeEvent(event); + } result.add(event); } } catch (Exception e) { @@ -1046,7 +1045,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL."); } } - loadLegacyImageAndVideoURLs(result, eventDBObject); BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); if (images != null) { for (Object imageObject : images) { @@ -2134,133 +2132,55 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { return result; } - /** - * Migrates images and videos stored as pure URLs to the new richer media format - * @param event the event to migrate - */ - @SuppressWarnings("deprecation") - private void migrateImagesAndVideosOfEvent(Event event) { - boolean changedAnything = false; - - List newImages = new ArrayList<>(); - for (URL url : event.getImageURLs()) { - if (!hasMedia(event.getImages(), url)) { - ImageDescriptor image = migrateImageURLtoImage(url, event.getStartDate()); - 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); - } - newImages.add(image); - changedAnything = true; - } - } - for (URL url : event.getSponsorImageURLs()) { - if (!hasMedia(event.getImages(), url)) { - ImageDescriptor image = migrateImageURLtoImage(url, event.getStartDate()); - image.addTag(MediaTagConstants.SPONSOR); - newImages.add(image); - changedAnything = true; - } - } - - if (event.getLogoImageURL() != null && !hasMedia(event.getImages(), event.getLogoImageURL())) { - ImageDescriptor image = migrateImageURLtoImage(event.getLogoImageURL(), event.getStartDate()); - image.addTag(MediaTagConstants.LOGO); - newImages.add(image); - changedAnything = true; - } - - List newVideos = new ArrayList(); - for (URL url : event.getVideoURLs()) { - if (!hasMedia(event.getVideos(), url)) { - MimeType mimeType = MediaUtils.detectMimeTypeFromUrl(url.toString()); - VideoDescriptor video = new VideoDescriptorImpl(url, mimeType, event.getStartDate()); - newVideos.add(video); - changedAnything = true; - } - } - - if (changedAnything) { - for (VideoDescriptor newVideo : newVideos) { - event.addVideo(newVideo); - } - for (ImageDescriptor newImage : newImages) { - event.addImage(newImage); - } - new MongoObjectFactoryImpl(database).storeEvent(event); - } - } - /** * Legacy code to support conversion of old image and video URLs * @param event * @param eventDBObject */ - @SuppressWarnings("deprecation") - private void loadLegacyImageAndVideoURLs(Event event, DBObject eventDBObject) { + private boolean loadLegacyImageAndVideoURLs(Event event, DBObject eventDBObject) { + URL logoImageURL = null; + List imageURLs = new ArrayList(); + List sponsorImageURLs = new ArrayList(); + List videoURLs = new ArrayList(); + String logoImageURLAsString = (String) eventDBObject.get(FieldNames.EVENT_LOGO_IMAGE_URL.name()); if (logoImageURLAsString != null) { try { - event.setLogoImageURL(new URL(logoImageURLAsString)); + logoImageURL = new URL(logoImageURLAsString); } catch (MalformedURLException e) { logger.severe("Error parsing logo image URL "+logoImageURLAsString+" for event "+event.getName()+". Ignoring this URL."); } } - BasicDBList imageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); - if (imageURLs != null) { - List urls = new ArrayList<>(); - for (Object imageURL : imageURLs) { + BasicDBList imageURLsJson = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGE_URLS.name()); + if (imageURLsJson != null) { + for (Object imageURL : imageURLsJson) { try { - urls.add(new URL((String) imageURL)); + imageURLs.add(new URL((String) imageURL)); } catch (MalformedURLException e) { logger.severe("Error parsing image URL "+imageURL+" for event "+event.getName()+". Ignoring this image URL."); } } - event.setImageURLs(urls); } - BasicDBList videoURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); - if (videoURLs != null) { - List urls = new ArrayList<>(); - for (Object videoURL : videoURLs) { + BasicDBList videoURLsJson = (BasicDBList) eventDBObject.get(FieldNames.EVENT_VIDEO_URLS.name()); + if (videoURLsJson != null) { + for (Object videoURL : videoURLsJson) { try { - urls.add(new URL((String) videoURL)); + videoURLs.add(new URL((String) videoURL)); } catch (MalformedURLException e) { logger.severe("Error parsing video URL "+videoURL+" for event "+event.getName()+". Ignoring this video URL."); } } - event.setVideoURLs(urls); } - BasicDBList sponsorImageURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); - if (sponsorImageURLs != null) { - List urls = new ArrayList<>(); - for (Object sponsorImageURL : sponsorImageURLs) { + BasicDBList sponsorImageURLsJson = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name()); + if (sponsorImageURLsJson != null) { + for (Object sponsorImageURL : sponsorImageURLsJson) { try { - urls.add(new URL((String) sponsorImageURL)); + sponsorImageURLs.add(new URL((String) sponsorImageURL)); } catch (MalformedURLException e) { logger.severe("Error parsing sponsor image URL "+sponsorImageURL+" for event "+event.getName()+". Ignoring this sponsor image URL."); } } - event.setSponsorImageURLs(urls); } - } - - private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt) { - ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if (imageDimensions != null) { - image.setSize(imageDimensions); - } - return image; - } - - private boolean hasMedia(Iterable media, URL url) { - for (MediaDescriptor mediaEntry : media) { - if (url.equals(mediaEntry.getURL())) { - return true; - } - } - return false; + return event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index 8ca8d0b4c72..42fb9204306 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -1,13 +1,11 @@ package com.sap.sailing.domain.base; import java.net.URL; -import java.util.concurrent.ExecutionException; 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; /** @@ -50,17 +48,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable getImageURLs(); - /** - * @deprecated - * Replaces the {@link #getImageURLs() current contents of the image URL sequence} by the image URLs in - * imageURLs. - * - * @param imageURLs - * if null, the internal sequence of image URLs is cleared but remains valid (non- - * null) - */ - void setImageURLs(Iterable imageURLs); - /** * @deprecated * An event may have zero or more sponsors, each of which usually want to see their logo on the web page. @@ -69,28 +56,12 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable getSponsorImageURLs(); - /** - * @deprecated - * Replaces the {@link #getSponsorImageURLs() current contents of the sponsorship image URL sequence} by the image URLs in - * sponsorImageURLs. - * - * @param sponsorImageURLs - * if null, the internal sequence of sponsorship image URLs is cleared but remains valid (non- - * null) - */ - void setSponsorImageURLs(Iterable sponsorImageURLs); - /** * @deprecated * An optional logo image; may return null. */ URL getLogoImageURL(); - /** - * @deprecated - */ - void setLogoImageURL(URL logoImageURL); - /** * @deprecated * Returns a non-null live but unmodifiable collection of URLs pointing to video resources that can be @@ -100,17 +71,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi */ Iterable getVideoURLs(); - /** - * @deprecated - * Replaces the {@link #getVideoURLs() current contents of the video URL sequence} by the video URLs in - * videoURLs. - * - * @param videoURLs - * if null, the internal sequence of image URLs is cleared but remains valid (non- - * null) - */ - void setVideoURLs(Iterable videoURLs); - /** * @return the URL of the event's official web site, or null if such a site does not exist or its URL * is not known @@ -121,9 +81,8 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi Iterable 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 imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, URL logoImageURL); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index 71a19adb66b..4dad4a4bd59 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -13,9 +13,15 @@ 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.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; @@ -27,10 +33,6 @@ public abstract class EventBaseImpl implements EventBase { private final UUID id; private TimePoint startDate; private TimePoint endDate; - private ConcurrentLinkedQueue imageURLs; - private ConcurrentLinkedQueue videoURLs; - private ConcurrentLinkedQueue sponsorImageURLs; - private URL logoImageURL; private URL officialWebsiteURL; private ConcurrentLinkedQueue images; private ConcurrentLinkedQueue videos; @@ -50,25 +52,12 @@ public abstract class EventBaseImpl implements EventBase { this.endDate = endDate; this.venue = venue; this.isPublic = isPublic; - this.imageURLs = new ConcurrentLinkedQueue(); - this.videoURLs = new ConcurrentLinkedQueue(); - this.sponsorImageURLs = new ConcurrentLinkedQueue(); this.images = new ConcurrentLinkedQueue(); this.videos = new ConcurrentLinkedQueue(); - syncImageAndVideoURLsForBackwardCompatibility(); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); - if (imageURLs == null) { - imageURLs = new ConcurrentLinkedQueue(); - } - if (videoURLs == null) { - videoURLs = new ConcurrentLinkedQueue(); - } - if (sponsorImageURLs == null) { - sponsorImageURLs = new ConcurrentLinkedQueue(); - } if (images == null) { images = new ConcurrentLinkedQueue(); } @@ -144,51 +133,41 @@ public abstract class EventBaseImpl implements EventBase { @Override public Iterable getImageURLs() { - return Collections.unmodifiableCollection(imageURLs); + List result = new ArrayList(); + for (ImageDescriptor image : images) { + if (Util.size(image.getTags()) == 0 || image.hasTag(MediaTagConstants.GALLERY)) { + result.add(image.getURL()); + } + } + return result; } - @Override - public void setImageURLs(Iterable imageURLs) { - this.imageURLs.clear(); - if (imageURLs != null) { - Util.addAll(imageURLs, this.imageURLs); - } - } - @Override public Iterable getVideoURLs() { - return Collections.unmodifiableCollection(videoURLs); - } - - @Override - public void setVideoURLs(Iterable videoURLs) { - this.videoURLs.clear(); - if (videoURLs != null) { - Util.addAll(videoURLs, this.videoURLs); + List result = new ArrayList(); + for(VideoDescriptor video: videos) { + result.add(video.getURL()); } + return result; } @Override public Iterable getSponsorImageURLs() { - return Collections.unmodifiableCollection(sponsorImageURLs); + List result = new ArrayList(); + for(MediaDescriptor media : findMediaWithTag(images, MediaTagConstants.SPONSOR)) { + result.add(media.getURL()); + } + return result; } - @Override - public void setSponsorImageURLs(Iterable 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; + List media = findMediaWithTag(images, MediaTagConstants.LOGO); + if(media.size() > 0) { + result = media.get(0).getURL(); + } + return result; } @Override @@ -210,14 +189,12 @@ public abstract class EventBaseImpl implements EventBase { public void addImage(ImageDescriptor image) { if (!images.contains(image)) { images.add(image); - syncImageURLsFromImagesForBackwardCompatibility(); } } @Override public void removeImage(ImageDescriptor image) { images.remove(image); - syncImageURLsFromImagesForBackwardCompatibility(); } @Override @@ -225,7 +202,6 @@ public abstract class EventBaseImpl implements EventBase { this.images.clear(); if (images != null) { Util.addAll(images, this.images); - syncImageURLsFromImagesForBackwardCompatibility(); } } @@ -238,14 +214,12 @@ public abstract class EventBaseImpl implements EventBase { public void addVideo(VideoDescriptor video) { if (!videos.contains(video)) { videos.add(video); - syncVideoURLsFromVideosForBackwardCompatibility(); } } @Override public void removeVideo(VideoDescriptor video) { videos.remove(video); - syncVideoURLsFromVideosForBackwardCompatibility(); } @Override @@ -253,38 +227,81 @@ public abstract class EventBaseImpl implements EventBase { this.videos.clear(); if (videos != null) { Util.addAll(videos, this.videos); - syncVideoURLsFromVideosForBackwardCompatibility(); } } - private void syncImageURLsFromImagesForBackwardCompatibility() { - List imageURLs = new ArrayList<>(); - List sponsorImageURLs = new ArrayList<>(); - URL logoImageURL = null; - for (ImageDescriptor image : images) { - if (image.hasTag(MediaTagConstants.SPONSOR)) { - sponsorImageURLs.add(image.getURL()); - } else if (image.hasTag(MediaTagConstants.LOGO)) { - logoImageURL = image.getURL(); - } else { - imageURLs.add(image.getURL()); + private List findMediaWithTag(Iterable media, String tagName) { + List result = new ArrayList<>(); + for (T mediaEntry : media) { + if(mediaEntry.hasTag(tagName)) { + result.add(mediaEntry); } } - setImageURLs(imageURLs); - setSponsorImageURLs(sponsorImageURLs); - setLogoImageURL(logoImageURL); + return result; } - private void syncVideoURLsFromVideosForBackwardCompatibility() { - List videoURLs = new ArrayList<>(); - for (VideoDescriptor video : videos) { - videoURLs.add(video.getURL()); + /** Sets and converts all event images and videos from the old URL based format to the new richer format */ + public boolean setMediaURLs(Iterable imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, URL logoImageURL) { + boolean changed = false; + + for (URL url : imageURLs) { + if (!hasMedia(images, url)) { + ImageDescriptor image = migrateImageURLtoImage(url, getStartDate()); + 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; + } } - setVideoURLs(videoURLs); + for (URL url : sponsorImageURLs) { + if (!hasMedia(images, url)) { + ImageDescriptor image = migrateImageURLtoImage(url, getStartDate()); + image.addTag(MediaTagConstants.SPONSOR); + addImage(image); + changed = true; + } + } + + if (logoImageURL != null && !hasMedia(images, logoImageURL)) { + ImageDescriptor image = migrateImageURLtoImage(logoImageURL, getStartDate()); + 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 void syncImageAndVideoURLsForBackwardCompatibility() { - syncImageURLsFromImagesForBackwardCompatibility(); - syncVideoURLsFromVideosForBackwardCompatibility(); + private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt) { + ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if (imageDimensions != null) { + image.setSize(imageDimensions); + } + return image; + } + + private boolean hasMedia(Iterable media, URL url) { + for (MediaDescriptor mediaEntry : media) { + if (url.equals(mediaEntry.getURL())) { + return true; + } + } + return false; } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java index a5b88e9b506..fe683702679 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java @@ -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 leaderboardGroups; - private final Map imageSizes; public StrippedEventImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id, Iterable leaderboardGroups) { @@ -34,20 +28,10 @@ public class StrippedEventImpl extends EventBaseImpl { boolean isPublic, UUID id, Iterable leaderboardGroups) { super(name, startDate, endDate, venue, isPublic, id); this.leaderboardGroups = leaderboardGroups; - this.imageSizes = new HashMap(); } @Override public Iterable 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); - } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java index abbe3dc0023..aef4e907422 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java @@ -1,13 +1,8 @@ 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.ImageDescriptor; -import com.sap.sse.common.media.ImageSize; -import com.sap.sse.common.media.MediaUtils; /** * An event is a group of {@link Regatta regattas} carried out at a common venue within a common time frame. For @@ -51,19 +46,4 @@ public interface Event extends EventBase { * leaderboard groups in leaderboardGroups. */ void setLeaderboardGroups(Iterable 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.

    - * - * Note that exceptions may result should the image be unavailable. If the image URL leads to a document that is not an image, - * null will result. - * - * @deprecated Use {@link MediaUtils#getImageDimensions(URL)} or simply use the dimensions given by {@link ImageDescriptor} - */ - @Deprecated - ImageSize getImageSize(URL imageURL) throws InterruptedException, ExecutionException; - } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java index 08f69d2ea88..e1c9d0c4a74 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java @@ -34,15 +34,11 @@ 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 regattas; private ConcurrentLinkedQueue leaderboardGroups; - private transient ConcurrentHashMap> 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 +50,6 @@ public class EventImpl extends EventBaseImpl implements Event { super(name, startDate, endDate, venue, isPublic, id); this.regattas = new HashSet(); this.leaderboardGroups = new ConcurrentLinkedQueue<>(); - this.imageSizeFetchers = new ConcurrentHashMap<>(); - this.executor = Executors.newCachedThreadPool(); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { @@ -63,8 +57,6 @@ public class EventImpl extends EventBaseImpl implements Event { if (leaderboardGroups == null) { leaderboardGroups = new ConcurrentLinkedQueue<>(); } - this.imageSizeFetchers = new ConcurrentHashMap<>(); - this.executor = Executors.newCachedThreadPool(); } @Override @@ -106,86 +98,4 @@ public class EventImpl extends EventBaseImpl implements Event { public boolean removeLeaderboardGroup(LeaderboardGroup leaderboardGroup) { return leaderboardGroups.remove(leaderboardGroup); } - - private Future getOrCreateImageSizeCalculator(final URL imageURL) { - Future imageSizeFetcher = imageSizeFetchers.get(imageURL); - if (imageSizeFetcher == null) { - imageSizeFetcher = executor.submit(new Callable() { - @Override - public ImageSize call() throws IOException { - ImageSize result = null; - ImageInputStream in = null; - try { - URLConnection conn = imageURL.openConnection(); - in = ImageIO.createImageInputStream(conn.getInputStream()); - final Iterator 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 imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL); - return imageSizeCalculator.get(); - } - - private void refreshImageSizeFetcher(URL imageURL) { - if (imageURL != null) { - removeImageSizeFetcher(imageURL); - getOrCreateImageSizeCalculator(imageURL); - } - } - - private void removeImageSizeFetcher(URL imageURL) { - if (imageURL != null) { - imageSizeFetchers.remove(imageURL); - } - } - - @Override - public void setImageURLs(Iterable imageURLs) { - super.setImageURLs(imageURLs); - if (imageURLs != null) { - for (URL imageURL : imageURLs) { - refreshImageSizeFetcher(imageURL); - } - } - } - - @Override - public void setSponsorImageURLs(Iterable sponsorImageURLs) { - super.setSponsorImageURLs(sponsorImageURLs); - if (sponsorImageURLs != null) { - for (URL imageURL : sponsorImageURLs) { - refreshImageSizeFetcher(imageURL); - } - } - } - - @Override - public void setLogoImageURL(URL logoImageURL) { - super.setLogoImageURL(logoImageURL); - refreshImageSizeFetcher(logoImageURL); - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index c4c7a0087aa..19c34d9bc26 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -75,11 +75,11 @@ public class ImagesListComposite extends Composite { imagesControlsPanel.setSpacing(5); panel.add(imagesControlsPanel); - Button addPhotoBtn = new Button("Add photo"); + Button addPhotoBtn = new Button("Add gallery photo"); addPhotoBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(null); + openCreateImageDialog(MediaTagConstants.GALLERY); } }); imagesControlsPanel.add(addPhotoBtn); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java index cb7c5aecdbc..402fb961100 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java @@ -10,7 +10,8 @@ import com.sap.sse.common.media.MimeType; public final class MediaConstants { - public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER, MediaTagConstants.SPONSOR, MediaTagConstants.LOGO }); + public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.STAGE, MediaTagConstants.TEASER, + MediaTagConstants.SPONSOR, MediaTagConstants.LOGO, MediaTagConstants.GALLERY }); public static final List videoTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.LIVESTREAM, MediaTagConstants.HIGHLIGHT,MediaTagConstants.FEATURED }); public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4)); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index b8a0de0489c..1b3b874b812 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -92,6 +92,7 @@ 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; @@ -340,11 +341,12 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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("Sponsor"); + image2.addTag(MediaTagConstants.SPONSOR); VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, MimeType.mp4, createdAt); event.addVideo(video1); @@ -354,9 +356,9 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest 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.getVideos())); assertEquals(1, Util.size(loadedEvent.getVideoURLs())); } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 0c17a99091b..21c413a0423 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -22,12 +22,10 @@ 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.Util.Pair; 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.MediaUtils; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoDescriptor; import com.sap.sse.common.media.VideoDescriptorImpl; @@ -99,31 +97,36 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } private void readImageAndVideoURLsFromLegacyServer(JSONObject eventJson, StrippedEventImpl event) throws JsonDeserializationException { + URL logoImageURL = null; + List imageURLs = new ArrayList(); + List sponsorImageURLs = new ArrayList(); + List videoURLs = new ArrayList(); + String logoImageURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_LOGO_IMAGE_URL); if (logoImageURLAsString != null) { try { - event.setLogoImageURL(new URL(logoImageURLAsString)); + logoImageURL = new URL(logoImageURLAsString); } catch (MalformedURLException e) { throw new JsonDeserializationException("Error deserializing logo image URL for event "+event.getName(), e); } } if (eventJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URLS) != null) { try { - event.setImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, 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 "+event.getName(), e); } } if (eventJson.get(EventBaseJsonSerializer.FIELD_VIDEO_URLS) != null) { try { - event.setVideoURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, 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 "+event.getName(), e); } } if (eventJson.get(EventBaseJsonSerializer.FIELD_SPONSOR_IMAGE_URLS) != null) { try { - event.setSponsorImageURLs(getURLsFromStrings(Helpers.getNestedArraySafe(eventJson, 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 "+event.getName(), e); } @@ -145,6 +148,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } } } + event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL); } private ImageDescriptor loadImage(JSONObject imageJson) { @@ -214,16 +218,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { return video; } - private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt, ImageSize size) { - ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if (imageDimensions != null) { - image.setSize(imageDimensions); - } - return image; - } - - private Iterable getURLsFromStrings(JSONArray strings) throws MalformedURLException { + private List getURLsFromStrings(JSONArray strings) throws MalformedURLException { List result = new ArrayList(); if (strings != null) { for (Object string : strings) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java index d3fad2bb576..0e1c1038685 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java @@ -1,6 +1,7 @@ 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"; From 706c882e47138cc214e6a4f0ffc4ccae5b4fe56d Mon Sep 17 00:00:00 2001 From: fmittag Date: Sun, 14 Jun 2015 16:55:33 +0200 Subject: [PATCH 075/117] improved using already known image sizes in case of migration of imageURLs to new image format --- .../impl/DomainObjectFactoryImpl.java | 3 ++- .../sap/sailing/domain/base/EventBase.java | 4 ++- .../domain/base/impl/EventBaseImpl.java | 27 ++++++++++++------- .../impl/EventBaseJsonDeserializer.java | 2 +- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 0db1e4dae6d..d7dd8571709 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -5,6 +5,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -2181,6 +2182,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } } } - return event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL); + return event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL, Collections.emptyMap()); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index 42fb9204306..36830a08816 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -1,11 +1,13 @@ package com.sap.sailing.domain.base; import java.net.URL; +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; /** @@ -84,5 +86,5 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi /** * Sets and converts all event images and videos from the old URL based format to the new richer format * */ - boolean setMediaURLs(Iterable imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, URL logoImageURL); + boolean setMediaURLs(Iterable imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, URL logoImageURL, Map imageSizes); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index 4dad4a4bd59..a4b7b2ccd60 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -6,6 +6,7 @@ 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; @@ -16,6 +17,7 @@ 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; @@ -240,13 +242,16 @@ public abstract class EventBaseImpl implements EventBase { 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 imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, URL logoImageURL) { + /** + * Sets and converts all event images and videos from the old URL based format to the new richer format + */ + public boolean setMediaURLs(Iterable imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, + URL logoImageURL, Map imageSizes) { boolean changed = false; for (URL url : imageURLs) { if (!hasMedia(images, url)) { - ImageDescriptor image = migrateImageURLtoImage(url, getStartDate()); + ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url)); String urlAsString = url.toString(); if (urlAsString.toLowerCase().indexOf("stage") > 0) { image.addTag(MediaTagConstants.STAGE); @@ -261,7 +266,7 @@ public abstract class EventBaseImpl implements EventBase { } for (URL url : sponsorImageURLs) { if (!hasMedia(images, url)) { - ImageDescriptor image = migrateImageURLtoImage(url, getStartDate()); + ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url)); image.addTag(MediaTagConstants.SPONSOR); addImage(image); changed = true; @@ -269,7 +274,7 @@ public abstract class EventBaseImpl implements EventBase { } if (logoImageURL != null && !hasMedia(images, logoImageURL)) { - ImageDescriptor image = migrateImageURLtoImage(logoImageURL, getStartDate()); + ImageDescriptor image = migrateImageURLtoImage(logoImageURL, getStartDate(), imageSizes.get(logoImageURL)); image.addTag(MediaTagConstants.LOGO); addImage(image); changed = true; @@ -287,11 +292,15 @@ public abstract class EventBaseImpl implements EventBase { return changed; } - private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt) { + private ImageDescriptor migrateImageURLtoImage(URL url, TimePoint createdAt, ImageSize imageSize) { ImageDescriptorImpl image = new ImageDescriptorImpl(url, createdAt); - Pair imageDimensions = MediaUtils.getImageDimensions(url); - if (imageDimensions != null) { - image.setSize(imageDimensions); + if (imageSize != null) { + image.setSize(imageSize.getWidth(), imageSize.getHeight()); + } else { + Pair imageDimensions = MediaUtils.getImageDimensions(url); + if (imageDimensions != null) { + image.setSize(imageDimensions); + } } return image; } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 21c413a0423..f9b9028a053 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -148,7 +148,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { } } } - event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL); + event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL, imageSizes); } private ImageDescriptor loadImage(JSONObject imageJson) { From 427b1a22633c6250752d9440b926da62d0095f44 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sun, 14 Jun 2015 17:32:50 +0200 Subject: [PATCH 076/117] replace usage of getLogoImageURL with usage of new Image descriptor for logos --- .../domain/base/impl/EventBaseImpl.java | 36 +++++++++++++++++-- .../event/partials/header/EventHeader.java | 2 +- .../partials/header/SeriesHeader.java | 2 +- .../sailing/gwt/server/HomeServiceImpl.java | 24 +++++++++++-- .../gwt/ui/shared/eventview/EventViewDTO.java | 11 +++--- .../shared/fakeseries/EventSeriesViewDTO.java | 11 +++--- .../com/sap/sse/common/media/WithMedia.java | 7 ++++ 7 files changed, 76 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index a4b7b2ccd60..ee82308ceb9 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -165,9 +165,9 @@ public abstract class EventBaseImpl implements EventBase { @Override public URL getLogoImageURL() { URL result = null; - List media = findMediaWithTag(images, MediaTagConstants.LOGO); - if(media.size() > 0) { - result = media.get(0).getURL(); + ImageDescriptor media = findImageWithTag(MediaTagConstants.LOGO); + if(media != null) { + result = media.getURL(); } return result; } @@ -232,6 +232,36 @@ public abstract class EventBaseImpl implements EventBase { } } + @Override + public ImageDescriptor findImageWithTag(String tagName) { + ImageDescriptor result = null; + List mediaWithTag = findMediaWithTag(images, tagName); + if(mediaWithTag.size() > 0) { + result = mediaWithTag.get(0); + } + return result; + } + + @Override + public VideoDescriptor findVideoWithTag(String tagName) { + VideoDescriptor result = null; + List mediaWithTag = findMediaWithTag(videos, tagName); + if(mediaWithTag.size() > 0) { + result = mediaWithTag.get(0); + } + return result; + } + + @Override + public List findImagesWithTag(String tagName) { + return findMediaWithTag(images, tagName); + } + + @Override + public List findVideosWithTag(String tagName) { + return findMediaWithTag(videos, tagName); + } + private List findMediaWithTag(Iterable media, String tagName) { List result = new ArrayList<>(); for (T mediaEntry : media) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java index 88863dccfa5..99bfb959893 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java @@ -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()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/fakeseries/partials/header/SeriesHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/fakeseries/partials/header/SeriesHeader.java index 75454a9f3df..8c8eae244e7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/fakeseries/partials/header/SeriesHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/fakeseries/partials/header/SeriesHeader.java @@ -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()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index c5b0d347f11..70b00cfcfef 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -55,8 +55,10 @@ 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.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; /** @@ -273,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)); @@ -365,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); @@ -521,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 tags = new ArrayList(); + for(String tag: image.getTags()) { + tags.add(tag); + } + result.setTags(tags); + return result; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java index af436fc3559..55aad746141 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java @@ -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) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/fakeseries/EventSeriesViewDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/fakeseries/EventSeriesViewDTO.java index eeb8a90b13c..b4166c35045 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/fakeseries/EventSeriesViewDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/fakeseries/EventSeriesViewDTO.java @@ -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 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() { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java index 6887f3eb8ae..71b0328c115 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java @@ -1,4 +1,11 @@ package com.sap.sse.common.media; +import java.util.List; + public interface WithMedia extends WithImages, WithVideos { + ImageDescriptor findImageWithTag(String tagName); + List findImagesWithTag(String tagName); + + VideoDescriptor findVideoWithTag(String tagName); + List findVideosWithTag(String tagName); } From 5ceacab61adf66f9c838038954ee1dc508413f77 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sun, 14 Jun 2015 17:45:10 +0200 Subject: [PATCH 077/117] removed some unused imports --- .../sap/sailing/domain/base/impl/EventImpl.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java index e1c9d0c4a74..6921517df90 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java @@ -2,35 +2,18 @@ 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; From 9e3dd6a31c2361f626fe75fc799ba775aea69399 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 08:37:17 +0200 Subject: [PATCH 078/117] Removed dummy news provider --- .../src/com/sap/sailing/news/Activator.java | 1 - .../impl/SimpleDemoEventNewsProvider.java | 67 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java index 57ca7be7ba3..fb112a1ace9 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/Activator.java @@ -19,7 +19,6 @@ public class Activator implements BundleActivator { context.registerService(EventNewsService.class, newsService, null); context.registerService(EventNewsProviderRegistry.class, providerRegistry, null); -// providerRegistry.registerNewsProvider(new SimpleDemoEventNewsProvider()); providerRegistry.registerNewsProvider(new JsonEventNewsProvider()); providerRegistry.registerNewsProvider(new LeaderboardUpdateEventNewsProvider()); logger.info("EventNews Service registered."); diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java deleted file mode 100644 index 8331877fdb3..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/SimpleDemoEventNewsProvider.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.sap.sailing.news.impl; - -import java.util.Collection; -import java.util.Date; -import java.util.LinkedList; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; - -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.news.EventNewsItem; -import com.sap.sailing.news.EventNewsProvider; -import com.sap.sailing.news.LimitedQueue; - -public class SimpleDemoEventNewsProvider implements EventNewsProvider { - private final LinkedList newsQueue; - - private final Timer timer = new Timer(); - - public SimpleDemoEventNewsProvider() { - newsQueue = new LimitedQueue<>(10); - - final UUID eventId = UUID.fromString("406cffc2-b491-4f7e-b78e-a21abd97006a"); -// final UUID eventId = UUID.fromString("406cffc2-b491-4f7e-b78e-a21abd97006a"); - - timer.scheduleAtFixedRate(new TimerTask() { - int counter=1; - @Override - public void run() { - newsQueue.add(new InfoEventNewsItem(eventId, "Test Entry " + counter, "Content for Test Entry "+counter, new Date(), null)); - counter++; - } - }, 5_000, 30_000); - } - - protected void finalize() throws Throwable { - timer.cancel(); - }; - - @Override - public Collection getNews(Event event) { -// Iterable leaderboardGroups = event.getLeaderboardGroups(); -// for(LeaderboardGroup leaderboardGroup: leaderboardGroups) { -// for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) { -// TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification(); -// } -// } - - return newsQueue.subList(0, newsQueue.size()); - } - - @Override - public Collection getNews(Event event, Date startingFrom) { - return newsQueue.subList(0, newsQueue.size()); - } - - @Override - public boolean hasNews(Event event, Date startingFrom) { - return newsQueue.size() > 0; - } - - @Override - public boolean hasNews(Event event) { - return newsQueue.size() > 0; - } - -} From 5344bffa4ea5f2ba93ce3a99f4641d59566e12d3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 08:45:37 +0200 Subject: [PATCH 079/117] I18n of leaderboard results news box message --- .../java/com/sap/sailing/gwt/ui/client/StringMessages.java | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages_de.properties | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages_ru.properties | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages_zh.properties | 3 ++- .../gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java | 3 ++- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 195f2be1edd..e0aa620808c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1310,4 +1310,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); String sailorInfo(); String sailorInfoLongText(); + String resultsUpdate(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 53f709a77d4..8470de79887 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1259,6 +1259,7 @@ raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now latestNews=Latest News +resultsUpdate=Result update showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 90676d4a43b..b5a93034d69 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1249,6 +1249,7 @@ raceIsPostponed=Verschoben startingInMinutes=Startet in {0,number} min startingInMinutes[none]=Startet gleich latestNews=Neuigkeiten +resultsUpdate=Neue Ergebnisse showCompetitorTimeOnTimeFactorColumn=Zeit-für-Zeit Faktor showCompetitorTimeOnDistanceAllowanceColumn=Zeit-für-Distanz Gutschrift rankingMetric=Wertung/Handicap diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index ec3037c882b..30685f82d4c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1197,6 +1197,7 @@ raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now latestNews=Последние Новости +resultsUpdate=Результаты обновление showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index eba84036e3f..758ba903dcf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -1249,7 +1249,8 @@ raceIsCanceled=Canceled raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now -latestNews=最新消息 +latestNews=最新消息 +resultsUpdate=結果更新 showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java index 6694525b716..03ed23fafc1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; public class LeaderboardNewsEntryDTO extends NewsEntryDTO { @@ -34,7 +35,7 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { public String getMessage() { switch (type) { case RESULTS_UPDATE: - return "Result update"; + return StringMessages.INSTANCE.resultsUpdate(); } return ""; } From 6fa791d10c9d03b3792155ee74a6f226e549bf0f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 08:47:46 +0200 Subject: [PATCH 080/117] Removed demo content for the news box --- .../event/GetEventOverviewStageAction.java | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 0ab9f043c59..1f287708628 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -141,35 +141,5 @@ public class GetEventOverviewStageAction implements Action Date: Mon, 15 Jun 2015 09:45:04 +0200 Subject: [PATCH 081/117] Implemented new parial CountdownTimer --- .../event/partials/countdown/Countdown.gss | 53 +++---------------- .../event/partials/countdown/Countdown.java | 3 +- .../countdown/CountdownResources.java | 12 +---- .../partials/countdown/CountdownTicker.ui.xml | 14 ----- .../countdownTimer/CountdownTimer.gss | 41 ++++++++++++++ .../CountdownTimer.java} | 13 ++--- .../countdownTimer/CountdownTimer.ui.xml | 16 ++++++ .../CountdownTimerResources.java | 25 +++++++++ 8 files changed, 100 insertions(+), 77 deletions(-) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.gss rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/{countdown/CountdownTicker.java => countdownTimer/CountdownTimer.java} (84%) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimerResources.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss index 8569a5ccab4..fb68ecc06ca 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss @@ -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; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.java index 02c1753f7d5..4f534a531f5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.java @@ -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); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownResources.java index 91aafa381fe..8ddafac0f0c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownResources.java @@ -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(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.ui.xml deleted file mode 100644 index 6caed0e8386..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.ui.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - -

    -
    -
    -
    -
    -
    -
    -
    - - \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.gss new file mode 100644 index 00000000000..f5d17429c39 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.gss @@ -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; +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.java similarity index 84% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.java index 5680938e0b8..87701774a8b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/CountdownTicker.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.java @@ -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 { + interface CountdownTickerUiBinder extends UiBinder { } @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()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.ui.xml new file mode 100644 index 00000000000..eca537d5e0a --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimer.ui.xml @@ -0,0 +1,16 @@ + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimerResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimerResources.java new file mode 100644 index 00000000000..bc5c3020998 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdownTimer/CountdownTimerResources.java @@ -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(); + } +} From 2b6ab8c64ebe920b5a7f154b4cce6064a811d478 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 10:39:45 +0200 Subject: [PATCH 082/117] Adaption of spacermargin styles for event overview tab --- .../multiregatta/tabs/MultiregattaOverviewTabView.ui.xml | 9 ++------- .../event/regatta/tabs/RegattaOverviewTabView.ui.xml | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.ui.xml index e959e50b54a..7e73a5c2923 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.ui.xml @@ -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"> - - .space-top { - margin-top: 2em; - } -
    - +
    - +
    \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.ui.xml index 2d12ca41cf3..a2d8a30b0f2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.ui.xml @@ -7,7 +7,7 @@
    - +
    From 3b6986c288830f94d6db3db8f3b309ab28991edf Mon Sep 17 00:00:00 2001 From: Jens Rommel Date: Mon, 15 Jun 2015 11:56:15 +0200 Subject: [PATCH 083/117] Fixed number conversion issue. --- .../persistence/impl/DomainObjectFactoryImpl.java | 10 +++++----- .../impl/EventBaseJsonDeserializer.java | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index d7dd8571709..2a1101b145b 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -2064,8 +2064,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { String copyright = (String) dbObject.get(FieldNames.IMAGE_COPYRIGHT.name()); String localeRaw = (String) dbObject.get(FieldNames.IMAGE_LOCALE.name()); Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; - Integer imageWidth = (Integer) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); - Integer imageHeight = (Integer) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); + Number imageWidth = (Number) dbObject.get(FieldNames.IMAGE_WIDTH_IN_PX.name()); + Number imageHeight = (Number) dbObject.get(FieldNames.IMAGE_HEIGHT_IN_PX.name()); TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.IMAGE_CREATEDATDATE); BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.IMAGE_TAGS.name()); List imageTags = new ArrayList(); @@ -2081,7 +2081,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { image.setLocale(locale); image.setTags(imageTags); if (imageWidth != null && imageHeight != null) { - image.setSize(imageWidth, imageHeight); + image.setSize(imageWidth.intValue(), imageHeight.intValue()); } } return image; @@ -2100,7 +2100,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; TimePoint createdAtDate = loadTimePoint(dbObject, FieldNames.VIDEO_CREATEDATDATE); BasicDBList tags = (BasicDBList) dbObject.get(FieldNames.VIDEO_TAGS.name()); - Integer lengthInSeconds = (Integer) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); + Number lengthInSeconds = (Number) dbObject.get(FieldNames.VIDEO_LENGTH_IN_SECONDS.name()); URL thumbnailURL = loadURL(dbObject, FieldNames.VIDEO_THUMBNAIL_URL); List videoTags = new ArrayList(); if (tags != null) { @@ -2114,7 +2114,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { video.setSubtitle(subtitle); video.setLocale(locale); video.setTags(videoTags); - video.setLengthInSeconds(lengthInSeconds); + video.setLengthInSeconds(lengthInSeconds == null ? null : lengthInSeconds.intValue()); video.setThumbnailURL(thumbnailURL); } return video; diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index f9b9028a053..a49790f7da3 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -160,10 +160,10 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { String copyright = (String) imageJson.get(EventBaseJsonSerializer.FIELD_COPYRIGHT); String localeRaw = (String) imageJson.get(EventBaseJsonSerializer.FIELD_LOCALE); Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; - Integer imageWidth = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH_IN_PX); - Integer imageHeight = (Integer) imageJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT_IN_PX); - Long createdAtDateInMs = (Long) imageJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); - TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs) : 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 imageTags = new ArrayList(); if (tags != null) { @@ -178,7 +178,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { image.setSubtitle(subtitle); image.setTags(imageTags); if (imageWidth != null && imageHeight != null) { - image.setSize(imageWidth, imageHeight); + image.setSize(imageWidth.intValue(), imageHeight.intValue()); } } return image; @@ -195,8 +195,8 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; Object mimeTypeRaw = videoJson.get(EventBaseJsonSerializer.FIELD_MIMETYPE); MimeType mimeType = mimeTypeRaw == null ? null : MimeType.valueOf((String) mimeTypeRaw); - Long createdAtDateInMs = (Long) videoJson.get(EventBaseJsonSerializer.FIELD_CREATEDATDATE); - TimePoint createdAtDate = createdAtDateInMs != null ? new MillisecondsTimePoint(createdAtDateInMs) : null; + 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); From 308bee5174b6542bd012e2faa9469509447dac54 Mon Sep 17 00:00:00 2001 From: Jens Rommel Date: Mon, 15 Jun 2015 12:51:46 +0200 Subject: [PATCH 084/117] Fixed backward-compatibility bug with image URL migration. --- .../src/com/sap/sailing/domain/base/impl/EventBaseImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index ee82308ceb9..359b0818df1 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -137,7 +137,7 @@ public abstract class EventBaseImpl implements EventBase { public Iterable getImageURLs() { List result = new ArrayList(); for (ImageDescriptor image : images) { - if (Util.size(image.getTags()) == 0 || image.hasTag(MediaTagConstants.GALLERY)) { + if (!image.hasTag(MediaTagConstants.SPONSOR) && !image.hasTag(MediaTagConstants.LOGO)) { result.add(image.getURL()); } } From 86e0b5352f295aa75a4f0284da7d73d97108426b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 14:08:56 +0200 Subject: [PATCH 085/117] Fixed typo --- .../com/sap/sailing/news/impl/JsonEventNewsProvider.java | 2 +- .../src/com/sap/sailing/news/impl/news.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java index ed71edcc7e6..81e4a78e96f 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java @@ -60,7 +60,7 @@ public class JsonEventNewsProvider implements EventNewsProvider { JSONObject eventAsJson = (JSONObject) eventAsObject; String eventIdAsString = (String) eventAsJson.get("event"); Number timestamp = (Number) eventAsJson.get("timestamp"); - String title = (String) eventAsJson.get("tite"); + String title = (String) eventAsJson.get("title"); String message = (String) eventAsJson.get("message"); String newsURL = (String) eventAsJson.get("url"); UUID eventId = UUID.fromString(eventIdAsString); diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json index 6d7906a9e6b..515c7813548 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json @@ -2,27 +2,27 @@ { "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", "timestamp": 1434030000000, - "tite": "Test KW2015 1", + "title": "Test KW2015 1", "message": "Test KW2015 1 content", "url": "http://www.sapsailing.com/" }, { "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", "timestamp": 1434050000000, - "tite": "Test KW2015 2", + "title": "Test KW2015 2", "message": "Test KW2015 2 content" }, { "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", "timestamp": 1434030000000, - "tite": "Test local 1", + "title": "Test local 1", "message": "Test local 1 content", "url": "http://www.sapsailing.com/" }, { "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", "timestamp": 1434050000000, - "tite": "Test local 2", + "title": "Test local 2", "message": "Test local 2 content" } ] \ No newline at end of file From 49f4ba9f66b3b49ace57d7ca76fc095ec2b60958 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 14:50:31 +0200 Subject: [PATCH 086/117] Implemented locale dependent news enty messages/titles --- .../event/GetEventOverviewStageAction.java | 2 +- .../dispatch/news/InfoNewsEntryDTO.java | 8 +++-- .../sailing/news/impl/InfoEventNewsItem.java | 25 ++++++++++++--- .../news/impl/JsonEventNewsProvider.java | 24 +++++++++++++- .../src/com/sap/sailing/news/impl/news.json | 32 +++++++++++++------ 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 1f287708628..74182ef43d0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -135,7 +135,7 @@ public class GetEventOverviewStageAction implements Action titles; + private Map messages; + public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category, - URL relatedItemLink) { + URL relatedItemLink, Map titles, Map messages) { super(eventId, title, message, createdAtDate, category, relatedItemLink); + this.titles = titles; + this.messages = messages; } - - public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category) { - super(eventId, title, message, createdAtDate, category); + + public String getTitle(Locale locale) { + if(titles.containsKey(locale)) { + return titles.get(locale); + } + return super.getTitle(); + } + + public String getMessage(Locale locale) { + if(messages.containsKey(locale)) { + return messages.get(locale); + } + return super.getMessage(); } } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java index 81e4a78e96f..71ccf2c1b17 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java @@ -6,9 +6,15 @@ import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.Collection; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -61,10 +67,12 @@ public class JsonEventNewsProvider implements EventNewsProvider { String eventIdAsString = (String) eventAsJson.get("event"); Number timestamp = (Number) eventAsJson.get("timestamp"); String title = (String) eventAsJson.get("title"); + Map titles = readI18nText(eventAsJson, "titles"); String message = (String) eventAsJson.get("message"); + Map messages = readI18nText(eventAsJson, "messages"); String newsURL = (String) eventAsJson.get("url"); UUID eventId = UUID.fromString(eventIdAsString); - InfoEventNewsItem newsItem = new InfoEventNewsItem(eventId, title, message, new Date(timestamp.longValue()), null, newsURL == null ? null : new URL(newsURL)); + InfoEventNewsItem newsItem = new InfoEventNewsItem(eventId, title, message, new Date(timestamp.longValue()), null, newsURL == null ? null : new URL(newsURL), titles, messages); newNews.add(newsItem); } news = newNews; @@ -78,6 +86,20 @@ public class JsonEventNewsProvider implements EventNewsProvider { } } + private Map readI18nText(JSONObject eventAsJson, String field) { + Object object = eventAsJson.get(field); + if(object == null) { + return Collections.emptyMap(); + } + JSONObject texts = (JSONObject) object; + Set> entrySet = texts.entrySet(); + Map result = new HashMap<>(); + for (Entry entry : entrySet) { + result.put(Locale.forLanguageTag((String) entry.getKey()), (String) entry.getValue()); + } + return result; + } + @Override public Collection getNews(Event event) { if(nextUpdate < System.currentTimeMillis()) { diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json index 515c7813548..958d98272c3 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json @@ -2,27 +2,39 @@ { "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", "timestamp": 1434030000000, - "title": "Test KW2015 1", - "message": "Test KW2015 1 content", - "url": "http://www.sapsailing.com/" + "title": "Winner's party", + "titles": { + "de": "Siegerfeier", + } + "message": "... is starting at 9pm", + "messages": { + "de": "... beginnt um 21:00 Uhr" + } }, { "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", "timestamp": 1434050000000, "title": "Test KW2015 2", "message": "Test KW2015 2 content" + "url": "http://www.sapsailing.com/", }, { - "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", + "event": "d7887678-6ace-4b67-b513-1d6478020568", "timestamp": 1434030000000, - "title": "Test local 1", - "message": "Test local 1 content", - "url": "http://www.sapsailing.com/" + "title": "Winner's party", + "titles": { + "de": "Siegerfeier", + } + "message": "... is starting at 9pm", + "messages": { + "de": "... beginnt um 21:00 Uhr" + } }, { - "event": "adbd871b-b9b3-4e18-bd79-d560e7b87c53", + "event": "d7887678-6ace-4b67-b513-1d6478020568", "timestamp": 1434050000000, - "title": "Test local 2", - "message": "Test local 2 content" + "title": "Test KW2015 2", + "message": "Test KW2015 2 content" + "url": "http://www.sapsailing.com/", } ] \ No newline at end of file From a4e4363681f1c77527dad8f8ea823f341b03a38f Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 15 Jun 2015 15:06:58 +0200 Subject: [PATCH 087/117] added com.sap.sailing.news bundle to product --- java/com.sap.sailing.feature.p2build/raceanalysis.product | 1 + java/com.sap.sailing.feature/feature.xml | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/java/com.sap.sailing.feature.p2build/raceanalysis.product b/java/com.sap.sailing.feature.p2build/raceanalysis.product index 520588e980e..3680642bd97 100755 --- a/java/com.sap.sailing.feature.p2build/raceanalysis.product +++ b/java/com.sap.sailing.feature.p2build/raceanalysis.product @@ -47,6 +47,7 @@ + diff --git a/java/com.sap.sailing.feature/feature.xml b/java/com.sap.sailing.feature/feature.xml index 63b9d34a6fa..0a8d1d1bb38 100755 --- a/java/com.sap.sailing.feature/feature.xml +++ b/java/com.sap.sailing.feature/feature.xml @@ -54,6 +54,13 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al version="0.0.0" unpack="false"/> + + Date: Mon, 15 Jun 2015 15:00:15 +0200 Subject: [PATCH 088/117] Updated model for race competitor news --- .../news/RaceCompetitorNewsEntryDTO.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java index 5cd0b4add00..04e56c743fe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java @@ -2,24 +2,22 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; import java.util.Date; -import com.sap.sailing.domain.common.dto.CompetitorDTO; - public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { public enum Type { - WINNER, CRASH + WINNER } - private CompetitorDTO competitor; + private String competitorName; private Type type; @SuppressWarnings("unused") private RaceCompetitorNewsEntryDTO() { } - public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, CompetitorDTO competitor, Type type) { + public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, String competitorName, Type type) { super(regattaName, trackedRaceName, raceTitle, boatClass, timestamp); - this.competitor = competitor; + this.competitorName = competitorName; this.type = type; } @@ -28,10 +26,8 @@ public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { // TODO I18n... switch (type) { case WINNER: - return competitor.getName() + " won the race"; - case CRASH: - return competitor.getName() + " crashed"; + return competitorName + " won the race"; } - return competitor.getName(); + return ""; } } From 83d8ef8a047cf9b391d1f5ffa4bae05356a833ee Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 15:05:36 +0200 Subject: [PATCH 089/117] I18n for race competitor news message --- .../java/com/sap/sailing/gwt/ui/client/StringMessages.java | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 1 + .../sap/sailing/gwt/ui/client/StringMessages_de.properties | 1 + .../sap/sailing/gwt/ui/client/StringMessages_ru.properties | 1 + .../sap/sailing/gwt/ui/client/StringMessages_zh.properties | 1 + .../ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java | 5 +++-- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 48302a81962..6a6eb4c65c2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1312,4 +1312,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String sailorInfo(); String sailorInfoLongText(); String resultsUpdate(); + String competitorWonRace(String competitorName); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index e89ac21e27e..ac60f671f59 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1261,6 +1261,7 @@ startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now latestNews=Latest News resultsUpdate=Result update +competitorWonRace={0} won race showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 55d2257a7e5..7eaac84e13c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1251,6 +1251,7 @@ startingInMinutes=Startet in {0,number} min startingInMinutes[none]=Startet gleich latestNews=Neuigkeiten resultsUpdate=Neue Ergebnisse +competitorWonRace={0} gewann die Wettfahrt showCompetitorTimeOnTimeFactorColumn=Zeit-für-Zeit Faktor showCompetitorTimeOnDistanceAllowanceColumn=Zeit-für-Distanz Gutschrift rankingMetric=Wertung/Handicap diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index ed057f7f152..d72df5494e2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1199,6 +1199,7 @@ startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now latestNews=Последние Новости resultsUpdate=Результаты обновление +competitorWonRace={0} won race showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 758ba903dcf..5258afc357f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -1251,6 +1251,7 @@ startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now latestNews=最新消息 resultsUpdate=結果更新 +competitorWonRace={0} won race showCompetitorTimeOnTimeFactorColumn=Time on Time Factor showCompetitorTimeOnDistanceAllowanceColumn=Time on Distance Allowance rankingMetric=Ranking diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java index 04e56c743fe..77d26641128 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java @@ -2,6 +2,8 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; import java.util.Date; +import com.sap.sailing.gwt.ui.client.StringMessages; + public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { public enum Type { @@ -23,10 +25,9 @@ public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { @Override public String getMessage() { - // TODO I18n... switch (type) { case WINNER: - return competitorName + " won the race"; + return StringMessages.INSTANCE.competitorWonRace(competitorName); } return ""; } From 11a91c88aeee551af51b3669c78a67cbf0c0ed1b Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 15 Jun 2015 15:30:08 +0200 Subject: [PATCH 090/117] set the static URL for the json based news provider to static.sapsailing.com/events_news/news.json --- .../news/impl/JsonEventNewsProvider.java | 17 +++++--- .../src/com/sap/sailing/news/impl/news.json | 40 ------------------- 2 files changed, 12 insertions(+), 45 deletions(-) delete mode 100644 java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java index 71ccf2c1b17..78c4c241f9a 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/JsonEventNewsProvider.java @@ -3,6 +3,7 @@ package com.sap.sailing.news.impl; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Collection; @@ -34,12 +35,18 @@ public class JsonEventNewsProvider implements EventNewsProvider { private static final Logger logger = Logger.getLogger(JsonEventNewsProvider.class.getName()); - // TODO fmittag: use correct URL - private static final URL url = JsonEventNewsProvider.class.getResource("news.json"); + private static URL staticNewsURL; private List news = new LinkedList<>(); private long nextUpdate = 0; + static { + try { + staticNewsURL = new URL("http://static.sapsailing.com/events_news/news.json"); + } catch (MalformedURLException e) { + } + } + public JsonEventNewsProvider() { } @@ -53,8 +60,8 @@ public class JsonEventNewsProvider implements EventNewsProvider { try { BufferedReader bufferedReader = null; try { - logger.fine("Updating news from URL "+url); - URLConnection urlConnection = url.openConnection(); + logger.fine("Updating news from URL "+staticNewsURL); + URLConnection urlConnection = staticNewsURL.openConnection(); urlConnection.setConnectTimeout(CONNECTION_TIMEOUT); urlConnection.connect(); bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); @@ -82,7 +89,7 @@ public class JsonEventNewsProvider implements EventNewsProvider { } } } catch (IOException | ParseException e) { - logger.log(Level.INFO, "Exception trying to fetch news from " + url, e); + logger.log(Level.INFO, "Exception trying to fetch news from " + staticNewsURL, e); } } diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json deleted file mode 100644 index 958d98272c3..00000000000 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/news.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { - "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", - "timestamp": 1434030000000, - "title": "Winner's party", - "titles": { - "de": "Siegerfeier", - } - "message": "... is starting at 9pm", - "messages": { - "de": "... beginnt um 21:00 Uhr" - } - }, - { - "event": "406cffc2-b491-4f7e-b78e-a21abd97006a", - "timestamp": 1434050000000, - "title": "Test KW2015 2", - "message": "Test KW2015 2 content" - "url": "http://www.sapsailing.com/", - }, - { - "event": "d7887678-6ace-4b67-b513-1d6478020568", - "timestamp": 1434030000000, - "title": "Winner's party", - "titles": { - "de": "Siegerfeier", - } - "message": "... is starting at 9pm", - "messages": { - "de": "... beginnt um 21:00 Uhr" - } - }, - { - "event": "d7887678-6ace-4b67-b513-1d6478020568", - "timestamp": 1434050000000, - "title": "Test KW2015 2", - "message": "Test KW2015 2 content" - "url": "http://www.sapsailing.com/", - } -] \ No newline at end of file From 2e5a64f5e84a64ed275aac67befa856454cea761 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 15:53:47 +0200 Subject: [PATCH 091/117] Calculation of Stage/Teaser/Gallery images is now only based tags --- .../sailing/gwt/server/HomeServiceUtil.java | 183 +----------------- 1 file changed, 3 insertions(+), 180 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 20f244f25c5..a7827638c57 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -102,178 +102,16 @@ public final class HomeServiceUtil { } 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 int height; - final int width; - final int size; - final double ratio; - final ImageDescriptor image; - final boolean stage; - - ImageHolder() { - this(null); - } - - 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.ratio = height / (double) width; - } - } - - boolean isBetterWorstcaseThan(ImageHolder otherImageHolder) { - if (isNull()) { - return false; - } - - if (stage) { - return false; - } - - if (otherImageHolder.isNull()) { - return true; - } - - if (!isBigEnough() && otherImageHolder.isBigEnough()) { - return true; - } - if (this.fitsRatio() && otherImageHolder.fitsRatio() && otherImageHolder.isBigEnough() - && otherImageHolder.isSmallerThan(this)) { - return true; - } - return false; - } - - boolean isSmallerThan(ImageHolder otherImageHolder) { - return size < otherImageHolder.size; - } - - boolean isBigEnough() { - return height >= PERFECT_HEIGHT && width >= PERFECT_WIDTH; - } - - boolean fitsRatio() { - return ratio == PERFECT_RATIO; - } - - boolean isPerfectFit() { - return (height == PERFECT_HEIGHT && width == PERFECT_WIDTH); - } - - boolean isNull() { - return image == null; - } - } - - // search for name pattern - for (ImageDescriptor imageUrl : event.getImages()) { - if (hasTag(imageUrl, MediaTagConstants.TEASER)) { - return imageUrl; - } - } - - ImageHolder actualWorstcase = new ImageHolder(); - ImageHolder bestFit = new ImageHolder(); - - for (ImageDescriptor candidateImage : getPhotoGalleryImages(event)) { - ImageHolder candidate = new ImageHolder(candidateImage); - - if (candidate.isPerfectFit()) { - return candidate.image; - } - - if (candidate.fitsRatio() && candidate.isBigEnough()) { - if (candidate.isSmallerThan(bestFit)) { - bestFit = candidate; - } - } - - if (candidate.isBetterWorstcaseThan(actualWorstcase)) { - actualWorstcase = candidate; - } - - } - - if (!bestFit.isNull()) { - return bestFit.image; - } - if (!actualWorstcase.isNull()) { - return actualWorstcase.image; - } - return null; + return event.findImageWithTag(MediaTagConstants.TEASER); } - /** - * The stage image is determined from the {@link #images} collection by a series of heuristics and fall-back - * rules: - *
      - *
    1. If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.
    2. - *
    3. If no image has {@link MediaConstants#STAGE} tag, all images are considered - * candidates.
    4. - *
    5. From all candidates, the one with the biggest known size (determined by the product of width and height) is - * chosen.
    6. - *
    7. If the size isn't known for any candidate, the first candidate in {@link #imageURLs} is picked.
    8. - *
    - */ public static String getStageImageURLAsString(final EventBase event) { ImageDescriptor image = getStageImage(event); return image == null ? null : image.getURL().toString(); } - /** - * The stage image is determined from the {@link #images} collection by a series of heuristics and fall-back - * rules: - *
      - *
    1. If one or more image has {@link MediaConstants#STAGE} tag, only they are considered candidates.
    2. - *
    3. If no image has {@link MediaConstants#STAGE} tag, all images are considered - * candidates.
    4. - *
    5. From all candidates, the one with the biggest known size (determined by the product of width and height) is - * chosen.
    6. - *
    7. If the size isn't known for any candidate, the first candidate in {@link #imageURLs} is picked.
    8. - *
    - */ public static ImageDescriptor getStageImage(final EventBase event) { - ImageDescriptor bestMatch = null; - - for(ImageDescriptor candidate : event.getImages()) { - if(bestMatch == null || isBetterStageImage(candidate, bestMatch)) { - bestMatch = candidate; - continue; - } - } - - 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; + return event.findImageWithTag(MediaTagConstants.STAGE); } public static List getPhotoGalleryImageURLsAsString(EventBase event) { @@ -286,22 +124,7 @@ public final class HomeServiceUtil { } public static List getPhotoGalleryImages(EventBase event) { - ImageDescriptor stageImage = getStageImage(event); // if set, exclude stage image from photo gallery - List result = new ArrayList<>(); - Iterable imageURLs = event.getImages(); - - boolean first = true; - for (Iterator 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; + return event.findImagesWithTag(MediaTagConstants.GALLERY); } public static List getSailingLovesPhotographyImages(EventBase event) { From 17e142b8d15a08622c24d993e1a5b1146c623945 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 15:55:49 +0200 Subject: [PATCH 092/117] Fixed size of the event overview stage image --- .../client/place/event/partials/countdown/Countdown.gss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss index fb68ecc06ca..e4ceefcb450 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/countdown/Countdown.gss @@ -11,9 +11,9 @@ .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"); + background-size: cover; + background-position: center; + background-image: url("images/home/countdown-thumbnail.png"); } .countdown_content { position: absolute; From cd048416ee577e5c6bfba274731bbe1bae7f3915 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 16:04:53 +0200 Subject: [PATCH 093/117] Fixed calculation if an event has media --- .../domain/base/impl/EventBaseImpl.java | 698 +++++++++--------- .../sailing/gwt/server/HomeServiceUtil.java | 7 +- .../com/sap/sse/common/media/WithMedia.java | 1 + 3 files changed, 354 insertions(+), 352 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index 359b0818df1..2ab810449d4 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -1,346 +1,352 @@ -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; - -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; - - private String name; - private String description; - private final Venue venue; - private boolean isPublic; - private final UUID id; - private TimePoint startDate; - private TimePoint endDate; - private URL officialWebsiteURL; - private ConcurrentLinkedQueue images; - private ConcurrentLinkedQueue videos; - - protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id) { - this(name, startDate, endDate, new VenueImpl(venueName), isPublic, id); - } - - /** - * @param venue must not be null - */ - protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, Venue venue, boolean isPublic, UUID id) { - assert venue != null; - this.id = id; - this.name = name; - this.startDate = startDate; - this.endDate = endDate; - this.venue = venue; - this.isPublic = isPublic; - this.images = new ConcurrentLinkedQueue(); - this.videos = new ConcurrentLinkedQueue(); - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - if (images == null) { - images = new ConcurrentLinkedQueue(); - } - if (videos == null) { - videos = new ConcurrentLinkedQueue(); - } - } - - @Override - public UUID getId() { - return id; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public void setDescription(String description) { - this.description = description; - } - - @Override - public Venue getVenue() { - return venue; - } - - @Override - public String getName() { - return name; - } - - /** - * @param newName must not be null - */ - public void setName(String newName) { - if (newName == null) { - throw new IllegalArgumentException("An event name must not be null"); - } - this.name = newName; - } - - @Override - public boolean isPublic() { - return isPublic; - } - - @Override - public void setPublic(boolean isPublic) { - this.isPublic = isPublic; - } - - @Override - public TimePoint getStartDate() { - return startDate; - } - - @Override - public void setStartDate(TimePoint startDate) { - this.startDate = startDate; - } - - @Override - public TimePoint getEndDate() { - return endDate; - } - - @Override - public void setEndDate(TimePoint endDate) { - this.endDate = endDate; - } - - @Override - public Iterable getImageURLs() { - List result = new ArrayList(); - for (ImageDescriptor image : images) { - if (!image.hasTag(MediaTagConstants.SPONSOR) && !image.hasTag(MediaTagConstants.LOGO)) { - result.add(image.getURL()); - } - } - return result; - } - - @Override - public Iterable getVideoURLs() { - List result = new ArrayList(); - for(VideoDescriptor video: videos) { - result.add(video.getURL()); - } - return result; - } - - @Override - public Iterable getSponsorImageURLs() { - List result = new ArrayList(); - for(MediaDescriptor media : findMediaWithTag(images, MediaTagConstants.SPONSOR)) { - result.add(media.getURL()); - } - return result; - } - - @Override - public URL getLogoImageURL() { - URL result = null; - ImageDescriptor media = findImageWithTag(MediaTagConstants.LOGO); - if(media != null) { - result = media.getURL(); - } - return result; - } - - @Override - public URL getOfficialWebsiteURL() { - return officialWebsiteURL; - } - - @Override - public void setOfficialWebsiteURL(URL officialWebsiteURL) { - this.officialWebsiteURL = officialWebsiteURL; - } - - @Override - public Iterable 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 images) { - this.images.clear(); - if (images != null) { - Util.addAll(images, this.images); - } - } - - @Override - public Iterable 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 videos) { - this.videos.clear(); - if (videos != null) { - Util.addAll(videos, this.videos); - } - } - - @Override - public ImageDescriptor findImageWithTag(String tagName) { - ImageDescriptor result = null; - List mediaWithTag = findMediaWithTag(images, tagName); - if(mediaWithTag.size() > 0) { - result = mediaWithTag.get(0); - } - return result; - } - - @Override - public VideoDescriptor findVideoWithTag(String tagName) { - VideoDescriptor result = null; - List mediaWithTag = findMediaWithTag(videos, tagName); - if(mediaWithTag.size() > 0) { - result = mediaWithTag.get(0); - } - return result; - } - - @Override - public List findImagesWithTag(String tagName) { - return findMediaWithTag(images, tagName); - } - - @Override - public List findVideosWithTag(String tagName) { - return findMediaWithTag(videos, tagName); - } - - private List findMediaWithTag(Iterable media, String tagName) { - List 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 imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, - URL logoImageURL, Map 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 imageDimensions = MediaUtils.getImageDimensions(url); - if (imageDimensions != null) { - image.setSize(imageDimensions); - } - } - return image; - } - - private boolean hasMedia(Iterable media, URL url) { - for (MediaDescriptor mediaEntry : media) { - if (url.equals(mediaEntry.getURL())) { - return true; - } - } - return false; - } -} +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; + +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; + + private String name; + private String description; + private final Venue venue; + private boolean isPublic; + private final UUID id; + private TimePoint startDate; + private TimePoint endDate; + private URL officialWebsiteURL; + private ConcurrentLinkedQueue images; + private ConcurrentLinkedQueue videos; + + protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id) { + this(name, startDate, endDate, new VenueImpl(venueName), isPublic, id); + } + + /** + * @param venue must not be null + */ + protected EventBaseImpl(String name, TimePoint startDate, TimePoint endDate, Venue venue, boolean isPublic, UUID id) { + assert venue != null; + this.id = id; + this.name = name; + this.startDate = startDate; + this.endDate = endDate; + this.venue = venue; + this.isPublic = isPublic; + this.images = new ConcurrentLinkedQueue(); + this.videos = new ConcurrentLinkedQueue(); + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + if (images == null) { + images = new ConcurrentLinkedQueue(); + } + if (videos == null) { + videos = new ConcurrentLinkedQueue(); + } + } + + @Override + public UUID getId() { + return id; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public Venue getVenue() { + return venue; + } + + @Override + public String getName() { + return name; + } + + /** + * @param newName must not be null + */ + public void setName(String newName) { + if (newName == null) { + throw new IllegalArgumentException("An event name must not be null"); + } + this.name = newName; + } + + @Override + public boolean isPublic() { + return isPublic; + } + + @Override + public void setPublic(boolean isPublic) { + this.isPublic = isPublic; + } + + @Override + public TimePoint getStartDate() { + return startDate; + } + + @Override + public void setStartDate(TimePoint startDate) { + this.startDate = startDate; + } + + @Override + public TimePoint getEndDate() { + return endDate; + } + + @Override + public void setEndDate(TimePoint endDate) { + this.endDate = endDate; + } + + @Override + public Iterable getImageURLs() { + List result = new ArrayList(); + for (ImageDescriptor image : images) { + if (!image.hasTag(MediaTagConstants.SPONSOR) && !image.hasTag(MediaTagConstants.LOGO)) { + result.add(image.getURL()); + } + } + return result; + } + + @Override + public Iterable getVideoURLs() { + List result = new ArrayList(); + for(VideoDescriptor video: videos) { + result.add(video.getURL()); + } + return result; + } + + @Override + public Iterable getSponsorImageURLs() { + List result = new ArrayList(); + for(MediaDescriptor media : findMediaWithTag(images, MediaTagConstants.SPONSOR)) { + result.add(media.getURL()); + } + return result; + } + + @Override + public URL getLogoImageURL() { + URL result = null; + ImageDescriptor media = findImageWithTag(MediaTagConstants.LOGO); + if(media != null) { + result = media.getURL(); + } + return result; + } + + @Override + public URL getOfficialWebsiteURL() { + return officialWebsiteURL; + } + + @Override + public void setOfficialWebsiteURL(URL officialWebsiteURL) { + this.officialWebsiteURL = officialWebsiteURL; + } + + @Override + public Iterable 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 images) { + this.images.clear(); + if (images != null) { + Util.addAll(images, this.images); + } + } + + @Override + public Iterable 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 videos) { + this.videos.clear(); + if (videos != null) { + Util.addAll(videos, this.videos); + } + } + + @Override + public ImageDescriptor findImageWithTag(String tagName) { + ImageDescriptor result = null; + List mediaWithTag = findMediaWithTag(images, tagName); + if(mediaWithTag.size() > 0) { + result = mediaWithTag.get(0); + } + return result; + } + + @Override + public VideoDescriptor findVideoWithTag(String tagName) { + VideoDescriptor result = null; + List mediaWithTag = findMediaWithTag(videos, tagName); + if(mediaWithTag.size() > 0) { + result = mediaWithTag.get(0); + } + return result; + } + + @Override + public boolean hasImageWithTag(String tagName) { + List mediaWithTag = findMediaWithTag(images, tagName); + return mediaWithTag.size() > 0; + } + + @Override + public List findImagesWithTag(String tagName) { + return findMediaWithTag(images, tagName); + } + + @Override + public List findVideosWithTag(String tagName) { + return findMediaWithTag(videos, tagName); + } + + private List findMediaWithTag(Iterable media, String tagName) { + List 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 imageURLs, Iterable sponsorImageURLs, Iterable videoURLs, + URL logoImageURL, Map 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 imageDimensions = MediaUtils.getImageDimensions(url); + if (imageDimensions != null) { + image.setSize(imageDimensions); + } + } + return image; + } + + private boolean hasMedia(Iterable media, URL url) { + for (MediaDescriptor mediaEntry : media) { + if (url.equals(mediaEntry.getURL())) { + return true; + } + } + return false; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index a7827638c57..b663cd427e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -185,12 +185,7 @@ public final class HomeServiceUtil { } public static boolean hasPhotos(Event event) { - for(ImageDescriptor image : event.getImages()) { - if(!hasTag(image, MediaTagConstants.TEASER)) { - return true; - } - } - return false; + return event.hasImageWithTag(MediaTagConstants.GALLERY); } public static boolean hasVideos(Event event) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java index 71b0328c115..ac433dc3bbf 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java @@ -5,6 +5,7 @@ import java.util.List; public interface WithMedia extends WithImages, WithVideos { ImageDescriptor findImageWithTag(String tagName); List findImagesWithTag(String tagName); + boolean hasImageWithTag(String tagName); VideoDescriptor findVideoWithTag(String tagName); List findVideosWithTag(String tagName); From 577831f1a71d3c1ca69ea89f3b0b0531b9c99d0a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 16:31:33 +0200 Subject: [PATCH 094/117] Adapted new version of the UpdatesBox styling to fix cut off messages --- .../home/client/place/event/partials/updatesBox/UpdatesBox.gss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss index bd215238bec..308dd6624eb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss @@ -84,7 +84,7 @@ margin-left: 4em; padding-left: 0.8em; border-left: 1px solid #dedede; - line-height: 1.2; + line-height: 1.3; } @media (max-width: 1190px) { .updatesbox_item_content { From 1240c3f1877bb369b3a764ff31b471453c6d9e7f Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 15 Jun 2015 17:07:49 +0200 Subject: [PATCH 095/117] changed link destination for leaderboard update new item to leaderobard tab --- .../home/client/place/event/AbstractEventActivity.java | 10 ++++++++++ .../sailing/gwt/home/client/place/event/EventView.java | 2 ++ .../event/partials/updatesBox/UpdatesBoxItem.java | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java index 1bf3b410c4e..91dd27ab5d4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java @@ -18,6 +18,7 @@ import com.sap.sailing.gwt.home.client.app.ApplicationHistoryMapper; import com.sap.sailing.gwt.home.client.app.HomePlacesNavigator; import com.sap.sailing.gwt.home.client.app.PlaceNavigation; import com.sap.sailing.gwt.home.client.place.event.regatta.AbstractEventRegattaPlace; +import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaLeaderboardPlace; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaOverviewPlace; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaRacesPlace; import com.sap.sailing.gwt.home.client.place.events.EventsPlace; @@ -116,6 +117,10 @@ public abstract class AbstractEventActivity ex return new RegattaRacesPlace(contextForRegatta(regattaId)); } + public RegattaLeaderboardPlace getPlaceForRegattaLeaderboard(String regattaId) { + return new RegattaLeaderboardPlace(contextForRegatta(regattaId)); + } + protected EventContext contextForRegatta(String regattaId) { return new EventContext(ctx).withRegattaId(regattaId).withRegattaAnalyticsManager(null); } @@ -181,6 +186,11 @@ public abstract class AbstractEventActivity ex return homePlacesNavigator.getEventNavigation(getPlaceForRegatta(regattaId), null, false); } + @Override + public PlaceNavigation getRegattaLeaderboardNavigation(String regattaId) { + return homePlacesNavigator.getEventNavigation(getPlaceForRegattaLeaderboard(regattaId), null, false); + } + @Override public void ensureRegattaStructure(final AsyncCallback> callback) { if (ctx.getRaceGroups() != null) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventView.java index b28ecb554bd..41628345267 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventView.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.common.dto.RaceDTO; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; import com.sap.sailing.gwt.home.client.app.PlaceNavigation; import com.sap.sailing.gwt.home.client.place.event.regatta.AbstractEventRegattaPlace; +import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaLeaderboardPlace; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaRacesPlace; import com.sap.sailing.gwt.home.client.place.events.EventsPlace; import com.sap.sailing.gwt.home.client.place.fakeseries.SeriesDefaultPlace; @@ -56,6 +57,7 @@ public interface EventView getRegattaRacesNavigation(String regattaName); PlaceNavigation getRegattaNavigation(String regattaName); + PlaceNavigation getRegattaLeaderboardNavigation(String regattaName); void ensureRegattaStructure(AsyncCallback> callback); void ensureLeaderboardGroups(AsyncCallback> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index 7f2a265fcb2..37b0b613925 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -68,7 +68,7 @@ public class UpdatesBoxItem extends Widget { PlaceNavigation placeNavigation = null; if(entry instanceof LeaderboardNewsEntryDTO) { directLink = ((LeaderboardNewsEntryDTO) entry).getExternalURL(); - placeNavigation = presenter.getRegattaNavigation(((LeaderboardNewsEntryDTO) entry).getLeaderboardName()); + placeNavigation = presenter.getRegattaLeaderboardNavigation(((LeaderboardNewsEntryDTO) entry).getLeaderboardName()); } else if(entry instanceof AbstractRaceNewsEntryDTO) { AbstractRaceNewsEntryDTO raceEntry = (AbstractRaceNewsEntryDTO) entry; if(raceEntry.getTrackedRaceName() != null) { From 5b45ea95fa0506b580b212f685cc5ce265bce3e2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 17:14:17 +0200 Subject: [PATCH 096/117] Implemented locale dependent sailors info link --- .../place/event/EventActivityProxy.java | 3 +- .../sailing/gwt/server/HomeServiceImpl.java | 184 +----------------- .../sailing/gwt/server/HomeServiceUtil.java | 79 ++++++++ .../sailing/gwt/ui/client/HomeService.java | 3 - .../gwt/ui/client/HomeServiceAsync.java | 3 - .../dispatch/event/GetEventViewAction.java | 132 +++++++++++++ .../gwt/ui/shared/eventview/EventViewDTO.java | 3 +- 7 files changed, 220 insertions(+), 187 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivityProxy.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivityProxy.java index be0dc64d40e..d308d93ac64 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivityProxy.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivityProxy.java @@ -17,6 +17,7 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaLeaderboa import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaMediaPlace; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaOverviewPlace; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.RegattaRacesPlace; +import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventViewAction; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO.EventType; import com.sap.sse.gwt.client.mvp.AbstractActivityProxy; @@ -43,7 +44,7 @@ public class EventActivityProxy extends AbstractActivityProxy { } else { final UUID eventUUID = UUID.fromString(ctx.getEventId()); - clientFactory.getHomeService().getEventViewById(eventUUID, new AsyncCallback() { + clientFactory.getDispatch().execute(new GetEventViewAction(eventUUID), new AsyncCallback() { @Override public void onSuccess(final EventViewDTO event) { ctx.updateContext(event); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index c32d87b69ae..57b80311e53 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -20,30 +20,21 @@ import org.osgi.util.tracker.ServiceTracker; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.EventBase; -import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.RemoteSailingServerReference; -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; -import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.gwt.ui.client.HomeService; import com.sap.sailing.gwt.ui.server.Activator; import com.sap.sailing.gwt.ui.server.ProxiedRemoteServiceServlet; import com.sap.sailing.gwt.ui.shared.eventlist.EventListEventDTO; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; -import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; -import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO.EventType; -import com.sap.sailing.gwt.ui.shared.eventview.RegattaMetadataDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO.EventSeriesState; 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.SailingImageDTO; import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; -import com.sap.sailing.gwt.ui.shared.start.EventStageDTO; import com.sap.sailing.gwt.ui.shared.start.StageEventType; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; import com.sap.sailing.server.RacingEventService; @@ -58,7 +49,6 @@ 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; /** @@ -177,7 +167,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home Pair pair = featuredEvents.get(i); StageEventType stageType = pair.getA(); EventHolder holder = pair.getB(); - result.addStageEvent(convertToEventStageDTO(holder.event, holder.baseURL, holder.onRemoteServer, stageType)); + result.addStageEvent(HomeServiceUtil.convertToEventStageDTO(holder.event, holder.baseURL, holder.onRemoteServer, stageType, getService())); EventReferenceDTO eventRef = new EventReferenceDTO(holder.event); @@ -209,7 +199,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home for(EventHolder holder : recentEventsOfLast12Month) { if(result.getRecentEvents().size() < MAX_RECENT_EVENTS) { - result.addRecentEvent(convertToEventListDTO(holder.event, holder.baseURL, holder.onRemoteServer)); + result.addRecentEvent(HomeServiceUtil.convertToEventListDTO(holder.event, holder.baseURL, holder.onRemoteServer, getService())); } EventBase event = holder.event; @@ -264,100 +254,6 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home // TODO media return result; } - - @Override - public EventViewDTO getEventViewById(UUID id) { - Event event = getService().getEvent(id); - if (event == null) { - throw new RuntimeException("Event not found"); - } - - EventViewDTO dto = new EventViewDTO(); - mapToMetadataDTO(event, dto); - - 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)); - dto.setState(HomeServiceUtil.calculateEventState(event)); - dto.setHasAnalytics(EventState.RUNNING.compareTo(dto.getState()) <= 0); - - boolean isFakeSeries = HomeServiceUtil.isFakeSeries(event); - - for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) { - for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { - if(leaderboard instanceof RegattaLeaderboard) { - Regatta regatta = getService().getRegattaByName(leaderboard.getName()); - if(isFakeSeries && !HomeServiceUtil.isPartOfEvent(event, regatta)) { - continue; - } - - RegattaMetadataDTO regattaDTO = createRegattaMetadataDTO(leaderboardGroup, leaderboard); - regattaDTO.setStartDate(regatta.getStartDate() != null ? regatta.getStartDate().asDate() : null); - regattaDTO.setEndDate(regatta.getEndDate() != null ? regatta.getEndDate().asDate() : null); - regattaDTO.setState(HomeServiceUtil.calculateRegattaState(regattaDTO)); - dto.getRegattas().add(regattaDTO); - - } else if(leaderboard instanceof FlexibleLeaderboard) { - RegattaMetadataDTO regattaDTO = createRegattaMetadataDTO(leaderboardGroup, leaderboard); - - regattaDTO.setStartDate(null); - regattaDTO.setEndDate(null); - regattaDTO.setState(HomeServiceUtil.calculateRegattaState(regattaDTO)); - dto.getRegattas().add(regattaDTO); - } - } - } - - if (isFakeSeries) { - dto.setType(EventType.SERIES_EVENT); - - LeaderboardGroup overallLeaderboardGroup = event.getLeaderboardGroups().iterator().next(); - dto.setSeriesName(overallLeaderboardGroup.getDisplayName() != null ? overallLeaderboardGroup.getDisplayName() :overallLeaderboardGroup.getName()); - List fakeSeriesEvents = new ArrayList(); - - for (Event eventOfSeries : getService().getAllEvents()) { - for (LeaderboardGroup leaderboardGroup : eventOfSeries.getLeaderboardGroups()) { - if (overallLeaderboardGroup.equals(leaderboardGroup)) { - fakeSeriesEvents.add(eventOfSeries); - } - } - } - Collections.sort(fakeSeriesEvents, new Comparator() { - public int compare(Event e1, Event e2) { - return e1.getStartDate().compareTo(e2.getEndDate()); - } - }); - for(Event eventInSeries: fakeSeriesEvents) { - String displayName = getLocation(eventInSeries); - if(displayName == null) { - displayName = eventInSeries.getName(); - } - dto.getEventsOfSeries().add(new EventReferenceDTO(eventInSeries.getId(), displayName)); - } - } else { - dto.setType(dto.getRegattas().size() == 1 ? EventType.SINGLE_REGATTA: EventType.MULTI_REGATTA); - } - - // Special solution for Kieler Woche 2015 - if("a9d6c5d5-cac3-47f2-9b5c-506e441819a1".equals(event.getId().toString())) { - dto.setSailorsInfoURL("http://sailorsinfo.kieler-woche.de/"); - } - - return dto; - } - - private RegattaMetadataDTO createRegattaMetadataDTO(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard) { - RegattaMetadataDTO regattaDTO = new RegattaMetadataDTO(leaderboard.getName(), leaderboard.getName()); - regattaDTO.setBoatCategory(leaderboardGroup.getDisplayName() != null ? leaderboardGroup.getDisplayName() : leaderboardGroup.getName()); - regattaDTO.setCompetitorsCount(HomeServiceUtil.calculateCompetitorsCount(leaderboard)); - regattaDTO.setRaceCount(HomeServiceUtil.calculateRaceCount(leaderboard)); - regattaDTO.setTrackedRacesCount(HomeServiceUtil.calculateTrackedRaceCount(leaderboard)); - regattaDTO.setBoatClass(HomeServiceUtil.calculateBoatClass(leaderboard)); - - return regattaDTO; - } @Override public EventSeriesViewDTO getEventSeriesViewById(UUID id) { @@ -369,7 +265,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home EventSeriesViewDTO dto = new EventSeriesViewDTO(); dto.setId(id); ImageDescriptor logoImage = o.findImageWithTag(MediaTagConstants.LOGO); - dto.setLogoImage(logoImage != null ? convertToImageDTO(logoImage) : null); + dto.setLogoImage(logoImage != null ? HomeServiceUtil.convertToImageDTO(logoImage) : null); // TODO implement correctly. We currently do not show media for series. dto.setHasMedia(false); @@ -398,7 +294,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } }); for(Event eventInSeries: fakeSeriesEvents) { - EventMetadataDTO eventOfSeries = convertToMetadataDTO(eventInSeries); + EventMetadataDTO eventOfSeries = HomeServiceUtil.convertToMetadataDTO(eventInSeries, getService()); dto.addEvent(eventOfSeries); oneEventStarted |= eventOfSeries.isStarted(); @@ -459,7 +355,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home forAllPublicEvents(new EventVisitor() { @Override public void visit(EventBase event, boolean onRemoteServer, URL baseURL) { - EventListEventDTO eventDTO = convertToEventListDTO(event, baseURL, onRemoteServer); + EventListEventDTO eventDTO = HomeServiceUtil.convertToEventListDTO(event, baseURL, onRemoteServer, getService()); result.addEvent(eventDTO, getYear(eventDTO.getStartDate())); } }); @@ -471,74 +367,4 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home cal.setTime(date); return cal.get(Calendar.YEAR); } - - private EventStageDTO convertToEventStageDTO(EventBase event, URL baseURL, boolean onRemoteServer, StageEventType stageType) { - EventStageDTO dto = new EventStageDTO(); - mapToMetadataDTO(event, dto); - dto.setBaseURL(baseURL.toString()); - dto.setOnRemoteServer(onRemoteServer); - dto.setStageType(stageType); - dto.setStageImageURL(HomeServiceUtil.getStageImageURLAsString(event)); - return dto; - } - - private EventListEventDTO convertToEventListDTO(EventBase event, URL baseURL, boolean onRemoteServer) { - EventListEventDTO dto = new EventListEventDTO(); - mapToMetadataDTO(event, dto); - dto.setBaseURL(baseURL.toString()); - dto.setOnRemoteServer(onRemoteServer); - return dto; - } - - private EventMetadataDTO convertToMetadataDTO(EventBase event) { - EventMetadataDTO dto = new EventMetadataDTO(); - mapToMetadataDTO(event, dto); - return dto; - } - - private void mapToMetadataDTO(EventBase event, EventMetadataDTO dto) { - dto.setId((UUID) event.getId()); - dto.setDisplayName(event.getName()); - dto.setStartDate(event.getStartDate().asDate()); - dto.setEndDate(event.getEndDate().asDate()); - dto.setState(HomeServiceUtil.calculateEventState(event)); - dto.setVenue(event.getVenue().getName()); - if(HomeServiceUtil.isFakeSeries(event)) { - dto.setLocation(getLocation(event)); - } - dto.setThumbnailImageURL(HomeServiceUtil.findEventThumbnailImageUrlAsString(event)); - } - - public String getLocation(EventBase eventBase) { - if(!(eventBase instanceof Event)) { - return null; - } - Event event = (Event) eventBase; - for (Leaderboard leaderboard : event.getLeaderboardGroups().iterator().next().getLeaderboards()) { - if(leaderboard instanceof RegattaLeaderboard) { - Regatta regattaEntity = getService().getRegattaByName(leaderboard.getName()); - if(!HomeServiceUtil.isPartOfEvent(event, regattaEntity)) { - continue; - } - } - return leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() : leaderboard.getName(); - } - 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 tags = new ArrayList(); - for(String tag: image.getTags()) { - tags.add(tag); - } - result.setTags(tags); - return result; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index b663cd427e3..db12859ccb5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.server; +import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -8,6 +9,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Random; +import java.util.UUID; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; @@ -19,16 +21,23 @@ import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.ui.shared.eventlist.EventListEventDTO; 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.EventMetadataDTO; 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.start.EventStageDTO; +import com.sap.sailing.gwt.ui.shared.start.StageEventType; +import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.Util; 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; +import com.sap.sse.gwt.client.media.ImageDTO; public final class HomeServiceUtil { @@ -294,4 +303,74 @@ public final class HomeServiceUtil { } return LocaleMatch.NO_MATCH; } + + public static EventStageDTO convertToEventStageDTO(EventBase event, URL baseURL, boolean onRemoteServer, StageEventType stageType, RacingEventService service) { + EventStageDTO dto = new EventStageDTO(); + mapToMetadataDTO(event, dto, service); + dto.setBaseURL(baseURL.toString()); + dto.setOnRemoteServer(onRemoteServer); + dto.setStageType(stageType); + dto.setStageImageURL(HomeServiceUtil.getStageImageURLAsString(event)); + return dto; + } + + public static EventListEventDTO convertToEventListDTO(EventBase event, URL baseURL, boolean onRemoteServer, RacingEventService service) { + EventListEventDTO dto = new EventListEventDTO(); + mapToMetadataDTO(event, dto, service); + dto.setBaseURL(baseURL.toString()); + dto.setOnRemoteServer(onRemoteServer); + return dto; + } + + public static EventMetadataDTO convertToMetadataDTO(EventBase event, RacingEventService service) { + EventMetadataDTO dto = new EventMetadataDTO(); + mapToMetadataDTO(event, dto, service); + return dto; + } + + public static void mapToMetadataDTO(EventBase event, EventMetadataDTO dto, RacingEventService service) { + dto.setId((UUID) event.getId()); + dto.setDisplayName(event.getName()); + dto.setStartDate(event.getStartDate().asDate()); + dto.setEndDate(event.getEndDate().asDate()); + dto.setState(HomeServiceUtil.calculateEventState(event)); + dto.setVenue(event.getVenue().getName()); + if(HomeServiceUtil.isFakeSeries(event)) { + dto.setLocation(getLocation(event, service)); + } + dto.setThumbnailImageURL(HomeServiceUtil.findEventThumbnailImageUrlAsString(event)); + } + + public static String getLocation(EventBase eventBase, RacingEventService service) { + if(!(eventBase instanceof Event)) { + return null; + } + Event event = (Event) eventBase; + for (Leaderboard leaderboard : event.getLeaderboardGroups().iterator().next().getLeaderboards()) { + if(leaderboard instanceof RegattaLeaderboard) { + Regatta regattaEntity = service.getRegattaByName(leaderboard.getName()); + if(!HomeServiceUtil.isPartOfEvent(event, regattaEntity)) { + continue; + } + } + return leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() : leaderboard.getName(); + } + return null; + } + + public static 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 tags = new ArrayList(); + for(String tag: image.getTags()) { + tags.add(tag); + } + result.setTags(tags); + return result; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java index 304c9d0d1d4..d46d9cb55c8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeService.java @@ -4,14 +4,11 @@ import java.util.UUID; import com.google.gwt.user.client.rpc.RemoteService; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; -import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; import com.sap.sailing.gwt.ui.shared.media.MediaDTO; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; public interface HomeService extends RemoteService { - EventViewDTO getEventViewById(UUID id); - EventSeriesViewDTO getEventSeriesViewById(UUID id); MediaDTO getMediaForEvent(UUID eventId); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java index 7198af22700..b2dc0acf209 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/HomeServiceAsync.java @@ -4,7 +4,6 @@ import java.util.UUID; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.gwt.ui.shared.eventlist.EventListViewDTO; -import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO; import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO; import com.sap.sailing.gwt.ui.shared.media.MediaDTO; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; @@ -14,8 +13,6 @@ import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; * The async counterpart of {@link HomeService} */ public interface HomeServiceAsync { - void getEventViewById(UUID id, AsyncCallback callback); - void getEventSeriesViewById(UUID id, AsyncCallback asyncCallback); void getMediaForEvent(UUID eventId, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java new file mode 100644 index 00000000000..280214e3a25 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java @@ -0,0 +1,132 @@ +package com.sap.sailing.gwt.ui.shared.dispatch.event; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.gwt.server.HomeServiceUtil; +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.eventview.EventViewDTO; +import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO.EventType; +import com.sap.sailing.gwt.ui.shared.eventview.RegattaMetadataDTO; +import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; +import com.sap.sailing.gwt.ui.shared.general.EventState; +import com.sap.sse.common.media.ImageDescriptor; +import com.sap.sse.common.media.MediaTagConstants; + +public class GetEventViewAction implements Action { + private UUID eventId; + + public GetEventViewAction() { + } + + public GetEventViewAction(UUID eventId) { + this.eventId = eventId; + } + + @GwtIncompatible + public EventViewDTO execute(DispatchContext context) { + Event event = context.getRacingEventService().getEvent(eventId); + if (event == null) { + throw new RuntimeException("Event not found"); + } + + EventViewDTO dto = new EventViewDTO(); + HomeServiceUtil.mapToMetadataDTO(event, dto, context.getRacingEventService()); + + ImageDescriptor logoImage = event.findImageWithTag(MediaTagConstants.LOGO); + dto.setLogoImage(logoImage != null ? HomeServiceUtil.convertToImageDTO(logoImage) : null); + dto.setOfficialWebsiteURL(event.getOfficialWebsiteURL() == null ? null : event.getOfficialWebsiteURL().toString()); + + dto.setHasMedia(HomeServiceUtil.hasMedia(event)); + dto.setState(HomeServiceUtil.calculateEventState(event)); + dto.setHasAnalytics(EventState.RUNNING.compareTo(dto.getState()) <= 0); + + boolean isFakeSeries = HomeServiceUtil.isFakeSeries(event); + + for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) { + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { + if(leaderboard instanceof RegattaLeaderboard) { + Regatta regatta = context.getRacingEventService().getRegattaByName(leaderboard.getName()); + if(isFakeSeries && !HomeServiceUtil.isPartOfEvent(event, regatta)) { + continue; + } + + RegattaMetadataDTO regattaDTO = createRegattaMetadataDTO(leaderboardGroup, leaderboard); + regattaDTO.setStartDate(regatta.getStartDate() != null ? regatta.getStartDate().asDate() : null); + regattaDTO.setEndDate(regatta.getEndDate() != null ? regatta.getEndDate().asDate() : null); + regattaDTO.setState(HomeServiceUtil.calculateRegattaState(regattaDTO)); + dto.getRegattas().add(regattaDTO); + + } else if(leaderboard instanceof FlexibleLeaderboard) { + RegattaMetadataDTO regattaDTO = createRegattaMetadataDTO(leaderboardGroup, leaderboard); + + regattaDTO.setStartDate(null); + regattaDTO.setEndDate(null); + regattaDTO.setState(HomeServiceUtil.calculateRegattaState(regattaDTO)); + dto.getRegattas().add(regattaDTO); + } + } + } + + if (isFakeSeries) { + dto.setType(EventType.SERIES_EVENT); + + LeaderboardGroup overallLeaderboardGroup = event.getLeaderboardGroups().iterator().next(); + dto.setSeriesName(overallLeaderboardGroup.getDisplayName() != null ? overallLeaderboardGroup.getDisplayName() :overallLeaderboardGroup.getName()); + List fakeSeriesEvents = new ArrayList(); + + for (Event eventOfSeries : context.getRacingEventService().getAllEvents()) { + for (LeaderboardGroup leaderboardGroup : eventOfSeries.getLeaderboardGroups()) { + if (overallLeaderboardGroup.equals(leaderboardGroup)) { + fakeSeriesEvents.add(eventOfSeries); + } + } + } + Collections.sort(fakeSeriesEvents, new Comparator() { + public int compare(Event e1, Event e2) { + return e1.getStartDate().compareTo(e2.getEndDate()); + } + }); + for(Event eventInSeries: fakeSeriesEvents) { + String displayName = HomeServiceUtil.getLocation(eventInSeries, context.getRacingEventService()); + if(displayName == null) { + displayName = eventInSeries.getName(); + } + dto.getEventsOfSeries().add(new EventReferenceDTO(eventInSeries.getId(), displayName)); + } + } else { + dto.setType(dto.getRegattas().size() == 1 ? EventType.SINGLE_REGATTA: EventType.MULTI_REGATTA); + } + + // Special solution for Kieler Woche 2015 + if("a9d6c5d5-cac3-47f2-9b5c-506e441819a1".equals(event.getId().toString())) { + dto.setSailorsInfoURL(Locale.GERMAN.equals(context.getClientLocale()) ? "http://sailorsinfo.kieler-woche.de/" : "http://sailorsinfo.kieler-woche.de/en"); + } + + return dto; + } + + @GwtIncompatible + private RegattaMetadataDTO createRegattaMetadataDTO(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard) { + RegattaMetadataDTO regattaDTO = new RegattaMetadataDTO(leaderboard.getName(), leaderboard.getName()); + regattaDTO.setBoatCategory(leaderboardGroup.getDisplayName() != null ? leaderboardGroup.getDisplayName() : leaderboardGroup.getName()); + regattaDTO.setCompetitorsCount(HomeServiceUtil.calculateCompetitorsCount(leaderboard)); + regattaDTO.setRaceCount(HomeServiceUtil.calculateRaceCount(leaderboard)); + regattaDTO.setTrackedRacesCount(HomeServiceUtil.calculateTrackedRaceCount(leaderboard)); + regattaDTO.setBoatClass(HomeServiceUtil.calculateBoatClass(leaderboard)); + + return regattaDTO; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java index 55aad746141..78279dc1f0c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/eventview/EventViewDTO.java @@ -3,11 +3,12 @@ package com.sap.sailing.gwt.ui.shared.eventview; import java.util.ArrayList; import java.util.List; +import com.sap.sailing.gwt.ui.shared.dispatch.Result; 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 { +public class EventViewDTO extends EventMetadataDTO implements Result { public enum EventType { SINGLE_REGATTA, MULTI_REGATTA, SERIES_EVENT From 3877064ef34b12c0ac961ff28a42782fa1977876 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 17:19:18 +0200 Subject: [PATCH 097/117] Fixed regatta display name --- .../sap/sailing/gwt/home/client/place/event/EventContext.java | 2 +- .../gwt/ui/shared/dispatch/event/GetEventViewAction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventContext.java index 6e5e81df66e..e9750708f07 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventContext.java @@ -77,7 +77,7 @@ public class EventContext { return regattaId; } if(eventDTO != null && (eventDTO.getType() == EventType.SINGLE_REGATTA || eventDTO.getType() == EventType.SERIES_EVENT)) { - return eventDTO.getRegattas().get(0).getDisplayName(); + return eventDTO.getRegattas().get(0).getId(); } return null; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java index 280214e3a25..e8e81c51a8d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java @@ -120,7 +120,7 @@ public class GetEventViewAction implements Action { @GwtIncompatible private RegattaMetadataDTO createRegattaMetadataDTO(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard) { - RegattaMetadataDTO regattaDTO = new RegattaMetadataDTO(leaderboard.getName(), leaderboard.getName()); + RegattaMetadataDTO regattaDTO = new RegattaMetadataDTO(leaderboard.getName(), leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() : leaderboard.getName()); regattaDTO.setBoatCategory(leaderboardGroup.getDisplayName() != null ? leaderboardGroup.getDisplayName() : leaderboardGroup.getName()); regattaDTO.setCompetitorsCount(HomeServiceUtil.calculateCompetitorsCount(leaderboard)); regattaDTO.setRaceCount(HomeServiceUtil.calculateRaceCount(leaderboard)); From 9a353743bf19240dabdcbd03dd46cc7dbc7820ec Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 17:31:31 +0200 Subject: [PATCH 098/117] Improved construction of regatta name for the EventHeader --- .../place/event/partials/header/EventHeader.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java index 99bfb959893..7762dae18ef 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/header/EventHeader.java @@ -105,12 +105,19 @@ public class EventHeader extends Composite { private void initFields() { String logoUrl = event.getLogoImage() != null ? event.getLogoImage().getSourceRef() : EventHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri().asString(); eventLogo.getStyle().setBackgroundImage("url(" + logoUrl + ")"); - eventLogo.setTitle(event.getDisplayName()); + + String eventDisplayName = event.getDisplayName(); + eventLogo.setTitle(eventDisplayName); String nameToShow; if(presenter.showRegattaMetadata()) { HasRegattaMetadata regattaMetadata = presenter.getRegattaMetadata(); - nameToShow = regattaMetadata.getDisplayName(); + String regattaDisplayName = regattaMetadata.getDisplayName(); + if(regattaDisplayName.toLowerCase().contains(eventDisplayName.toLowerCase())) { + nameToShow = regattaDisplayName; + } else { + nameToShow = eventDisplayName + " - " + regattaDisplayName; + } if(regattaMetadata.getCompetitorsCount() > 0) { competitors.setInnerText((i18n.competitorsCount(regattaMetadata.getCompetitorsCount()))); @@ -138,7 +145,7 @@ public class EventHeader extends Composite { hide(eventVenueContainer, eventLink); } else { - nameToShow = event.getDisplayName(); + nameToShow = eventDisplayName; eventDate.setInnerHTML(EventDatesFormatterUtil.formatDateRangeWithYear(event.getStartDate(), event.getEndDate())); String venue = event.getLocationAndVenue(); if(event.getVenueCountry() != null && !event.getVenueCountry().isEmpty()) { From 162f565b693536551885ef78bc7d0ee90201a5f2 Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 15 Jun 2015 17:38:21 +0200 Subject: [PATCH 099/117] fix for a prio1 problem with migration code losing event -> leaderboard group relations --- .../persistence/impl/DomainObjectFactoryImpl.java | 5 +---- .../sailing/server/impl/RacingEventServiceImpl.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 2a1101b145b..444b11d07c1 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -979,10 +979,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { try { for (DBObject object : eventCollection.find()) { Event event = loadEvent(object); - boolean hasMigratedSomething = loadLegacyImageAndVideoURLs(event, object); - if(hasMigratedSomething) { - new MongoObjectFactoryImpl(database).storeEvent(event); - } + loadLegacyImageAndVideoURLs(event, object); result.add(event); } } catch (Exception e) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 4ce6bd25815..b2eb96a0b9d 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -545,6 +545,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes loadRaceIDToRegattaAssociations(); loadStoredLeaderboardsAndGroups(); loadLinksFromEventsToLeaderboardGroups(); + storeLoadedEvents(); loadMediaLibary(); loadStoredDeviceConfigurations(); loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh(); @@ -641,6 +642,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } } + /** + * Stores all events directly after loading them. + * This is a workaround for a problem with event migration code which requires storing an event after some changes. + * Because not all event data is stored in the event collection (e.g. LeaderboardGroup -> Event relation) the storeEvent + * method must be called AFTER the event object is fully initialized. + */ + private void storeLoadedEvents() { + for(Event event: eventsById.values()) { + mongoObjectFactory.storeEvent(event); + } + } + private void loadLinksFromEventsToLeaderboardGroups() { domainObjectFactory.loadLeaderboardGroupLinksForEvents(/* eventResolver */this, /* leaderboardGroupResolver */ this); From 361fb0334ef1dc5fb5db68516947b03953700f74 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 15 Jun 2015 18:08:24 +0200 Subject: [PATCH 100/117] Generation of more consistent series event names --- .../sailing/gwt/server/HomeServiceUtil.java | 24 ++++++++++++++++++- .../dispatch/event/GetEventViewAction.java | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index db12859ccb5..854f145cd51 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -330,7 +330,7 @@ public final class HomeServiceUtil { public static void mapToMetadataDTO(EventBase event, EventMetadataDTO dto, RacingEventService service) { dto.setId((UUID) event.getId()); - dto.setDisplayName(event.getName()); + dto.setDisplayName(getEventDisplayName(event, service)); dto.setStartDate(event.getStartDate().asDate()); dto.setEndDate(event.getEndDate().asDate()); dto.setState(HomeServiceUtil.calculateEventState(event)); @@ -341,6 +341,28 @@ public final class HomeServiceUtil { dto.setThumbnailImageURL(HomeServiceUtil.findEventThumbnailImageUrlAsString(event)); } + public static String getEventDisplayName(EventBase event, RacingEventService service) { + if(isFakeSeries(event)) { + String seriesName = getSeriesName(event); + if(seriesName != null) { + String location = getLocation(event, service); + if(location != null) { + return seriesName + " - " + location; + } + } + } + return event.getName(); + } + + public static String getSeriesName(EventBase event) { + LeaderboardGroupBase overallLeaderboardGroup = event.getLeaderboardGroups().iterator().next(); + return getLeaderboardDisplayName(overallLeaderboardGroup); + } + + public static String getLeaderboardDisplayName(LeaderboardGroupBase overallLeaderboardGroup) { + return overallLeaderboardGroup.getDisplayName() != null ? overallLeaderboardGroup.getDisplayName() : overallLeaderboardGroup.getName(); + } + public static String getLocation(EventBase eventBase, RacingEventService service) { if(!(eventBase instanceof Event)) { return null; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java index e8e81c51a8d..aca16fc0cb7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventViewAction.java @@ -84,7 +84,7 @@ public class GetEventViewAction implements Action { dto.setType(EventType.SERIES_EVENT); LeaderboardGroup overallLeaderboardGroup = event.getLeaderboardGroups().iterator().next(); - dto.setSeriesName(overallLeaderboardGroup.getDisplayName() != null ? overallLeaderboardGroup.getDisplayName() :overallLeaderboardGroup.getName()); + dto.setSeriesName(HomeServiceUtil.getLeaderboardDisplayName(overallLeaderboardGroup)); List fakeSeriesEvents = new ArrayList(); for (Event eventOfSeries : context.getRacingEventService().getAllEvents()) { From 01b65cd6ebbcaa466c8008d0bead9179ccf9210f Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 15 Jun 2015 19:36:02 +0200 Subject: [PATCH 101/117] some javadoc --- .../news/impl/LeaderboardUpdateEventNewsProvider.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java index 54305106f5d..29f972c1313 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java @@ -15,6 +15,11 @@ import com.sap.sailing.news.EventNewsItem; import com.sap.sailing.news.EventNewsProvider; import com.sap.sse.common.TimePoint; +/** + * An event news provider looking at leaderboard updates triggered by changes of timePointOfLatestModification + * @author Frank + * + */ public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider { @Override From 0f28a307f667222b3e6f8a281dcbff113d906f02 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 16 Jun 2015 09:16:57 +0200 Subject: [PATCH 102/117] Loading news is now handled in it's own action independent of the stage --- .../tabs/MultiregattaOverviewTabView.java | 2 + .../event/overview/EventOverviewStage.java | 18 ++++++- .../regatta/tabs/RegattaOverviewTabView.java | 2 + .../tabs/reload/RefreshableWidget.java | 3 +- .../gwt/ui/shared/dispatch/ListResult.java | 21 ++++++++ .../dispatch/event/EventOverviewStageDTO.java | 24 --------- .../event/GetEventOverviewNewsAction.java | 53 +++++++++++++++++++ .../event/GetEventOverviewStageAction.java | 21 -------- .../ui/shared/dispatch/news/NewsEntryDTO.java | 4 +- 9 files changed, 98 insertions(+), 50 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/ListResult.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java index b467fbaab88..ab6ce85375d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java @@ -23,6 +23,7 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshMa import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewNewsAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetLiveRacesForEventAction; import com.sap.sse.common.Util.Triple; @@ -63,6 +64,7 @@ public class MultiregattaOverviewTabView extends Composite implements Multiregat RefreshManager refreshManager = new RefreshManager(this, currentPresenter.getDispatch()); refreshManager.add(stage, new GetEventOverviewStageAction(currentPresenter.getCtx().getEventDTO().getId())); + refreshManager.add(stage.getNewsRefreshable(), new GetEventOverviewNewsAction(currentPresenter.getCtx().getEventDTO().getId())); refreshManager.add(racesListLive, new GetLiveRacesForEventAction(currentPresenter.getCtx().getEventDTO().getId())); contentArea.setWidget(this); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java index b9b682a563d..5cee021c6f4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java @@ -18,6 +18,7 @@ import com.sap.sailing.gwt.home.client.place.event.partials.message.Message; import com.sap.sailing.gwt.home.client.place.event.partials.updatesBox.UpdatesBox; import com.sap.sailing.gwt.home.client.place.event.partials.video.Video; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshableWidget; +import com.sap.sailing.gwt.ui.shared.dispatch.ListResult; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageContentDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewTickerStageDTO; @@ -26,6 +27,13 @@ import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; public class EventOverviewStage extends Composite implements RefreshableWidget { + private final RefreshableWidget> newsRefreshable = new RefreshableWidget>() { + @Override + public void setData(ListResult data, long nextUpdate, int updateNo) { + setNews(data.getValues()); + } + }; + private static StageUiBinder uiBinder = GWT.create(StageUiBinder.class); interface StageUiBinder extends UiBinder { @@ -70,8 +78,13 @@ public class EventOverviewStage extends Composite implements RefreshableWidget news) { + if(lastContent == null) { + setData(new EventOverviewStageDTO(null, new EventOverviewTickerStageDTO(null, null, null)), 0, 0); + } - List news = stageData.getNews(); if(news.isEmpty()) { updatesWrapperUi.getStyle().setDisplay(Display.NONE); stage.removeStyleName(mediaCss.medium7()); @@ -84,4 +97,7 @@ public class EventOverviewStage extends Composite implements RefreshableWidget> getNewsRefreshable() { + return newsRefreshable; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java index 9422074fdc5..eaf84a9a789 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java @@ -13,6 +13,7 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.EventRegattaView; import com.sap.sailing.gwt.home.client.place.event.regatta.EventRegattaView.Presenter; import com.sap.sailing.gwt.home.client.place.event.regatta.RegattaTabView; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshManager; +import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewNewsAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetLiveRacesForRegattaAction; @@ -51,6 +52,7 @@ public class RegattaOverviewTabView extends Composite implements RegattaTabView< // TODO regatta specific depending on event type refreshManager.add(stage, new GetEventOverviewStageAction(currentPresenter.getCtx().getEventDTO().getId())); + refreshManager.add(stage.getNewsRefreshable(), new GetEventOverviewNewsAction(currentPresenter.getCtx().getEventDTO().getId())); refreshManager.add(racesListLive, new GetLiveRacesForRegattaAction(currentPresenter.getCtx().getEventDTO() .getId(), currentPresenter.getCtx().getRegattaId())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/reload/RefreshableWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/reload/RefreshableWidget.java index d1d6e0b5844..2186f477d10 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/reload/RefreshableWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/reload/RefreshableWidget.java @@ -1,8 +1,7 @@ package com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload; -import com.google.gwt.user.client.ui.IsWidget; import com.sap.sailing.gwt.ui.shared.dispatch.DTO; -public interface RefreshableWidget extends IsWidget { +public interface RefreshableWidget { void setData(D data, long nextUpdate, int updateNo); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/ListResult.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/ListResult.java new file mode 100644 index 00000000000..467f6d2235e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/ListResult.java @@ -0,0 +1,21 @@ +package com.sap.sailing.gwt.ui.shared.dispatch; + +import java.util.ArrayList; +import java.util.List; + +public class ListResult implements DTO, Result { + private ArrayList values = new ArrayList<>(); + + @SuppressWarnings("unused") + private ListResult() { + } + + public ListResult(List values) { + super(); + this.values.addAll(values); + } + + public List getValues() { + return values; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java index 765b30f755f..6500765e5f2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewStageDTO.java @@ -1,19 +1,12 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - import com.sap.sailing.gwt.ui.shared.dispatch.DTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; public class EventOverviewStageDTO implements DTO { private String eventMessage; private EventOverviewStageContentDTO stageContent; - private List news = new ArrayList<>(); - @SuppressWarnings("unused") private EventOverviewStageDTO() { } @@ -31,21 +24,4 @@ public class EventOverviewStageDTO implements DTO { public EventOverviewStageContentDTO getStageContent() { return stageContent; } - - public List getNews() { - return news; - } - - public void addNews(NewsEntryDTO newsEntry) { - for(int i = 0; i < news.size(); i++) { - NewsEntryDTO foundEntry = news.get(i); - Date foundTimestamp = foundEntry.getTimestamp(); - Date timestamp = newsEntry.getTimestamp(); - if(timestamp == null || (foundTimestamp != null && timestamp.compareTo(foundTimestamp)>0)) { - news.add(i, newsEntry); - return; - } - } - news.add(newsEntry); - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java new file mode 100644 index 00000000000..c36144046bb --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java @@ -0,0 +1,53 @@ +package com.sap.sailing.gwt.ui.shared.dispatch.event; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Event; +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.ListResult; +import com.sap.sailing.gwt.ui.shared.dispatch.ResultWithTTL; +import com.sap.sailing.gwt.ui.shared.dispatch.news.InfoNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; +import com.sap.sailing.news.EventNewsItem; +import com.sap.sailing.news.impl.InfoEventNewsItem; +import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; + +public class GetEventOverviewNewsAction implements Action>> { + private UUID eventId; + + public GetEventOverviewNewsAction() { + } + + public GetEventOverviewNewsAction(UUID eventId) { + this.eventId = eventId; + } + + @Override + @GwtIncompatible + public ResultWithTTL> execute(DispatchContext context) { + Event event = context.getRacingEventService().getEvent(eventId); + long ttl = 1000 * 60 * 2; + return new ResultWithTTL<>(ttl, new ListResult(getNews(context, event))); + } + + @GwtIncompatible + private List getNews(DispatchContext dispatchContext, Event event) { + List newsItems = dispatchContext.getEventNewsService().getNews(event); + + List news = new ArrayList<>(newsItems.size()); + for(EventNewsItem newsItem: newsItems) { + if(newsItem instanceof InfoEventNewsItem) { + news.add(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem, dispatchContext.getClientLocale())); + } + if(newsItem instanceof LeaderboardUpdateNewsItem) { + news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem)); + } + } + return news; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index d54614feb89..77dd332870d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -2,7 +2,6 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; @@ -11,12 +10,7 @@ import com.sap.sailing.gwt.server.HomeServiceUtil; 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.dispatch.news.InfoNewsEntryDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; -import com.sap.sailing.news.EventNewsItem; -import com.sap.sailing.news.impl.InfoEventNewsItem; -import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.VideoDescriptor; @@ -50,7 +44,6 @@ public class GetEventOverviewStageAction implements Action(ttl, stage); } @@ -127,18 +120,4 @@ public class GetEventOverviewStageAction implements Action newsItems = dispatchContext.getEventNewsService().getNews(event); - - for(EventNewsItem newsItem: newsItems) { - if(newsItem instanceof InfoEventNewsItem) { - stage.addNews(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem, dispatchContext.getClientLocale())); - } - if(newsItem instanceof LeaderboardUpdateNewsItem) { - stage.addNews(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem)); - } - } - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java index 95e98bb0cba..314c07eb4fb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java @@ -4,9 +4,9 @@ import java.net.URL; import java.util.Date; import com.google.gwt.core.shared.GwtIncompatible; -import com.google.gwt.user.client.rpc.IsSerializable; +import com.sap.sailing.gwt.ui.shared.dispatch.DTO; -public abstract class NewsEntryDTO implements IsSerializable { +public abstract class NewsEntryDTO implements DTO { private Date timestamp; From db44d1bc96bc7fdf3723a914505da7c4b65c119c Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 16 Jun 2015 07:29:02 +0000 Subject: [PATCH 103/117] Typo (launch --> lounge) --- wiki/505-worlds-kiel-2014.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki/505-worlds-kiel-2014.md b/wiki/505-worlds-kiel-2014.md index 0922c17e22b..33dec5d8d17 100644 --- a/wiki/505-worlds-kiel-2014.md +++ b/wiki/505-worlds-kiel-2014.md @@ -33,7 +33,7 @@ Event Page (newhome): http://505worlds2014.sapsailing.com/gwt/Home.html#EventPla ## Replication to Cube Server -At this event we operate a replica on our SAP Sail Cube server. The server is physically located behind the ground floor desk. With one of its network adapters it is hooked up to the lounge network, using a radio link from realTV. The second network adapter (Mainboard) is connected to the cube's network, allowing access from studio PCs to the cube server. This adapter is also the default route, providing the cube server, cube showroom and realTV with Internet access. As a backup it is possible to switch the default route to the launch. See `ip route show`. +At this event we operate a replica on our SAP Sail Cube server. The server is physically located behind the ground floor desk. With one of its network adapters it is hooked up to the lounge network, using a radio link from realTV. The second network adapter (Mainboard) is connected to the cube's network, allowing access from studio PCs to the cube server. This adapter is also the default route, providing the cube server, cube showroom and realTV with Internet access. As a backup it is possible to switch the default route to the lounge. See `ip route show`. The server runs a isc-dhcp-server, which requires all connected routers to NOT deliver a dhcp server. All required subnet config is in `/etc/dhcp/dhcpd.conf`. We have a /22 subnet for cube and a /24 subnet for the launch. BeTomorrow get static ips assigned by the dhcp through MAC-addresses, because their server always needs the same ip address. Futhermore the dhcp deploys our own DNS server here. For further description of the DNS setup read further. From 587641528772bdb29d4d5e410c36cf51e2b1c0c9 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 16 Jun 2015 07:33:12 +0000 Subject: [PATCH 104/117] More launch --> lounge replacements --- wiki/505-worlds-kiel-2014.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/505-worlds-kiel-2014.md b/wiki/505-worlds-kiel-2014.md index 33dec5d8d17..b65ed410dba 100644 --- a/wiki/505-worlds-kiel-2014.md +++ b/wiki/505-worlds-kiel-2014.md @@ -35,9 +35,9 @@ Event Page (newhome): http://505worlds2014.sapsailing.com/gwt/Home.html#EventPla At this event we operate a replica on our SAP Sail Cube server. The server is physically located behind the ground floor desk. With one of its network adapters it is hooked up to the lounge network, using a radio link from realTV. The second network adapter (Mainboard) is connected to the cube's network, allowing access from studio PCs to the cube server. This adapter is also the default route, providing the cube server, cube showroom and realTV with Internet access. As a backup it is possible to switch the default route to the lounge. See `ip route show`. -The server runs a isc-dhcp-server, which requires all connected routers to NOT deliver a dhcp server. All required subnet config is in `/etc/dhcp/dhcpd.conf`. We have a /22 subnet for cube and a /24 subnet for the launch. BeTomorrow get static ips assigned by the dhcp through MAC-addresses, because their server always needs the same ip address. Futhermore the dhcp deploys our own DNS server here. For further description of the DNS setup read further. +The server runs a isc-dhcp-server, which requires all connected routers to NOT deliver a dhcp server. All required subnet config is in `/etc/dhcp/dhcpd.conf`. We have a /22 subnet for cube and a /24 subnet for the lounge. BeTomorrow get static ips assigned by the dhcp through MAC-addresses, because their server always needs the same ip address. Futhermore the dhcp deploys our own DNS server here. For further description of the DNS setup read further. -The server also runs a bind9 DNS server which is set as the primary DNS for all lounge and cube PCs. All DNS requests are forwarded to a public DNS server except for requests for 505worlds2014.sapsailing.com for which the local DNS server returns the IP address of the cube server for the NIC through which the DNS request was received. For that two DNS zones are introduced, which match by the incoming IP range request. See `/etc/bind/named.conf.zones-cube` and `/etc/bind/named.conf.zones-launch` for definition of zone and forwarding. Take a look at `/etc/bind/zones/505sapsailing.cube.db` and `/etc/bind/zones/505sapsailing.sailing.db` for the nameserver entries for the zone. The result is, that if a request comes from the launch network, the domain is resolved to the ip the cube server has in this subnet and also if the request comes from the cube, it returns the ip in the subnet of the cube. +The server also runs a bind9 DNS server which is set as the primary DNS for all lounge and cube PCs. All DNS requests are forwarded to a public DNS server except for requests for 505worlds2014.sapsailing.com for which the local DNS server returns the IP address of the cube server for the NIC through which the DNS request was received. For that two DNS zones are introduced, which match by the incoming IP range request. See `/etc/bind/named.conf.zones-cube` and `/etc/bind/named.conf.zones-launch` for definition of zone and forwarding. Take a look at `/etc/bind/zones/505sapsailing.cube.db` and `/etc/bind/zones/505sapsailing.sailing.db` for the nameserver entries for the zone. The result is, that if a request comes from the lounge network, the domain is resolved to the ip the cube server has in this subnet and also if the request comes from the cube, it returns the ip in the subnet of the cube. As described in bug2204 wind data and API are not served through the replica, so BeTomorrow has to go to our main server. For that i introduced a subsubdomain `btmw.505worlds2014.sapsailing.com` which points to `sapsailing.com` and answers with our main active server of the event. On the cube server we run a replica server instance as user `sailing` under the usual directory set-up (`/home/sailing/servers/server`). The `env.sh` file uses a configuration that lets the server start replicating when launched. The two possible master servers (A / B) are specified in two lines defining `REPLICATE_MASTER_SERVLET_HOST`, one is commented, the other one active. From 184a4762707af7776526a6a16cf5f93b17e499a1 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 16 Jun 2015 07:43:13 +0000 Subject: [PATCH 105/117] Fixed some Wiki typos --- wiki/505-worlds-kiel-2014.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/505-worlds-kiel-2014.md b/wiki/505-worlds-kiel-2014.md index b65ed410dba..3593fe11b09 100644 --- a/wiki/505-worlds-kiel-2014.md +++ b/wiki/505-worlds-kiel-2014.md @@ -38,11 +38,11 @@ At this event we operate a replica on our SAP Sail Cube server. The server is ph The server runs a isc-dhcp-server, which requires all connected routers to NOT deliver a dhcp server. All required subnet config is in `/etc/dhcp/dhcpd.conf`. We have a /22 subnet for cube and a /24 subnet for the lounge. BeTomorrow get static ips assigned by the dhcp through MAC-addresses, because their server always needs the same ip address. Futhermore the dhcp deploys our own DNS server here. For further description of the DNS setup read further. The server also runs a bind9 DNS server which is set as the primary DNS for all lounge and cube PCs. All DNS requests are forwarded to a public DNS server except for requests for 505worlds2014.sapsailing.com for which the local DNS server returns the IP address of the cube server for the NIC through which the DNS request was received. For that two DNS zones are introduced, which match by the incoming IP range request. See `/etc/bind/named.conf.zones-cube` and `/etc/bind/named.conf.zones-launch` for definition of zone and forwarding. Take a look at `/etc/bind/zones/505sapsailing.cube.db` and `/etc/bind/zones/505sapsailing.sailing.db` for the nameserver entries for the zone. The result is, that if a request comes from the lounge network, the domain is resolved to the ip the cube server has in this subnet and also if the request comes from the cube, it returns the ip in the subnet of the cube. -As described in bug2204 wind data and API are not served through the replica, so BeTomorrow has to go to our main server. For that i introduced a subsubdomain `btmw.505worlds2014.sapsailing.com` which points to `sapsailing.com` and answers with our main active server of the event. +As described in bug2204 wind data and API are not served through the replica, so BeTomorrow has to go to our main server. For that I introduced a subsubdomain `btmw.505worlds2014.sapsailing.com` which points to `sapsailing.com` and answers with our main active server of the event. On the cube server we run a replica server instance as user `sailing` under the usual directory set-up (`/home/sailing/servers/server`). The `env.sh` file uses a configuration that lets the server start replicating when launched. The two possible master servers (A / B) are specified in two lines defining `REPLICATE_MASTER_SERVLET_HOST`, one is commented, the other one active. -When switching from the A server to the B server or vice versa, the replica needs to be re-configured. Before stopping it, connected clients need to be re-directed to the master when they hit 505worlds2014.sapsailing.com. This is achieved by re-configuring the Apache server running on the replica, as user `root`, editing `/etc/apache2/sites-enabled/001-events.conf` and activating the line for `505worlds2014.sapsailing.com` that points to the IP address of the new active server, then invoking `/etc/init.d/apache2 reload`. Once this is done, the running replica should cleanly stop replication (using the `Replication` tab in the AdminConsole), then stopping the instance (as user `sailing` run `/home/sailing/servers/server/stop`). Then, in `env.sh` the `REPLICATE_MASTER_SERVLET_HOST` variable needs to be set to point to the new master. After that, the replica Java instance can be launched using `/home/sailing/servers/server/start`). Before re-activating it is important that the rabbit initial load is done. So please watch eather `/home/sailing/servers/server/logs/sailing0.log.0` or the Rabbit Webinterface on `http://54.246.250.138:15672/#/queues`. Please deleted eventually displayed old queues (be sure not to remove the correct replicating queue!). Re-configure Apache again by editing `/etc/apache2/sites-enabled/001-events.conf` again, re-activating the record that lets 505worlds2014.sapsailing.com point to the replica. From this point on, clients in the lounge and the Cube will instantly be directed to the cube server again when hitting the replica server's Apache with a URL starting with `505worlds2014.sapsailing.com`. You can check this by example checking the load with `htop` or `apachetop`. +When switching from the A server to the B server or vice versa, the replica needs to be re-configured. Before stopping it, connected clients need to be re-directed to the master when they hit 505worlds2014.sapsailing.com. This is achieved by re-configuring the Apache server running on the replica, as user `root`, editing `/etc/apache2/sites-enabled/001-events.conf` and activating the line for `505worlds2014.sapsailing.com` that points to the IP address of the new active server, then invoking `/etc/init.d/apache2 reload`. Once this is done, the running replica should cleanly stop replication (using the `Replication` tab in the AdminConsole), then stopping the instance (as user `sailing` run `/home/sailing/servers/server/stop`). Then, in `env.sh` the `REPLICATE_MASTER_SERVLET_HOST` variable needs to be set to point to the new master. After that, the replica Java instance can be launched using `/home/sailing/servers/server/start`). Before re-activating it is important that the rabbit initial load is done. So please watch either `/home/sailing/servers/server/logs/sailing0.log.0` or the Rabbit Webinterface on `http://54.246.250.138:15672/#/queues`. Please deleted eventually displayed old queues (be sure not to remove the correct replicating queue!). Re-configure Apache again by editing `/etc/apache2/sites-enabled/001-events.conf` again, re-activating the record that lets 505worlds2014.sapsailing.com point to the replica. From this point on, clients in the lounge and the Cube will instantly be directed to the cube server again when hitting the replica server's Apache with a URL starting with `505worlds2014.sapsailing.com`. You can check this by example checking the load with `htop` or `apachetop`. ## Switching Servers From fc4dbd7913de78e6b273a461c0e8a13b39cfbb15 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 16 Jun 2015 13:09:52 +0200 Subject: [PATCH 106/117] News Box is only added for live events --- .../tabs/MultiregattaOverviewTabView.java | 5 +-- .../event/overview/EventOverviewStage.java | 32 +++++++++++++------ .../event/overview/EventOverviewStage.ui.xml | 2 +- .../regatta/tabs/RegattaOverviewTabView.java | 7 +--- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java index ab6ce85375d..5c6144acb4d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/multiregatta/tabs/MultiregattaOverviewTabView.java @@ -23,8 +23,6 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshMa import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; -import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewNewsAction; -import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetLiveRacesForEventAction; import com.sap.sse.common.Util.Triple; @@ -63,8 +61,7 @@ public class MultiregattaOverviewTabView extends Composite implements Multiregat RefreshManager refreshManager = new RefreshManager(this, currentPresenter.getDispatch()); - refreshManager.add(stage, new GetEventOverviewStageAction(currentPresenter.getCtx().getEventDTO().getId())); - refreshManager.add(stage.getNewsRefreshable(), new GetEventOverviewNewsAction(currentPresenter.getCtx().getEventDTO().getId())); + stage.setupRefresh(refreshManager); refreshManager.add(racesListLive, new GetLiveRacesForEventAction(currentPresenter.getCtx().getEventDTO().getId())); contentArea.setWidget(this); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java index 5cee021c6f4..9bb68ed395a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.java @@ -17,16 +17,26 @@ import com.sap.sailing.gwt.home.client.place.event.partials.countdown.Countdown; import com.sap.sailing.gwt.home.client.place.event.partials.message.Message; import com.sap.sailing.gwt.home.client.place.event.partials.updatesBox.UpdatesBox; import com.sap.sailing.gwt.home.client.place.event.partials.video.Video; +import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshManager; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshableWidget; import com.sap.sailing.gwt.ui.shared.dispatch.ListResult; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageContentDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewStageDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewTickerStageDTO; import com.sap.sailing.gwt.ui.shared.dispatch.event.EventOverviewVideoStageDTO; +import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewNewsAction; +import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.general.EventState; -public class EventOverviewStage extends Composite implements RefreshableWidget { +public class EventOverviewStage extends Composite { + private final RefreshableWidget refreshable = new RefreshableWidget() { + @Override + public void setData(EventOverviewStageDTO data, long nextUpdate, int updateNo) { + setStageData(data); + } + }; private final RefreshableWidget> newsRefreshable = new RefreshableWidget>() { @Override public void setData(ListResult data, long nextUpdate, int updateNo) { @@ -55,12 +65,20 @@ public class EventOverviewStage extends Composite implements RefreshableWidget news) { if(lastContent == null) { - setData(new EventOverviewStageDTO(null, new EventOverviewTickerStageDTO(null, null, null)), 0, 0); + setStageData(new EventOverviewStageDTO(null, new EventOverviewTickerStageDTO(null, null, null))); } if(news.isEmpty()) { @@ -96,8 +114,4 @@ public class EventOverviewStage extends Composite implements RefreshableWidget> getNewsRefreshable() { - return newsRefreshable; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml index 1bc987b11e8..7902ce2899d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml @@ -8,7 +8,7 @@
    -
    +
    diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java index eaf84a9a789..f639c97ab56 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java @@ -13,8 +13,6 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.EventRegattaView; import com.sap.sailing.gwt.home.client.place.event.regatta.EventRegattaView.Presenter; import com.sap.sailing.gwt.home.client.place.event.regatta.RegattaTabView; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshManager; -import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewNewsAction; -import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetLiveRacesForRegattaAction; /** @@ -47,12 +45,9 @@ public class RegattaOverviewTabView extends Composite implements RegattaTabView< initWidget(ourUiBinder.createAndBindUi(this)); - // TODO CF RefreshManager refreshManager = new RefreshManager(this, currentPresenter.getDispatch()); - // TODO regatta specific depending on event type - refreshManager.add(stage, new GetEventOverviewStageAction(currentPresenter.getCtx().getEventDTO().getId())); - refreshManager.add(stage.getNewsRefreshable(), new GetEventOverviewNewsAction(currentPresenter.getCtx().getEventDTO().getId())); + stage.setupRefresh(refreshManager); refreshManager.add(racesListLive, new GetLiveRacesForRegattaAction(currentPresenter.getCtx().getEventDTO() .getId(), currentPresenter.getCtx().getRegattaId())); From 8fe099d7d9e24dd1cd89f673314f37e28ca5af96 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 16 Jun 2015 13:34:48 +0200 Subject: [PATCH 107/117] improved storage of migration event domain objects --- .../persistence/DomainObjectFactory.java | 3 +- .../impl/DomainObjectFactoryImpl.java | 9 +++--- .../server/impl/RacingEventServiceImpl.java | 32 +++++++++---------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java index e524246e193..a117994d7a8 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java @@ -29,6 +29,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sse.common.Util.Pair; /** * Offers methods to load domain objects from a Mongo DB @@ -97,7 +98,7 @@ public interface DomainObjectFactory { Event loadEvent(String name); - Iterable loadAllEvents(); + Iterable> loadAllEvents(); /** * The {@link MongoObjectFactory#storeEvent(Event)} method stores events and their links to leaderboard groups. diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 444b11d07c1..414c80b9148 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -186,6 +186,7 @@ import com.sap.sse.common.TimeRange; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Triple; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; @@ -972,15 +973,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } @Override - public Iterable loadAllEvents() { - ArrayList result = new ArrayList(); + public Iterable> loadAllEvents() { + ArrayList> result = new ArrayList<>(); DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); try { for (DBObject object : eventCollection.find()) { Event event = loadEvent(object); - loadLegacyImageAndVideoURLs(event, object); - result.add(event); + Boolean requiresStoreAfterMigration = loadLegacyImageAndVideoURLs(event, object); + result.add(new Pair(event, requiresStoreAfterMigration)); } } catch (Exception e) { logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load events."); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index b2eb96a0b9d..dd38e8ea84a 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -207,6 +207,7 @@ import com.sap.sse.BuildVersion; import com.sap.sse.common.TimePoint; import com.sap.sse.common.TypeBasedServiceFinderFactory; 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.media.ImageDescriptor; import com.sap.sse.common.media.VideoDescriptor; @@ -540,15 +541,23 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes // This is more for debugging purposes than for anything else. addFlexibleLeaderboard(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME, null, new int[] { 5, 8 }, getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), null); - loadStoredEvents(); + + final Iterable> loadedEventsWithRequireStoreFlag = loadStoredEvents(); loadStoredRegattas(); loadRaceIDToRegattaAssociations(); loadStoredLeaderboardsAndGroups(); loadLinksFromEventsToLeaderboardGroups(); - storeLoadedEvents(); loadMediaLibary(); loadStoredDeviceConfigurations(); loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh(); + + // Stores all events which run through a data migration + // Remark: must be called after loadLinksFromEventsToLeaderboardGroups(), otherwise would loose the Event -> LeaderboardGroup relation + for (Pair eventAndRequireStoreFlag : loadedEventsWithRequireStoreFlag) { + if (eventAndRequireStoreFlag.getB()) { + mongoObjectFactory.storeEvent(eventAndRequireStoreFlag.getA()); + } + } } @Override @@ -635,23 +644,14 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } } - private void loadStoredEvents() { - for (Event event : domainObjectFactory.loadAllEvents()) { + private Iterable> loadStoredEvents() { + Iterable> loadedEventsWithRequireStoreFlag = domainObjectFactory.loadAllEvents(); + for (Pair eventAndFlag : loadedEventsWithRequireStoreFlag) { + Event event = eventAndFlag.getA(); if (event.getId() != null) eventsById.put(event.getId(), event); } - } - - /** - * Stores all events directly after loading them. - * This is a workaround for a problem with event migration code which requires storing an event after some changes. - * Because not all event data is stored in the event collection (e.g. LeaderboardGroup -> Event relation) the storeEvent - * method must be called AFTER the event object is fully initialized. - */ - private void storeLoadedEvents() { - for(Event event: eventsById.values()) { - mongoObjectFactory.storeEvent(event); - } + return loadedEventsWithRequireStoreFlag; } private void loadLinksFromEventsToLeaderboardGroups() { From 3843719f1ea1b597a8e624f407e17ecc2e9b038f Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 16 Jun 2015 14:58:21 +0200 Subject: [PATCH 108/117] fixed live race state view for races with state 'general recall' --- .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 2 +- .../gwt/ui/shared/dispatch/event/LiveRaceCalculator.java | 2 +- .../sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java | 4 +++- .../com/sap/sailing/gwt/ui/shared/race/RaceMetadataDTO.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 3db284c2c85..d5abb720db9 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1255,7 +1255,7 @@ analyseRace=Analyse race nextRaceStartingIn=Next race starts in startingIn={0} starts in raceIsPlanned=Planned -raceIsCanceled=Canceled +raceIsCanceled=Abandoned raceIsPostponed=Postponed startingInMinutes=Starts in {0,number} min startingInMinutes[none]=Starting now diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/LiveRaceCalculator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/LiveRaceCalculator.java index 0c80b501c19..ca29f22a07b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/LiveRaceCalculator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/LiveRaceCalculator.java @@ -23,7 +23,7 @@ final class LiveRaceCalculator implements RaceCallback { } else if(race.getViewState() == RaceViewState.SCHEDULED) { int timeTillRace = (int) MillisecondsTimePoint.now().until(new MillisecondsTimePoint(race.getStart())).asMillis(); ttl = Math.min(ttl, Math.min(1000 * 60, timeTillRace)); - } else if(race.getViewState() == RaceViewState.POSTPONED || race.getViewState() == RaceViewState.CANCELED) { + } else if(race.getViewState() == RaceViewState.POSTPONED || race.getViewState() == RaceViewState.ABANDONED) { ttl = Math.min(ttl, 1000 * 60); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index 11f26dcd2ae..71fd6f51aa0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -355,7 +355,9 @@ public class RaceContext { if(upperFlag.equals(Flags.AP)) { raceState = RaceViewState.POSTPONED; } else if(upperFlag.equals(Flags.NOVEMBER)) { - raceState = RaceViewState.CANCELED; + raceState = RaceViewState.ABANDONED; + } else if(upperFlag.equals(Flags.FIRSTSUBSTITUTE)) { + raceState = RaceViewState.ABANDONED; } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/race/RaceMetadataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/race/RaceMetadataDTO.java index d168b244d0d..41c49440dc7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/race/RaceMetadataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/race/RaceMetadataDTO.java @@ -38,7 +38,7 @@ public class RaceMetadataDTO implements IsSerializable { return StringMessages.INSTANCE.raceIsPostponed(); } }, - CANCELED { // the running racing has been canceled + ABANDONED { // the running racing has been abandoned @Override public String getLabel() { return StringMessages.INSTANCE.raceIsCanceled(); From 2893bb8e389443ecc5795c9fd059ff262c894c48 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:21:02 +0000 Subject: [PATCH 109/117] new wiki entry for setting up a local network with routers and replica at an event --- event-network-with-replica.md | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 event-network-with-replica.md diff --git a/event-network-with-replica.md b/event-network-with-replica.md new file mode 100644 index 00000000000..84a63d06147 --- /dev/null +++ b/event-network-with-replica.md @@ -0,0 +1,101 @@ +# Setup local area network for an Sailing Event + +## Hardware +- Cisco Meraki MX60W +- Sail Cube Server (2HE, Xeon E3-12XXv2, 32GB RAM, 120GB SSD) + +## Software +- Setup router through https://dashboard.meraki.com (get access from Axel, Frank or Steffen) +- Server OS: Debian Wheezy + +## Scenarios +### Standard FritzBox / ... network +If you have a given network setup (without own router) I would suggest the following solution: +The server has three network adapters to connect to multiple networks at the same time (e.g. Cube and Lounge,..). You could simply integrate the server into all networks and set up a static ip on each of the networks for the server. then simply configure the sailing instance to listen on all interfaces and that should be it. You could additionally use the replica's DNS server to also overwrite `event.sapsailing.com` URL's but therefore you need to tell each router of the network to server the replica as DNS server to other LAN clients. + +### Single WAN uplink (Meraki) +- Create 3 VLAN's with (VLAN-ID 10=>ADMIN,20=>CUBE,30=>GUEST) +- Link VLAN's with physical ports on the router +- Create 3 WLAN SSID's and link each with a VLAN +- Create a splash page for guest wifi (Security appliance->Access control and Splash page) +- Create traffic shaping rules / policies to limit bandwidth on each of the VLAN's + * give Cube network about 1600Kb/s down and 500Kb/s up + * make Admin network unlimited + * set guest network limit to 200Kb/s up and down +- Set up DHCP section to your desire + * e.g. deploy replica server IP as DNS server for Cube network + * give importand servers (replica, TriCaster, beTomorrow server a static ip lease in Cube network) => MAC's needed +- Create firewall rules to restrict access to special services (e.g. ssh on replica server) +- If needed create a Client VPN Server and choose a free subnet for it (L2TP over IPSec) + +### Dual WAN uplink (Meraki) +`not yet tested, but possible` + +### Dual WAN uplink (Meraki) with mobile LTE +`not yet tested, but possible` + +## Prepare Replica Server +### Physically +The server is localted behind the ground floor desk in the 19" cabinet. The router could be set up in the same place, so that a physical link can be established from server to router (short ways for better latency). + +### Services & configs +- runs `bind9`, `apache2`, `isc-dhcp-server` (default: off), 2x `sailing instances` +- apache2: `/etc/apache2/sites-enabled/{001-event.conf, 000-main.conf, 000-macros.conf}` +- bind9: + - `/etc/bind/named.conf.*` for client matching and zone forwarding + - `/etc/bind/zones/*` for the different nameserver zones +- isc-dhcp-server + - default `chkconfig off` + - only needed if you want the replica to operate as kind of router (e.g. turn off dhcp and dns from FritzBox) + - prepared configs: `/etc/dhcp/dhcpd.conf` + - 1x /22 network for cube (with static MAC/IP mappings for some clients) + - 1x /24 network for SAP-lounge setup +- user: sailing => `/home/sailing/servers/{servers,test}` +- Maven: ready to build code under `/home/sailing/code/` + +### Hostnames +- the replica should be available as `sailing-demo.sapsailing.com` from every local network +- the replica should be available as `event.sapsailing.com` from the desired network where replica should operate instead of EC2 instance + +### Set up replication with dns and apache + +The server runs a bind9 DNS server which is set as the primary DNS for the meraki networks which should server the replica instead of the event EC2 instance. + +Other then the event EC2 instance DNS requests are forwarded to a public DNS server (8.8.8.8). For the event server which should be locally replaced by the replica, e.g. 505worlds2014.sapsailing.com, the local DNS server returns the IP address of the cube server for the NIC through which the DNS request was received (this is received through client-matching). + +For that three DNS zones are introduced, which match by the incoming IP range request (choose what you need here, depending on the local setup!). See `/etc/bind/named.conf.zones-cube`, `/etc/bind/named.conf.zones-launch` and `/etc/bind/named.conf.zones-admin` for definition of zones and forwarding. + +Take a look at `/etc/bind/zones/kwsapsailing.cube.db` and `/etc/bind/zones/kwsapsailing.admin.db` for the nameserver entries for the zone. The result is, that if a request comes from the lounge network, the domain is resolved to the ip the cube server has in this subnet and also if the request comes from the cube, it returns the ip in the subnet of the cube. + +It depends on the network setup if you need this client matching or not. The Meraki supports inter-VLAN Routing, which leads to no need to multiple IP adresses for the replica server. Instead put the replica server into one of the networks and then restrict access through firewall rules. Furthermore just setup a single dns zone (e.g. `/etc/bind/named.conf.zones-cube` in which everything is maintained. + +As described in bug2204 wind data and API are not served through the replica, so BeTomorrow has to go to our main server. For that I introduced a subsubdomain `btmw.event.sapsailing.com` which points to `sapsailing.com` and answers with our main active server of the event. This has to be clarified if we need this or if the replica operates correctly and servers everything as RESTlets.. + +On the cube server we run a replica server instance as user `sailing` under the usual directory set-up (`/home/sailing/servers/server`). The `env.sh` file uses a configuration that lets the server start replicating when launched. The two possible master servers (A / B) are specified in two lines defining `REPLICATE_MASTER_SERVLET_HOST`, one is commented, the other one active. + +I have also prepared a second sailing instance as user `sailing` under the usual directory set-up (`/home/sailing/servers/test`) which could also be used to switch between to local instances if needed. + +When switching from the A server to the B server or vice versa, the replica needs to be re-configured. Before stopping it, connected clients need to be re-directed to the master when they hit `event.sapsailing.com`. This is achieved by re-configuring the Apache server running on the replica, as user `root`, editing `/etc/apache2/sites-enabled/001-events.conf` and activating the line for `event.sapsailing.com` that points to the IP address of the new active server, then invoking `/etc/init.d/apache2 reload`. Once this is done, the running replica should cleanly stop replication (using the `Replication` tab in the AdminConsole), then stopping the instance (as user `sailing` run `/home/sailing/servers/server/stop`). Then, in `env.sh` the `REPLICATE_MASTER_SERVLET_HOST` variable needs to be set to point to the new master. After that, the replica Java instance can be launched using `/home/sailing/servers/server/start`). Before re-activating it is important that the rabbit initial load is done. So please watch either `/home/sailing/servers/server/logs/sailing0.log.0` or the Rabbit Webinterface on `http://RABBIT-MQ-SERVER:15672/#/queues`. +Please deleted eventually displayed old queues (be sure not to remove the correct replicating queue!). Re-configure Apache again by editing `/etc/apache2/sites-enabled/001-events.conf` again, re-activating the record that lets event.sapsailing.com point to the replica. From this point on, clients in the Lounge, Cube and eventual other networks will instantly be directed (without connection loss!) to the cube server again when hitting the replica server's Apache with a URL starting with `event.sapsailing.com`. + +### Monitor the server +- You can check the load with `htop` +- You can check the accesses to apache with `apachetop` or you go to `http://sailing-demo.sapsailing.com/server-status`page to display the http status +- You can check the system temperature (depending on local environment may be important!) with `sensors` command + +### Switching Servers + +For maximum availability we normally have at least two EC2 servers reserved for a bigger event (e.g. building new releases in parallel and then switching, or with ELB). We can prepare the other server by installing a release, either by using the `refreshInstance.sh` script or by using `tmux attach` to go to a console and fetching from git and building and installing there. When done, fire up the server and load all races required. Test the server reasonably well. + +Then switch the cube server replica to point to the new server. This process is described above. + +Then, log on as `root` on `sapsailing.com`, go to `/etc/httpd/conf.d` and edit `001-events.conf` to update the event-related URLs. By convention, the inactive server URLs are suffixed with `-a` or `-b` name, respectively. When done editing, run `/etc/init.d/httpd reload` which will update the Apache configuration so that from that point on requests to `event.sapsailing.com` will go to the new server. Convince yourself by looking at the logs under `/home/sailing/servers/server/logs/sailing0.log.0` that the correct server is now active. Afterwards, stop the old server's Java instance. + +### Local builds on replica +- verify on which branch you are inside `/home/sailing/code/` with `git status` +- do a `git fetch` / `git pull` +- eventually switch branches for a new build with `git co branch` +- eventually merge other stuff to that branch `git merge origin/branch` +- start doing a maven build with `./configuration/buildAndUpdateProduct.sh -t build` +- after build is **SUCCESSFULLY FINISHED** install build with `./configuration/buildAndUpdateProduct.sh -s server install` +- now you are able to stop and start sailing instance (be careful with correct replication handling -> see above) From 0516db68889181f59445f60886f6a9185b7acd66 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:24:09 +0000 Subject: [PATCH 110/117] inserted link to replication and network howto --- home.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/home.md b/home.md index 54d69649deb..0278cc2d5ef 100644 --- a/home.md +++ b/home.md @@ -57,6 +57,7 @@ SAP is at the center of today’s technology revolution, developing innovations * [[Create clickable UI prototypes with Axure|wiki/ui-clickable-prototypes]] * [[Uploading Media Content|wiki/uploading-media-content]] * Information for Event Managers + * [[Set up local network with replication server|event-network-with-replica]] * [[Operating Igtimi WindBots/windbot-operations]] * [[Linking Race Videos|wiki/linking-race-videos]] * [[Import official results|wiki/results-import]] @@ -66,6 +67,7 @@ SAP is at the center of today’s technology revolution, developing innovations * [[Information about Extreme Sailing Series|wiki/extreme-sailing-series]] * [[Travemünder Woche 2014 event page|wiki/tw2014]] * [[505 worlds Kiel 2014 event page|wiki/505-worlds-kiel-2014]] + * [[Kieler Woche event page|kieler-woche-2015]] ### Internal services (not related to wiki but useful) From 26415a83fbae1a1f46b345cfc50d530632f0892e Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:24:58 +0000 Subject: [PATCH 111/117] updated kieler woche event link --- home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home.md b/home.md index 0278cc2d5ef..230e3a8e111 100644 --- a/home.md +++ b/home.md @@ -67,7 +67,7 @@ SAP is at the center of today’s technology revolution, developing innovations * [[Information about Extreme Sailing Series|wiki/extreme-sailing-series]] * [[Travemünder Woche 2014 event page|wiki/tw2014]] * [[505 worlds Kiel 2014 event page|wiki/505-worlds-kiel-2014]] - * [[Kieler Woche event page|kieler-woche-2015]] + * [[Kieler Woche event page|wiki/kieler-woche-2015]] ### Internal services (not related to wiki but useful) From 0e67992045558a2752487b5e5b351ef975b41fc1 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:26:10 +0000 Subject: [PATCH 112/117] Renamed event-network-with-replica to /wiki/event-network-with-replica --- .../event-network-with-replica.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename event-network-with-replica.md => wiki/event-network-with-replica.md (100%) diff --git a/event-network-with-replica.md b/wiki/event-network-with-replica.md similarity index 100% rename from event-network-with-replica.md rename to wiki/event-network-with-replica.md From 5032d898e3d1211724240001b7b4a11a8effa1c3 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:27:18 +0000 Subject: [PATCH 113/117] updated network wiki link --- home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home.md b/home.md index 230e3a8e111..f6fca6bdba8 100644 --- a/home.md +++ b/home.md @@ -57,7 +57,7 @@ SAP is at the center of today’s technology revolution, developing innovations * [[Create clickable UI prototypes with Axure|wiki/ui-clickable-prototypes]] * [[Uploading Media Content|wiki/uploading-media-content]] * Information for Event Managers - * [[Set up local network with replication server|event-network-with-replica]] + * [[Set up local network with replication server|wiki/event-network-with-replica]] * [[Operating Igtimi WindBots/windbot-operations]] * [[Linking Race Videos|wiki/linking-race-videos]] * [[Import official results|wiki/results-import]] From 379d2ee1ee0573a2edef68535a6b1b11922d6f13 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:39:20 +0000 Subject: [PATCH 114/117] Created kieler woche 2015 event wiki page --- wiki/kieler-woche-2015.md | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 wiki/kieler-woche-2015.md diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md new file mode 100644 index 00000000000..d35c5012a2a --- /dev/null +++ b/wiki/kieler-woche-2015.md @@ -0,0 +1,40 @@ +# Kieler Woche 2015 + +## Server Landscape + +We run four servers for the event: +- on EC2: **Master**, **Replika 1** and **2**, +- locally: **Cube-Server** + +For fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `XXX` and the git tag used to build a release for it is called `XXX-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX-release/, respectively, for their Hudson jobs. + +### Master Server +- Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html +- External IP: 54.154.151.10 +- Internal IP: 172.31.24.187 + +### Replika 1 server +- Admin Console at http://ec2-54-72-226-124.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html +- External IP: 54.72.226.124 +- Internal IP: 172.31.20.11 + +### Replika 2 server +- Admin Console at http://ec2-54-154-175-180.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html +- External IP: 54.154.175.180 +- Internal IP: 172.31.20.12 + +## TracTrac URL +- http://xxx.traclive.dk/events/event_xxx/jsonservice.php + +## Replication +- RabbitMQ server for replication: 52.16.112.6 (Web: http://52.16.112.6:15672/) +- Replication Exchange Name: KW2015 + +## Other links +- Regatta Overview: http://kielerwoche2015ro.sapsailing.com +- Manage2Sail Event URL: http://manage2sail.com/api/public/links/event/ID?accesstoken=TOKEN&mediaType=json + +## Local network setup +basically see [[Set up local network with replication server|wiki/event-network-with-replica]] operating with a Meraki and a local replica server using 1 physical WAN interface on the Meraki. Meraki network config for this event can be found under [[Meraki Dashboard|https://n142.meraki.com/KiWo-TraWo/n/Rzu9tdoc]] + +- Accessing replica server from `sailing-demo.sapsailing.com`via ssh or http from `ADMIN` network \ No newline at end of file From b9e866b43c675537296bfc690f46a91547668226 Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:55:19 +0000 Subject: [PATCH 115/117] inserted ELB into server landscape --- wiki/kieler-woche-2015.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md index d35c5012a2a..b4272750ec3 100644 --- a/wiki/kieler-woche-2015.md +++ b/wiki/kieler-woche-2015.md @@ -3,7 +3,7 @@ ## Server Landscape We run four servers for the event: -- on EC2: **Master**, **Replika 1** and **2**, +- on EC2: **Master**, **Replika 1** and **2** with an **ELB** in front, - locally: **Cube-Server** For fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `XXX` and the git tag used to build a release for it is called `XXX-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX-release/, respectively, for their Hudson jobs. From 0a4e7cbdc39dff11b4b2153ae6bc890cf176235c Mon Sep 17 00:00:00 2001 From: Steffen Tobias Wagner Date: Tue, 16 Jun 2015 13:59:54 +0000 Subject: [PATCH 116/117] inserted git branch for kw2015 --- wiki/kieler-woche-2015.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md index b4272750ec3..54afdcc9d74 100644 --- a/wiki/kieler-woche-2015.md +++ b/wiki/kieler-woche-2015.md @@ -6,7 +6,7 @@ We run four servers for the event: - on EC2: **Master**, **Replika 1** and **2** with an **ELB** in front, - locally: **Cube-Server** -For fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `XXX` and the git tag used to build a release for it is called `XXX-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX-release/, respectively, for their Hudson jobs. +For fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `XXX-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX-release/, respectively, for their Hudson jobs. ### Master Server - Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html From 732d45c1befa9e05fcfcc93abb78c84f74d6a2e9 Mon Sep 17 00:00:00 2001 From: fmittag Date: Tue, 16 Jun 2015 22:04:03 +0200 Subject: [PATCH 117/117] added another alternative name for the 2.4mR boat class --- .../src/com/sap/sailing/domain/common/BoatClassMasterdata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java index 7834eeb525c..1d30e8dee86 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java @@ -4,7 +4,7 @@ import com.sap.sailing.domain.common.impl.MeterDistance; public enum BoatClassMasterdata { - _2_4M ("2.4 Meter", true, 4.11, 0.81, BoatHullType.MONOHULL, false, "2.4M", "2.4mR"), + _2_4M ("2.4 Meter", true, 4.11, 0.81, BoatHullType.MONOHULL, false, "2.4M", "2.4mR", "2.4 Metre"), _5O5 ("5O5", true, 5.03, 1.88, BoatHullType.MONOHULL, true, "505", "5o5", "505er", "5o5er"), _12M ("12 Meter", true, 5.97, 1.43, BoatHullType.MONOHULL, true, "12M", "12mR", "12SQM"), _29ER ("29er", true, 4.45, 1.70, BoatHullType.MONOHULL, true),