mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-15 06:49:56 +00:00
Merge branch '60_inch' into 60_inch_bug4100
# Conflicts: # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
This commit is contained in:
commit
e8ced96f26
35 files changed
+339
-171
No files matched your search
+1
-1
@@ -528,7 +528,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
logger.info("Couldn't find regatta "+regattaName+" for corresponding regatta leaderboard. Not loading regatta leaderboard.");
|
||||
} else {
|
||||
result = new RegattaLeaderboardImpl(regatta, resultDiscardingRule);
|
||||
result.setName(leaderboardName);
|
||||
result.setName(leaderboardName); // this will temporarily set the display name; it will be adjusted later if a display name is found
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+9
-28
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -11,17 +10,10 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
import com.google.zxing.WriterException;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LastEventOfTypeFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
@@ -73,7 +65,9 @@ import com.sap.sse.common.mail.MailException;
|
||||
import com.sap.sse.common.media.MediaTagConstants;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.qrcode.QRCodeGenerationUtil;
|
||||
import com.sap.sse.mail.QRCodeMimeBodyPartSupplier;
|
||||
import com.sap.sse.mail.SerializableDefaultMimeBodyPartSupplier;
|
||||
import com.sap.sse.mail.SerializableMultipartSupplier;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.util.impl.NonGwtUrlHelper;
|
||||
|
||||
@@ -322,9 +316,6 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
|
||||
String subject = String.format("%s %s", B.get(locale, "trackingInvitationFor"), invitee);
|
||||
|
||||
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
|
||||
BodyPart messageTextPart = new MimeBodyPart();
|
||||
|
||||
boolean hasIOSAppUrl = iOSAppUrl != null && !iOSAppUrl.isEmpty();
|
||||
boolean hasAndroidAppUrl = androidAppUrl != null && !androidAppUrl.isEmpty();
|
||||
boolean hasLogoUrl = logoUrl != null && !logoUrl.isEmpty();
|
||||
@@ -373,26 +364,16 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
htmlText.append("</html>");
|
||||
|
||||
try {
|
||||
messageTextPart.setContent(htmlText.toString(), "text/html");
|
||||
|
||||
BodyPart messageImagePart = new MimeBodyPart();
|
||||
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
|
||||
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "<image>");
|
||||
messageImagePart.setHeader("Content-Disposition", "inline;filename=\"qr.png\"");
|
||||
|
||||
MimeMultipart multipart = new MimeMultipart();
|
||||
multipart.addBodyPart(messageTextPart);
|
||||
multipart.addBodyPart(messageImagePart);
|
||||
|
||||
getMailService().sendMail(toAddress, subject, multipart);
|
||||
} catch (MessagingException | MailException | WriterException | IOException e) {
|
||||
final SerializableMultipartSupplier multipartSupplier = new SerializableMultipartSupplier("Invite",
|
||||
new SerializableDefaultMimeBodyPartSupplier(htmlText.toString(), "text/html"),
|
||||
new QRCodeMimeBodyPartSupplier(url));
|
||||
getMailService().sendMail(toAddress, subject, multipartSupplier);
|
||||
} catch (MessagingException | MailException | IOException e) {
|
||||
logger.log(Level.SEVERE, "Error trying to send mail to " + invitee + " with e-mail address " + toAddress, e);
|
||||
throw new MailException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
|
||||
String emails, String iOSAppUrl, String androidAppUrl, Locale locale) throws MailException {
|
||||
|
||||
-11
@@ -5,7 +5,6 @@ import static org.hamcrest.core.IsNull.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
@@ -53,14 +52,4 @@ public class DomainFactoryTest {
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode.UNKNOWN));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testCompetitorLookup() throws Exception {
|
||||
before();
|
||||
|
||||
// swissTimingDomainFactory.getOrCreateCompetitor(boatID, threeLetterIOCCode, name, boatClass);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-2
@@ -41,7 +41,6 @@ public class SwissTimingRaceConfigurationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("According to Radek Masnica ('masnica.r@st-software.com') the OTA stuff may not be supported any longer by the SwissTiming Leipzip lab... 2017-05-19")
|
||||
@Test
|
||||
public void testRaceConfig_446483_no_detail_config() throws Exception {
|
||||
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "446483"));
|
||||
@@ -59,7 +58,6 @@ public class SwissTimingRaceConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Ignore("According to Radek Masnica ('masnica.r@st-software.com') the OTA stuff may not be supported any longer by the SwissTiming Leipzip lab... 2017-05-19")
|
||||
@Test
|
||||
public void testRaceConfig_6260_with_detail_config() throws Exception {
|
||||
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "6260"));
|
||||
|
||||
+2
-4
@@ -74,12 +74,11 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
assertEquals(321920, replayCountListener.rankingMarkCount);
|
||||
}
|
||||
|
||||
@Ignore("According to Radek Masnica ('masnica.r@st-software.com') the OTA stuff may not be supported any longer by the SwissTiming Leipzip lab... 2017-05-19")
|
||||
@Test
|
||||
public void testRaceData_SAW005905_20120805_EqualsOnlineVersion() throws Exception {
|
||||
byte[] localCopy = read(getClass().getResourceAsStream("/SAW005905.20120805.replay"));
|
||||
byte[] onlineCopy = read((InputStream) new URL(
|
||||
"http://live.ota.st-sportservice.com/Replay?id=446495&_start=0").getContent());
|
||||
"http://ota2.sportresult.com/Replay?id=446495&_start=0").getContent());
|
||||
assertArrayEquals(localCopy, onlineCopy);
|
||||
}
|
||||
|
||||
@@ -114,13 +113,12 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
assertEquals(9500, replayCountListener.rankingMarkCount);
|
||||
}
|
||||
|
||||
@Ignore("According to Radek Masnica ('masnica.r@st-software.com') the OTA stuff may not be supported any longer by the SwissTiming Leipzip lab... 2017-05-19")
|
||||
@Test
|
||||
public void testRaceData_SAW005905_20120805_online() throws Exception {
|
||||
SwissTimingReplayTestListener replayCountListener = new SwissTimingReplayTestListener();
|
||||
// race ID is 450053, as extracted from http://live.ota.st-sportservice.com/service?cmd=unity_race_overview&id=91
|
||||
byte[] onlineCopy = read((InputStream) new URL(
|
||||
"http://live.ota.st-sportservice.com/Replay?id=446495&_start=0").getContent());
|
||||
"http://ota2.sportresult.com/Replay?id=446495&_start=0").getContent());
|
||||
new SwissTimingReplayParserImpl().readData(new ByteArrayInputStream(onlineCopy), replayCountListener);
|
||||
assertEquals(0, replayCountListener.keyFrameIndexSum);
|
||||
assertEquals(715, replayCountListener.keyFrameIndexPositionCount);
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import com.sap.sse.util.ByteArrayOutputStreamWithVisibleBuffer;
|
||||
|
||||
public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
|
||||
|
||||
public static final String RACE_CONFIG_URL_TEMPLATE = "http://live.ota.st-sportservice.com/configuration?_race={0}&effective=1&additional=config";
|
||||
public static final String RACE_CONFIG_URL_TEMPLATE = "http://ota2.sportresult.com/configuration?_race={0}&effective=1&additional=config";
|
||||
|
||||
private static final String SWISSTIMING_DATEFORMAT_PATTERN = "dd.MM.yyyy HH:mm";
|
||||
private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||
|
||||
+13
-33
@@ -8,9 +8,6 @@ import com.sap.sailing.gwt.autoplay.client.places.screens.liveraceloop.racemapwi
|
||||
import com.sap.sailing.gwt.autoplay.client.places.screens.preliveraceloop.racemap.PreRaceRacemapPlace;
|
||||
import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper;
|
||||
import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper.RVWrapper;
|
||||
import com.sap.sailing.gwt.home.communication.event.minileaderboard.GetMiniLeaderboardDTO;
|
||||
import com.sap.sailing.gwt.home.communication.event.minileaderboard.GetMiniLeaderbordAction;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
|
||||
|
||||
public class PreLiveRaceWithRacemapNode extends FiresPlaceNode {
|
||||
private final AutoPlayClientFactory cf;
|
||||
@@ -21,12 +18,12 @@ public class PreLiveRaceWithRacemapNode extends FiresPlaceNode {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void onStart() {
|
||||
AutoplayHelper.create(cf.getSailingService(), cf.getErrorReporter(),
|
||||
cf.getAutoPlayCtx().getContextDefinition().getLeaderboardName(), cf.getAutoPlayCtx().getContextDefinition().getEventId(),
|
||||
cf.getAutoPlayCtx().getEvent(), cf.getEventBus(), cf.getDispatch(),
|
||||
cf.getAutoPlayCtx().getPreLiveRace(), new AsyncCallback<RVWrapper>() {
|
||||
cf.getAutoPlayCtx().getContextDefinition().getLeaderboardName(),
|
||||
cf.getAutoPlayCtx().getContextDefinition().getEventId(), cf.getAutoPlayCtx().getEvent(),
|
||||
cf.getEventBus(), cf.getDispatch(), cf.getAutoPlayCtx().getPreLiveRace(),
|
||||
new AsyncCallback<RVWrapper>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
@@ -39,33 +36,16 @@ public class PreLiveRaceWithRacemapNode extends FiresPlaceNode {
|
||||
|
||||
@Override
|
||||
public void onSuccess(RVWrapper result) {
|
||||
cf.getDispatch().execute(
|
||||
new GetMiniLeaderbordAction(cf.getAutoPlayCtx().getEvent().id,
|
||||
cf.getAutoPlayCtx().getContextDefinition().getLeaderboardName()),
|
||||
new AsyncCallback<ResultWithTTL<GetMiniLeaderboardDTO>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
// fireEvent(new DataLoadFailureEvent(MiniLeaderboardLoader.this, caught));
|
||||
firePlaceChangeAndStartTimer();
|
||||
}
|
||||
PreRaceRacemapPlace place = new PreRaceRacemapPlace();
|
||||
place.setRaceMap(result.raceboardPerspective, result.csel);
|
||||
// add later with settings here
|
||||
place.setURL(cf.getAutoPlayCtx().getEvent().getOfficialWebsiteURL());
|
||||
setPlaceToGo(place);
|
||||
getBus().fireEvent(
|
||||
new AutoPlayHeaderEvent(cf.getAutoPlayCtx().getPreLiveRace().getRegattaName(),
|
||||
cf.getAutoPlayCtx().getPreLiveRace().getRaceName()));
|
||||
firePlaceChangeAndStartTimer();
|
||||
|
||||
@Override
|
||||
public void onSuccess(ResultWithTTL<GetMiniLeaderboardDTO> resultTTL) {
|
||||
GetMiniLeaderboardDTO dto = resultTTL.getDto();
|
||||
PreRaceRacemapPlace place = new PreRaceRacemapPlace();
|
||||
place.setLeaderBoardDTO(dto);
|
||||
place.setRaceMap(result.raceboardPerspective, result.csel);
|
||||
// add later with settings here
|
||||
place.setURL(cf.getAutoPlayCtx().getEvent().getOfficialWebsiteURL());
|
||||
setPlaceToGo(place);
|
||||
getBus().fireEvent(
|
||||
new AutoPlayHeaderEvent(
|
||||
cf.getAutoPlayCtx().getPreLiveRace().getRegattaName(),
|
||||
cf.getAutoPlayCtx().getPreLiveRace().getRaceName()));
|
||||
firePlaceChangeAndStartTimer();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+11
-3
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.autoplay.client.places.screens.afterliveraceloop.boa
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
@@ -95,10 +96,17 @@ public class RaceEndWithBoatsPresenterImpl extends AutoPlayPresenterConfigured<A
|
||||
}
|
||||
|
||||
private void determinePlacement(RegattaAndRaceIdentifier lifeRace) {
|
||||
|
||||
RaceColumnDTO preselectedRaceColumn = leaderboardPanel.getLeaderboard().getRaceList().get(0);
|
||||
//TODO this is not multifleet capable currently, think about alternatives
|
||||
List<RaceColumnDTO> lifeRaceResult = leaderboardPanel.getLeaderboard().getRaceList();
|
||||
RaceColumnDTO raceColumn = null;
|
||||
for(RaceColumnDTO column:lifeRaceResult){
|
||||
if(column.containsRace(lifeRace)){
|
||||
raceColumn = column;
|
||||
}
|
||||
}
|
||||
GWT.debugger();
|
||||
List<CompetitorDTO> sortedCompetitors = leaderboardPanel.getLeaderboard()
|
||||
.getCompetitorsFromBestToWorst(preselectedRaceColumn);
|
||||
.getCompetitorsFromBestToWorst(raceColumn);
|
||||
|
||||
if (sortedCompetitors.size() >= 3) {
|
||||
view.setFirst(sortedCompetitors.get(0));
|
||||
|
||||
+10
-1
@@ -20,7 +20,9 @@ import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.raceboard.QuickRanksDTOFromLeaderboardDTOProvider;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
@@ -117,7 +119,11 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
|
||||
|
||||
List<LeaderboardRowDTO> sortedCompetitors = leaderboardPanel.getLeaderboardTable().getVisibleItems();
|
||||
if (sortedCompetitors.size() > 0) {
|
||||
view.setStatistic(windSpeed,getPlace().getStatistic().getDistance(), AutoplayHelper.durationOfCurrentLiveRaceRunning());
|
||||
if(getPlace().getStatistic() == null){
|
||||
view.setStatistic(windSpeed,null, AutoplayHelper.durationOfCurrentLiveRaceRunning());
|
||||
}else{
|
||||
view.setStatistic(windSpeed,getPlace().getStatistic().getDistance(), AutoplayHelper.durationOfCurrentLiveRaceRunning());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +160,9 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
|
||||
true, lifeRace, getPlace().getRaceMapSelectionProvider(), timer, null,
|
||||
getSlideCtx().getContextDefinition().getLeaderboardName(), errorReporter, StringMessages.INSTANCE, null,
|
||||
false, null, false, null, false, true, false, false, false);
|
||||
|
||||
getPlace().getRaceMap().setQuickRanksDTOProvider(new QuickRanksDTOFromLeaderboardDTOProvider(new RaceCompetitorSet(getPlace().getRaceMapSelectionProvider()), lifeRace));
|
||||
|
||||
view.startingWith(this, panel, getPlace().getRaceMap(), leaderboardPanel);
|
||||
selectionTimer.schedule(SWITCH_COMPETITOR_DELAY);
|
||||
}
|
||||
|
||||
-9
@@ -53,13 +53,4 @@ public class PreRaceRacemapPlace extends Place {
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setLeaderBoardDTO(GetMiniLeaderboardDTO dto) {
|
||||
this.leaderboard = dto;
|
||||
}
|
||||
|
||||
public GetMiniLeaderboardDTO getLeaderboard() {
|
||||
return leaderboard;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -77,7 +77,7 @@ public class PreRaceRacemapPresenterImpl extends AutoPlayPresenterConfigured<Pre
|
||||
}
|
||||
}
|
||||
String url = getRaceViewerURL(getSlideCtx().getContextDefinition().getLeaderboardName(), null,
|
||||
getSlideCtx().getLiveRace());
|
||||
getSlideCtx().getPreLiveRace());
|
||||
view.updateStatistic(lastStatisticResult, url, windSpeed, windDegree);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class PreRaceRacemapPresenterImpl extends AutoPlayPresenterConfigured<Pre
|
||||
}
|
||||
|
||||
private void reloadStatistics() {
|
||||
RegattaAndRaceIdentifier upcomingRace = getSlideCtx().getLiveRace();
|
||||
RegattaAndRaceIdentifier upcomingRace = getSlideCtx().getPreLiveRace();
|
||||
getClientFactory().getDispatch().execute(
|
||||
new GetSixtyInchStatisticAction(upcomingRace.getRaceName(), upcomingRace.getRegattaName()),
|
||||
new AsyncCallback<GetSixtyInchStatisticDTO>() {
|
||||
|
||||
+15
-9
@@ -31,6 +31,7 @@ import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
|
||||
import com.sap.sailing.gwt.ui.raceboard.AbstractQuickRanksDTOProvider;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
@@ -50,15 +51,19 @@ public class AutoplayHelper {
|
||||
private static Timer raceboardTimer = new Timer(PlayModes.Live, /* delayBetweenAutoAdvancesInMilliseconds */1000l);
|
||||
private static Date startOfLifeRace;
|
||||
public static final AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
/**
|
||||
* If a racestart is longer ago, the race is never considered live, even if all other checks pass
|
||||
*/
|
||||
private static final long NEGATIVE_SANITY_CHECK = -24 * 60 * 60 * 1000;
|
||||
|
||||
public static long durationOfCurrentLiveRaceRunning(){
|
||||
if(startOfLifeRace != null){
|
||||
return raceboardTimer.getLiveTimePointInMillis()-startOfLifeRace.getTime();
|
||||
}else{
|
||||
public static long durationOfCurrentLiveRaceRunning() {
|
||||
if (startOfLifeRace != null) {
|
||||
return raceboardTimer.getLiveTimePointInMillis() - startOfLifeRace.getTime();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void getLiveRace(SailingServiceAsync sailingService, ErrorReporter errorReporter, EventDTO event,
|
||||
String leaderBoardName, SailingDispatchSystem dispatch,
|
||||
AsyncCallback<Pair<Long, RegattaAndRaceIdentifier>> callback) {
|
||||
@@ -139,7 +144,7 @@ public class AutoplayHelper {
|
||||
long startTimeInMs = raceTimes.getStartOfRace().getTime();
|
||||
long delayToLiveInMs = raceTimes.delayToLiveInMs;
|
||||
long startIn = startTimeInMs - serverTimeDuringRequest.getTime() - delayToLiveInMs;
|
||||
if (startIn <= PRE_RACE_DELAY) {
|
||||
if (startIn <= PRE_RACE_DELAY && startIn > NEGATIVE_SANITY_CHECK) {
|
||||
startOfLifeRace = raceTimes.getStartOfRace();
|
||||
return new Pair<Long, RegattaAndRaceIdentifier>(startIn, raceIdentifier);
|
||||
}
|
||||
@@ -203,7 +208,7 @@ public class AutoplayHelper {
|
||||
AutoplayHelper.asyncActionsExecutor, errorReporter, raceboardTimer,
|
||||
callback, clientTimeWhenResponseWasReceived,
|
||||
serverTimeDuringRequest, clientTimeWhenRequestWasSent,
|
||||
raceTimesInfo);
|
||||
raceTimesInfo, new DefaultQuickRanksDTOProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -261,7 +266,8 @@ public class AutoplayHelper {
|
||||
Iterable<CompetitorDTO> competitors, SailingServiceAsync sailingService,
|
||||
AsyncActionsExecutor asyncActionsExecutor, ErrorReporter errorReporter, Timer raceboardTimer,
|
||||
AsyncCallback<RVWrapper> callback, long clientTimeWhenResponseWasReceived, Date serverTimeDuringRequest,
|
||||
long clientTimeWhenRequestWasSent, Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos) {
|
||||
long clientTimeWhenRequestWasSent, Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos,
|
||||
AbstractQuickRanksDTOProvider provider) {
|
||||
|
||||
ArrayList<ZoomTypes> typesToConsiderOnZoom = new ArrayList<>();
|
||||
// Other zoom types such as BOATS, TAILS or WINDSENSORS are not currently used as default zoom types.
|
||||
@@ -282,7 +288,7 @@ public class AutoplayHelper {
|
||||
RaceMap raceboardPerspective = new RaceMap(null, null, raceMapLifecycle, settings, sailingService,
|
||||
asyncActionsExecutor, errorReporter, raceboardTimer, competitorSelectionProvider,
|
||||
new RaceCompetitorSet(competitorSelectionProvider), StringMessages.INSTANCE, currentLiveRace,
|
||||
raceMapResources, false, new DefaultQuickRanksDTOProvider());
|
||||
raceMapResources, false, provider);
|
||||
raceboardPerspective.raceTimesInfosReceived(raceTimesInfos, clientTimeWhenRequestWasSent,
|
||||
serverTimeDuringRequest, clientTimeWhenResponseWasReceived);
|
||||
// raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceboardPerspective);
|
||||
|
||||
+15
-13
@@ -238,19 +238,21 @@ public class RegattaDetailsComposite extends Composite {
|
||||
editRacesOfRegattaSeries(regatta, series);
|
||||
} else if (SeriesConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
|
||||
RegattaIdentifier identifier = new RegattaName(regatta.getName());
|
||||
sailingService.removeSeries(identifier, series.getName(), new MarkedAsyncCallback<Void>(
|
||||
new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable cause) {
|
||||
errorReporter.reportError("Error trying to remove series " + series.getName()
|
||||
+ ": " + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
regattaRefresher.fillRegattas();
|
||||
}
|
||||
}));
|
||||
if (Window.confirm(stringMessages.reallyRemoveSeries(series.getName()))) {
|
||||
sailingService.removeSeries(identifier, series.getName(),
|
||||
new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable cause) {
|
||||
errorReporter.reportError("Error trying to remove series " + series.getName()
|
||||
+ ": " + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
regattaRefresher.fillRegattas();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -1817,7 +1817,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String showRacePlaceColumn();
|
||||
String unknownLeaderboardType(String name);
|
||||
String selectCompetitorsToEliminate();
|
||||
String trackedRaceAlreadyLinked();
|
||||
String trackedRaceAlreadyLinked();
|
||||
String reallyRemoveSeries(String seriesName);
|
||||
String noData();
|
||||
String settingsId();
|
||||
String documentSettingsId();
|
||||
|
||||
+1
@@ -1796,6 +1796,7 @@ showRacePlaceColumn=Show race place
|
||||
estimatedDistance=Estimated Distance
|
||||
estimatedTime=Estimated Time
|
||||
nothingUpcoming=There are currently no further planned races
|
||||
reallyRemoveSeries=Do you really want to remove the series ''{0}''? Note: all race logs for the attached race columns will also permanently be removed!
|
||||
noData=No data is available
|
||||
settingsId=Settings ID
|
||||
documentSettingsId=Document settings ID
|
||||
|
||||
+1
@@ -1784,3 +1784,4 @@ resetToDefault=Auf Standard zurücksetzen
|
||||
resetToDefaultInProgress=Setze zurück...
|
||||
settingsRemoved=Standardeinstellungen wiederhergestellt
|
||||
settingsRemovedError=Fehler beim Widerherstellen der Standardeinstellungen
|
||||
reallyRemoveSeries=Möchten Sie die Serie ''{0}'' wirklich entfernen? Achtung: alle Ereignisprotokolle (RaceLogs) der zugehörigen Renn-Spalten werden unwiederbringlich gelöscht!
|
||||
+7
-6
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -8,13 +9,13 @@ import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class DefaultQuickRanksDTOProvider extends AbstractQuickRanksDTOProvider {
|
||||
private Map<String, QuickRankDTO> quickRanksFromServer;
|
||||
private Map<String, QuickRankDTO> currentQuickRanksFromServer = Collections.emptyMap();
|
||||
|
||||
@Override
|
||||
public void quickRanksReceivedFromServer(Map<String, QuickRankDTO> quickRanksFromServer) {
|
||||
final Map<String, QuickRankDTO> oldQuickRanksFromServer = quickRanksFromServer;
|
||||
this.quickRanksFromServer = quickRanksFromServer;
|
||||
for (final Entry<String, QuickRankDTO> e : quickRanksFromServer.entrySet()) {
|
||||
public void quickRanksReceivedFromServer(Map<String, QuickRankDTO> receivedQuickRanksFromServer) {
|
||||
final Map<String, QuickRankDTO> oldQuickRanksFromServer = this.currentQuickRanksFromServer;
|
||||
this.currentQuickRanksFromServer = Util.nullToEmptyMap(receivedQuickRanksFromServer);
|
||||
for (final Entry<String, QuickRankDTO> e : currentQuickRanksFromServer.entrySet()) {
|
||||
final QuickRankDTO oldQuickRank = oldQuickRanksFromServer.get(e.getKey());
|
||||
if (Util.equalsWithNull(oldQuickRank, e.getValue())) {
|
||||
notifyListeners(e.getKey(), oldQuickRank, e.getValue());
|
||||
@@ -24,7 +25,7 @@ public class DefaultQuickRanksDTOProvider extends AbstractQuickRanksDTOProvider
|
||||
|
||||
@Override
|
||||
public Map<String, QuickRankDTO> getQuickRanks() {
|
||||
return quickRanksFromServer;
|
||||
return currentQuickRanksFromServer;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-1
@@ -31,6 +31,13 @@ public interface QuickRanksDTOProvider {
|
||||
|
||||
void removeQuickRanksListener(QuickRanksListener listener);
|
||||
|
||||
/**
|
||||
* When switching the underlying provider, this method allows to move current listeners to the new provider.
|
||||
*
|
||||
* @param newProvider
|
||||
*/
|
||||
public void moveListernersTo(QuickRanksDTOProvider newProvider);
|
||||
|
||||
/**
|
||||
* The strategy may or may not use this quick ranks information provided directly from the server. This information
|
||||
* may have been provided with some delay and may be slightly inconsistent with a {@link LeaderboardDTO leaderboard}
|
||||
@@ -38,7 +45,8 @@ public interface QuickRanksDTOProvider {
|
||||
* {@link LeaderboardDTO leaderboard} should ignore this call if it already has quick ranks information available
|
||||
* from a leaderboard.
|
||||
*
|
||||
* @param quickRanksFromServer keys are the competitor IDs as strings
|
||||
* @param quickRanksFromServer
|
||||
* keys are the competitor IDs as strings
|
||||
*/
|
||||
void quickRanksReceivedFromServer(Map<String, QuickRankDTO> quickRanksFromServer);
|
||||
|
||||
|
||||
+9
-2
@@ -353,7 +353,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
|
||||
* quick ranks received from a {@link RaceMapDataDTO#quickRanks} field but may choose to ignore this information, e.g.,
|
||||
* if it can assume that more current information about ranks and leg numbers is available from a {@link LeaderboardDTO}.
|
||||
*/
|
||||
private final QuickRanksDTOProvider quickRanksDTOProvider;
|
||||
private QuickRanksDTOProvider quickRanksDTOProvider;
|
||||
|
||||
private final CombinedWindPanel combinedWindPanel;
|
||||
private final TrueNorthIndicatorPanel trueNorthIndicatorPanel;
|
||||
@@ -487,6 +487,12 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
|
||||
this.setSize("100%", "100%");
|
||||
}
|
||||
|
||||
public void setQuickRanksDTOProvider(QuickRanksDTOProvider newQuickRanksDTOProvider) {
|
||||
if (this.quickRanksDTOProvider != null) {
|
||||
this.quickRanksDTOProvider.moveListernersTo(newQuickRanksDTOProvider);
|
||||
}
|
||||
this.quickRanksDTOProvider = newQuickRanksDTOProvider;
|
||||
}
|
||||
/**
|
||||
* The {@link WindDTO#dampenedTrueWindFromDeg} direction if {@link #lastCombinedWindTrackInfoDTO} has a
|
||||
* {@link WindSourceType#COMBINED} source which has at least one fix recorded; <code>null</code> otherwise.
|
||||
@@ -1403,7 +1409,8 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
|
||||
|
||||
final static Distance advantageLineLength = new MeterDistance(1000); // TODO this should probably rather scale with the visible area of the map; bug 616
|
||||
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date, long timeForPositionTransitionMillis) {
|
||||
if (map != null && lastRaceTimesInfo != null && quickRanksDTOProvider.getQuickRanks() != null && lastCombinedWindTrackInfoDTO != null) {
|
||||
if (map != null && lastRaceTimesInfo != null && quickRanksDTOProvider.getQuickRanks().isEmpty()
|
||||
&& lastCombinedWindTrackInfoDTO != null) {
|
||||
boolean drawAdvantageLine = false;
|
||||
if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.ADVANTAGELINE)) {
|
||||
// find competitor with highest rank
|
||||
|
||||
+7
@@ -23,6 +23,13 @@ public abstract class AbstractQuickRanksDTOProvider implements QuickRanksDTOProv
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void moveListernersTo(QuickRanksDTOProvider newProvider) {
|
||||
for (QuickRanksListener quickRanksListener : listeners) {
|
||||
newProvider.addQuickRanksListener(quickRanksListener);
|
||||
}
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
protected void notifyListeners(String competitorIdAsString, QuickRankDTO oldQuickRank, QuickRankDTO newQuickRank) {
|
||||
for (QuickRanksListener listener : listeners) {
|
||||
listener.rankChanged(competitorIdAsString, oldQuickRank, newQuickRank);
|
||||
|
||||
+2
-2
@@ -66,8 +66,8 @@ public class RegattaDetailsCompositePO extends PageArea {
|
||||
if (entry != null) {
|
||||
WebElement removeAction = ActionsHelper.findRemoveAction(entry.getWebElement());
|
||||
removeAction.click();
|
||||
// ActionsHelper.acceptAlert(this.driver);
|
||||
// waitForAjaxRequests();
|
||||
ActionsHelper.acceptAlert(this.driver);
|
||||
waitForAjaxRequests();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -1,12 +1,20 @@
|
||||
package com.sap.sailing.server.notification.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class NotificationMailTemplate {
|
||||
|
||||
/**
|
||||
* The class needs to implement the {@link Serializable} interface because it can become part of a
|
||||
* {@link SerializableMultipartSupplier}.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class NotificationMailTemplate implements Serializable {
|
||||
private static final long serialVersionUID = 3291811210425722552L;
|
||||
private final String subject;
|
||||
private final String title;
|
||||
private final String text;
|
||||
|
||||
+8
-23
@@ -10,17 +10,12 @@ import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl;
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.mail.SerializableDefaultMimeBodyPartSupplier;
|
||||
import com.sap.sse.mail.SerializableImageMimeBodyPartSupplier;
|
||||
import com.sap.sse.mail.SerializableMultipartSupplier;
|
||||
import com.sap.sse.mail.queue.MailNotification;
|
||||
import com.sap.sse.security.PreferenceObjectBasedNotificationSet;
|
||||
import com.sap.sse.security.User;
|
||||
@@ -81,22 +76,12 @@ public abstract class NotificationSetNotification<T> implements MailNotification
|
||||
// send batches with the actual mail addresses as bcc?
|
||||
associatedNotificationSet.forUsersWithVerifiedEmailMappedTo(objectToNotifyAbout, (user) -> {
|
||||
Locale locale = user.getLocaleOrDefault();
|
||||
Multipart multipart = new MimeMultipart("related");
|
||||
BodyPart bodyPart = new MimeBodyPart();
|
||||
BodyPart messageImagePart = new MimeBodyPart();
|
||||
final NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale);
|
||||
try {
|
||||
// TODO: add cid:saplogo
|
||||
NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale);
|
||||
bodyPart.setContent(getMailContent(mailTemplate, user, locale), "text/html");
|
||||
multipart.addBodyPart(bodyPart);
|
||||
|
||||
DataSource imageDs = new ByteArrayDataSource(LOGO_BYTES, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "saplogo");
|
||||
messageImagePart.setHeader("Content-Disposition", "inline;filename=\"saplogo.png\"");
|
||||
multipart.addBodyPart(messageImagePart);
|
||||
|
||||
mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), multipart);
|
||||
final SerializableMultipartSupplier multipartSupplier = new SerializableMultipartSupplier("related",
|
||||
new SerializableDefaultMimeBodyPartSupplier(getMailContent(mailTemplate, user, locale), "text/html"),
|
||||
new SerializableImageMimeBodyPartSupplier(LOGO_BYTES, "image/png", "saplogo", "saplogo.png"));
|
||||
mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), multipartSupplier);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Could not send mail notification for \"" + objectToNotifyAbout + "\" to user \"" + user + "\"", e);
|
||||
|
||||
@@ -514,7 +514,7 @@ public class Util {
|
||||
* {@link #isEmpty(Iterable) isEmpty(splitAlongWhitespaceRespectingDoubleQuotedPhrases(" \n\t "))
|
||||
* </pre>
|
||||
*
|
||||
* @return if {@code s==null}, then {@code null}, else a non-{@code null} but possibly empty sequence of {@link Strings} whose iteration order corresponds with
|
||||
* @return if {@code s==null}, then {@code null}, else a non-{@code null} but possibly empty sequence of {@link String} whose iteration order corresponds with
|
||||
* the occurrence of the split results, left to right, in {@code s}
|
||||
*/
|
||||
public static Iterable<String> splitAlongWhitespaceRespectingDoubleQuotedPhrases(String s) {
|
||||
@@ -734,4 +734,14 @@ public class Util {
|
||||
public static <T extends Comparable<T>> T max(T... elements) {
|
||||
return Collections.max(Arrays.asList(elements));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given map is null, and if, returns an empty map.
|
||||
*/
|
||||
public static <K, V> Map<K, V> nullToEmptyMap(Map<K, V> map) {
|
||||
if (map == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -8,6 +8,7 @@ import org.junit.Before;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.mail.MailServiceResolver;
|
||||
import com.sap.sse.mail.SerializableMultipartSupplier;
|
||||
import com.sap.sse.mail.impl.MailServiceImpl;
|
||||
import com.sap.sse.replication.testsupport.AbstractServerReplicationTestSetUp;
|
||||
import com.sap.sse.replication.testsupport.AbstractServerWithSingleServiceReplicationTest;
|
||||
@@ -34,12 +35,13 @@ public class AbstractMailServiceReplicationTest extends AbstractServerWithSingle
|
||||
};
|
||||
mailService[0] = new MailServiceImpl(null, mailServiceResolver) {
|
||||
@Override
|
||||
protected void internalSendMail(String toAddress, String subject, ContentSetter contentSetter)
|
||||
public Void internalSendMail(String toAddress, String subject, SerializableMultipartSupplier multipartSupplier)
|
||||
throws MailException {
|
||||
if (canSendMail) {
|
||||
Integer old = numberOfMailsSent.get(this);
|
||||
numberOfMailsSent.put(this, old == null ? 1 : old + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return mailService[0];
|
||||
|
||||
@@ -12,6 +12,7 @@ Export-Package: com.sap.sse.mail,
|
||||
com.sap.sse.mail.queue.impl
|
||||
Import-Package: javax.mail,
|
||||
javax.mail.internet,
|
||||
javax.mail.util;version="1.4.0",
|
||||
org.osgi.framework,
|
||||
org.osgi.util.tracker;version="1.5.1"
|
||||
Require-Bundle: com.sap.sse.replication,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import javax.mail.Multipart;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
import com.sap.sse.common.IsManagedByCache;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
@@ -29,5 +31,5 @@ public interface MailService extends ReplicableWithObjectInputStream<ReplicableM
|
||||
/**
|
||||
* Send mail with multipart content (e.g. inline image).
|
||||
*/
|
||||
void sendMail(String toAddress, String subject, Multipart multipartContent) throws MailException;
|
||||
void sendMail(String toAddress, String subject, SerializableMultipartSupplier multipartContent) throws MailException, IOException, MessagingException;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
import com.sap.sse.qrcode.QRCodeGenerationUtil;
|
||||
|
||||
/**
|
||||
* Constructs a MIME body part containing a QR code for a {@link #text} provided to this object
|
||||
* at construction time.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class QRCodeMimeBodyPartSupplier implements SerializableMimeBodyPartSupplier {
|
||||
private static final long serialVersionUID = 6073707813859319317L;
|
||||
private final String text;
|
||||
|
||||
public QRCodeMimeBodyPartSupplier(String text) {
|
||||
super();
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeBodyPart get() {
|
||||
final MimeBodyPart messageImagePart = new MimeBodyPart();
|
||||
InputStream imageIs;
|
||||
try {
|
||||
imageIs = QRCodeGenerationUtil.create(text, 250);
|
||||
final DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "<image>");
|
||||
messageImagePart.setHeader("Content-Disposition", "inline;filename=\"qr.png\"");
|
||||
return messageImagePart;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
|
||||
/**
|
||||
* Can construct a {@link MimeBodyPart} out of a serializable object and a content type specification string.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class SerializableDefaultMimeBodyPartSupplier implements SerializableMimeBodyPartSupplier {
|
||||
private static final long serialVersionUID = -2893291156595020570L;
|
||||
private final Serializable serializableContent;
|
||||
private final String contentType;
|
||||
|
||||
public SerializableDefaultMimeBodyPartSupplier(Serializable serializableContent, String contentType) {
|
||||
super();
|
||||
this.serializableContent = serializableContent;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeBodyPart get() {
|
||||
final MimeBodyPart result = new MimeBodyPart();
|
||||
try {
|
||||
result.setContent(serializableContent, contentType);
|
||||
} catch (MessagingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
public class SerializableImageMimeBodyPartSupplier implements SerializableMimeBodyPartSupplier {
|
||||
private static final long serialVersionUID = -1540223936240644379L;
|
||||
private final byte[] imageBytes;
|
||||
private final String contentType;
|
||||
private final String contentId;
|
||||
private final String imageFilename;
|
||||
|
||||
public SerializableImageMimeBodyPartSupplier(byte[] imageBytes, String contentType, String contentId,
|
||||
String imageFilename) {
|
||||
super();
|
||||
this.imageBytes = imageBytes;
|
||||
this.contentType = contentType;
|
||||
this.contentId = contentId;
|
||||
this.imageFilename = imageFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeBodyPart get() {
|
||||
final MimeBodyPart messageImagePart = new MimeBodyPart();
|
||||
DataSource imageDs = new ByteArrayDataSource(imageBytes, contentType);
|
||||
try {
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", contentId);
|
||||
messageImagePart.setHeader("Content-Disposition", "inline;filename=\"" + imageFilename + "\"");
|
||||
return messageImagePart;
|
||||
} catch (MessagingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
|
||||
/**
|
||||
* Plays together with {@link SerializableMultipartSupplier}. One or more instances of this type can be
|
||||
* passed to its constructor so that after de-serialization a {@link Multipart} message can be constructed
|
||||
* from the parts.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public interface SerializableMimeBodyPartSupplier extends Supplier<MimeBodyPart>, Serializable {
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.sap.sse.mail;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
import com.sap.sse.common.Named;
|
||||
import com.sap.sse.common.impl.NamedImpl;
|
||||
|
||||
public class SerializableMultipartSupplier extends NamedImpl implements Supplier<Multipart>, Named {
|
||||
private static final long serialVersionUID = 4316486727705670702L;
|
||||
private final SerializableMimeBodyPartSupplier[] bodyPartSuppliers;
|
||||
|
||||
public SerializableMultipartSupplier(String name, SerializableMimeBodyPartSupplier... partSuppliers) {
|
||||
super(name);
|
||||
this.bodyPartSuppliers = partSuppliers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multipart get() {
|
||||
final Multipart result = new MimeMultipart(getName());
|
||||
for (final SerializableMimeBodyPartSupplier bodyPartSupplier : bodyPartSuppliers) {
|
||||
try {
|
||||
result.addBodyPart(bodyPartSupplier.get());
|
||||
} catch (MessagingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.mail.Message.RecipientType;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
@@ -28,6 +27,7 @@ import javax.mail.internet.MimeUtility;
|
||||
import com.sap.sse.common.IsManagedByCache;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
import com.sap.sse.mail.MailServiceResolver;
|
||||
import com.sap.sse.mail.SerializableMultipartSupplier;
|
||||
import com.sap.sse.replication.OperationExecutionListener;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
@@ -68,7 +68,7 @@ public class MailServiceImpl implements ReplicableMailService {
|
||||
protected static interface ContentSetter {
|
||||
void setContent(MimeMessage msg) throws MessagingException;
|
||||
}
|
||||
|
||||
|
||||
private boolean canSendMail() {
|
||||
return mailProperties != null && mailProperties.containsKey("mail.transport.protocol");
|
||||
}
|
||||
@@ -88,16 +88,12 @@ public class MailServiceImpl implements ReplicableMailService {
|
||||
msg.setSubject(subject);
|
||||
}
|
||||
msg.addRecipient(RecipientType.TO, new InternetAddress(toAddress.trim()));
|
||||
|
||||
// this fixes the DCH MIME type error
|
||||
// see http://tanyamadurapperuma.blogspot.de/2014/01/struggling-with-nosuchproviderexception.html
|
||||
Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
|
||||
|
||||
contentSetter.setContent(msg);
|
||||
|
||||
// for testing with gmail
|
||||
//Transport ts = session.getTransport("smtps");
|
||||
|
||||
Transport ts = session.getTransport();
|
||||
ts.connect();
|
||||
ts.sendMessage(msg, msg.getRecipients(RecipientType.TO));
|
||||
@@ -134,19 +130,19 @@ public class MailServiceImpl implements ReplicableMailService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalSendMail(String toAddress, String subject, Multipart multipartContent) throws MailException {
|
||||
public Void internalSendMail(String toAddress, String subject, SerializableMultipartSupplier multipartSupplier) throws MailException {
|
||||
internalSendMail(toAddress, subject, new ContentSetter() {
|
||||
@Override
|
||||
public void setContent(MimeMessage msg) throws MessagingException {
|
||||
msg.setContent(multipartContent);
|
||||
msg.setContent(multipartSupplier.get());
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(String toAddress, String subject, Multipart multipartContent) throws MailException {
|
||||
apply(s -> s.internalSendMail(toAddress, subject, multipartContent));
|
||||
public void sendMail(String toAddress, String subject, SerializableMultipartSupplier multipartSupplier) throws MailException {
|
||||
apply(s -> s.internalSendMail(toAddress, subject, multipartSupplier));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
package com.sap.sse.mail.impl;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.mail.SerializableMultipartSupplier;
|
||||
|
||||
public interface ReplicableMailService extends MailService {
|
||||
Void internalSendMail(String toAddress, String subject, String body) throws MailException;
|
||||
Void internalSendMail(String toAddress, String subject, String body) throws MailException, MessagingException;
|
||||
|
||||
Void internalSendMail(String toAddress, String subject, Multipart multipartContent) throws MailException;
|
||||
/**
|
||||
* @param multipartSupplier
|
||||
* can produce a {@link Multipart} object and must be serializable
|
||||
*/
|
||||
Void internalSendMail(String toAddress, String subject, SerializableMultipartSupplier multipartSupplier) throws MailException, MessagingException;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
*
|
||||
*/
|
||||
public class QRCodeGenerationUtil {
|
||||
public static InputStream create(String text, int sizeInPixels) throws WriterException, IOException {
|
||||
public static InputStream create(String text, int sizeInPixels) throws Exception {
|
||||
Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<EncodeHintType,
|
||||
ErrorCorrectionLevel>();
|
||||
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
|
||||
|
||||
Reference in new issue
Block a user