Merge branch 'master' into translation

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties

Change-Id: I3ff3966a8ebb007d14f37ea96fc6cdcc46a17dd5
This commit is contained in:
Axel Uhl committed 2016-04-18 20:58:27 +02:00
commit 38d65f22ba
151 files changed
+7700 -7129

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0-alpha5'
classpath 'com.android.tools.build:gradle:2.1.0-beta1'
}
}
+1
View File
@@ -28,6 +28,7 @@ SAP is at the center of today’s technology revolution, developing innovations
* [[Amazon EC2|wiki/amazon-ec2]]
* [[SSL / HTTPS Support|wiki/ssl-support]]
* [[EC2 Backup Strategy|wiki/amazon-ec2-backup-strategy]]
* [[EC2 mail relaying|wiki/mail-relaying]]
* [[TracTrac|wiki/tractrac-lifecycle]]
* [[Analytics on a stick|wiki/analytics-on-a-stick]]
* [[Operating Igtimi WindBots/windbot-operations]]
@@ -45,6 +45,14 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
if (coreLocationManager.respondsToSelector("requestAlwaysAuthorization")) {
coreLocationManager.requestAlwaysAuthorization()
}
// Now try everything to allow the app to use the GPS sensor
// while in background
coreLocationManager.pausesLocationUpdatesAutomatically = false;
if #available(iOS 9, *) {
coreLocationManager.allowsBackgroundLocationUpdates = true;
}
coreLocationManager.startUpdatingLocation()
coreLocationManager.startUpdatingHeading()
coreLocationManager.delegate = self
@@ -102,4 +110,4 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
return true;
}
}
}
@@ -17,7 +17,9 @@ public interface CompetitorDTO extends Serializable, MappableToDevice {
String getIdAsString();
String getSailID();
String getSearchTag();
BoatDTO getBoat();
BoatClassDTO getBoatClass();
@@ -1,207 +1,219 @@
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
* to change for a competitor while the ID remains unchanged.
*
* @author Axel Uhl (d043530)
*
*/
public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serializable {
private static final long serialVersionUID = -4997852354821083154L;
private String countryName;
private String twoLetterIsoCountryCode;
private String threeLetterIocCountryCode;
private Color color;
private String email;
private String idAsString;
private BoatClassDTO boatClass;
private BoatDTO boat;
private String imageURL;
private String flagImageURL;
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorDTOImpl() {}
public CompetitorDTOImpl(String name, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
String countryName, String idAsString, String imageURL, String flagImageURL,
BoatDTO boat, BoatClassDTO boatClass, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
super(name);
this.color = color;
this.email = email;
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
this.countryName = countryName;
this.idAsString = idAsString;
this.imageURL = imageURL;
this.flagImageURL = flagImageURL;
this.boat = boat;
this.boatClass = boatClass;
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
CompetitorDTOImpl other = (CompetitorDTOImpl) obj;
if (boatClass == null) {
if (other.boatClass != null)
return false;
} else if (!boatClass.equals(other.boatClass))
return false;
if (boat == null) {
if (other.boat != null)
return false;
} else if (!boat.equals(other.boat))
return false;
if (idAsString == null) {
if (other.idAsString != null)
return false;
} else if (!idAsString.equals(other.idAsString))
return false;
if (threeLetterIocCountryCode == null) {
if (other.threeLetterIocCountryCode != null)
return false;
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (imageURL == null) {
if (other.imageURL != null)
return false;
} else if (!imageURL.equals(other.imageURL))
return false;
if (flagImageURL == null) {
if (other.flagImageURL != null)
return false;
} else if (!flagImageURL.equals(other.flagImageURL))
return false;
if (timeOnTimeFactor == null) {
if (other.timeOnTimeFactor != null)
return false;
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
return false;
if (timeOnDistanceAllowancePerNauticalMile == null) {
if (other.timeOnDistanceAllowancePerNauticalMile != null)
return false;
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
return twoLetterIsoCountryCode;
}
@Override
public String getThreeLetterIocCountryCode() {
return threeLetterIocCountryCode;
}
@Override
public String getCountryName() {
return countryName;
}
@Override
public String getSailID() {
return boat==null?null:boat.getSailId();
}
@Override
public String getImageURL() {
return imageURL;
}
@Override
public String getFlagImageURL() {
return flagImageURL;
}
@Override
public String getIdAsString() {
return idAsString;
}
@Override
public BoatClassDTO getBoatClass() {
return boatClass;
}
@Override
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
return this;
}
public Color getColor() {
return color;
}
public String getEmail() {
return email;
}
public String email(){
return email;
}
@Override
public boolean hasEmail() {
return email != null && !email.isEmpty();
}
@Override
public Double getTimeOnTimeFactor() {
return timeOnTimeFactor;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
@Override
public BoatDTO getBoat() {
return boat;
}
}
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
* to change for a competitor while the ID remains unchanged.
*
* @author Axel Uhl (d043530)
*
*/
public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serializable {
private static final long serialVersionUID = -4997852354821083154L;
private String countryName;
private String twoLetterIsoCountryCode;
private String threeLetterIocCountryCode;
private Color color;
private String email;
private String searchTag;
private String idAsString;
private BoatClassDTO boatClass;
private BoatDTO boat;
private String imageURL;
private String flagImageURL;
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorDTOImpl() {}
public CompetitorDTOImpl(String name, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
String countryName, String idAsString, String imageURL, String flagImageURL,
BoatDTO boat, BoatClassDTO boatClass, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
super(name);
this.color = color;
this.email = email;
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
this.countryName = countryName;
this.idAsString = idAsString;
this.imageURL = imageURL;
this.flagImageURL = flagImageURL;
this.boat = boat;
this.boatClass = boatClass;
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
this.searchTag = searchTag;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
result = prime * result + ((searchTag == null) ? 0 : searchTag.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
CompetitorDTOImpl other = (CompetitorDTOImpl) obj;
if (boatClass == null) {
if (other.boatClass != null)
return false;
} else if (!boatClass.equals(other.boatClass))
return false;
if (boat == null) {
if (other.boat != null)
return false;
} else if (!boat.equals(other.boat))
return false;
if (idAsString == null) {
if (other.idAsString != null)
return false;
} else if (!idAsString.equals(other.idAsString))
return false;
if (threeLetterIocCountryCode == null) {
if (other.threeLetterIocCountryCode != null)
return false;
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (imageURL == null) {
if (other.imageURL != null)
return false;
} else if (!imageURL.equals(other.imageURL))
return false;
if (flagImageURL == null) {
if (other.flagImageURL != null)
return false;
} else if (!flagImageURL.equals(other.flagImageURL))
return false;
if (timeOnTimeFactor == null) {
if (other.timeOnTimeFactor != null)
return false;
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
return false;
if (timeOnDistanceAllowancePerNauticalMile == null) {
if (other.timeOnDistanceAllowancePerNauticalMile != null)
return false;
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
return false;
if (searchTag == null) {
if (other.searchTag != null)
return false;
} else if (!searchTag.equals(other.searchTag))
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
return twoLetterIsoCountryCode;
}
@Override
public String getThreeLetterIocCountryCode() {
return threeLetterIocCountryCode;
}
@Override
public String getCountryName() {
return countryName;
}
@Override
public String getSailID() {
return boat==null?null:boat.getSailId();
}
@Override
public String getImageURL() {
return imageURL;
}
@Override
public String getFlagImageURL() {
return flagImageURL;
}
@Override
public String getIdAsString() {
return idAsString;
}
@Override
public BoatClassDTO getBoatClass() {
return boatClass;
}
@Override
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
return this;
}
public Color getColor() {
return color;
}
public String getSearchTag() {
return searchTag;
}
public String getEmail() {
return email;
}
public String email(){
return email;
}
@Override
public boolean hasEmail() {
return email != null && !email.isEmpty();
}
@Override
public Double getTimeOnTimeFactor() {
return timeOnTimeFactor;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
@Override
public BoatDTO getBoat() {
return boat;
}
}
@@ -1,143 +1,149 @@
package com.sap.sailing.domain.common.dto;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the index pointing into a previous leaderboard's competitors list.
*
* @author Axel Uhl (d043530)
*
*/
public class PreviousCompetitorDTOImpl implements CompetitorDTO {
private static final long serialVersionUID = 8820028699103040805L;
private int indexInPreviousCompetitorList;
PreviousCompetitorDTOImpl() {} // for serialization only
public PreviousCompetitorDTOImpl(int indexInPreviousCompetitorList) {
super();
this.indexInPreviousCompetitorList = indexInPreviousCompetitorList;
}
protected int getIndexInPreviousCompetitorList() {
return indexInPreviousCompetitorList;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + indexInPreviousCompetitorList;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PreviousCompetitorDTOImpl other = (PreviousCompetitorDTOImpl) obj;
if (indexInPreviousCompetitorList != other.indexInPreviousCompetitorList)
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getThreeLetterIocCountryCode() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getCountryName() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getSailID() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public BoatDTO getBoat() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Color getColor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getIdAsString() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public BoatClassDTO getBoatClass() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getName() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getEmail() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getImageURL() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getFlagImageURL() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public boolean hasEmail() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Double getTimeOnTimeFactor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
return previousVersion.competitors.get(indexInPreviousCompetitorList);
}
package com.sap.sailing.domain.common.dto;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the index pointing into a previous leaderboard's competitors list.
*
* @author Axel Uhl (d043530)
*
*/
public class PreviousCompetitorDTOImpl implements CompetitorDTO {
private static final long serialVersionUID = 8820028699103040805L;
private int indexInPreviousCompetitorList;
PreviousCompetitorDTOImpl() {} // for serialization only
public PreviousCompetitorDTOImpl(int indexInPreviousCompetitorList) {
super();
this.indexInPreviousCompetitorList = indexInPreviousCompetitorList;
}
protected int getIndexInPreviousCompetitorList() {
return indexInPreviousCompetitorList;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + indexInPreviousCompetitorList;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PreviousCompetitorDTOImpl other = (PreviousCompetitorDTOImpl) obj;
if (indexInPreviousCompetitorList != other.indexInPreviousCompetitorList)
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getThreeLetterIocCountryCode() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getCountryName() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getSailID() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public BoatDTO getBoat() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Color getColor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getIdAsString() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public BoatClassDTO getBoatClass() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getName() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getEmail() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getSearchTag() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getImageURL() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getFlagImageURL() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public boolean hasEmail() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Double getTimeOnTimeFactor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
return previousVersion.competitors.get(indexInPreviousCompetitorList);
}
}
@@ -1,21 +1,23 @@
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
public class RaceLogTrackingInfoDTO implements Serializable {
private static final long serialVersionUID = -6861382173074620168L;
public boolean raceLogTrackerExists;
public boolean competitorRegistrationsExists;
public RaceLogTrackingState raceLogTrackingState;
protected RaceLogTrackingInfoDTO() {}
public RaceLogTrackingInfoDTO(boolean raceLogTrackerExists, boolean competitorRegistrationsExists,
RaceLogTrackingState raceLogTrackingState) {
this.raceLogTrackerExists = raceLogTrackerExists;
this.competitorRegistrationsExists = competitorRegistrationsExists;
this.raceLogTrackingState = raceLogTrackingState;
}
}
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
public class RaceLogTrackingInfoDTO implements Serializable {
private static final long serialVersionUID = -6861382173074620168L;
public boolean raceLogTrackerExists;
public boolean competitorRegistrationsExists;
public boolean courseExists;
public RaceLogTrackingState raceLogTrackingState;
protected RaceLogTrackingInfoDTO() {}
public RaceLogTrackingInfoDTO(boolean raceLogTrackerExists, boolean competitorRegistrationsExists, boolean courseExists,
RaceLogTrackingState raceLogTrackingState) {
this.raceLogTrackerExists = raceLogTrackerExists;
this.competitorRegistrationsExists = competitorRegistrationsExists;
this.courseExists = courseExists;
this.raceLogTrackingState = raceLogTrackingState;
}
}
@@ -22,6 +22,7 @@ public class CompetitorJsonConstants {
public static final String FIELD_BOAT = "boat";
public static final String FIELD_DISPLAY_COLOR = "displayColor";
public static final String FIELD_EMAIL = "email";
public static final String FIELD_SEARCHTAG = "searchTag";
public static final String FIELD_FLAG_IMAGE_URI = "flagImageUri";
public static final String FIELD_TEAM_IMAGE_URI = "teamImageUri";
public static final String FIELD_TIME_ON_TIME_FACTOR = "timeOnTimeFactor";
@@ -37,7 +37,6 @@ public class GPSFixImpl extends AbstractGPSFixImpl implements GPSFix {
public String toString() {
return getTimePoint()+": "+getPosition();
}
public static GPSFixImpl create(double lonDeg, double latDeg, long timeMillis) {
return new GPSFixImpl(new DegreePosition(latDeg, lonDeg), new MillisecondsTimePoint(timeMillis));
@@ -28,7 +28,9 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import com.sap.sailing.domain.igtimiadapter.Account;
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
@@ -47,6 +49,8 @@ import com.sap.sse.mongodb.MongoDBService;
public class WebSocketTest {
private static final Logger logger = Logger.getLogger(WebSocketTest.class.getName());
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(1 * 60 * 1000);
@WebSocket
public class SimpleEchoTestSocket {
private final CountDownLatch closeLatch;
@@ -1002,6 +1002,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
}
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogUseCompetitorsFromRaceLogEvent event) {
BasicDBObject result = new BasicDBObject();
storeRaceLogIdentifier(raceLogIdentifier, result);
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogUseCompetitorsFromRaceLogEvent(event));
return result;
}
public DBObject storeRaceLogUseCompetitorsFromRaceLogEvent(RaceLogUseCompetitorsFromRaceLogEvent event) {
DBObject result = new BasicDBObject();
storeRaceLogEventProperties(event, result);
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogUseCompetitorsFromRaceLogEvent.class.getSimpleName());
@@ -1,94 +1,94 @@
package com.sap.sailing.domain.racelogtracking.test;
import static com.sap.sse.common.Util.size;
import static junit.framework.Assert.assertEquals;
import java.util.UUID;
import org.junit.After;
import org.junit.Before;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
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.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
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.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoGPSFixStoreImpl;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.tracking.Track;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.deserialization.impl.DeviceAndSessionIdentifierWithGPSFixesDeserializer;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class AbstractGPSFixStoreTest {
protected RacingEventService service;
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
DeviceAndSessionIdentifierWithGPSFixesDeserializer deserializer =
new MockDeviceAndSessionIdentifierWithGPSFixesDeserializer();
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
protected RaceLog raceLog;
protected RegattaLog regattaLog;
protected GPSFixStore store;
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
}
@Before
public void setServiceAndRaceLog() {
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
raceLog = new RaceLogImpl("racelog");
regattaLog = new RegattaLogImpl("regattalog");
store = new MongoGPSFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
serviceFinderFactory);
}
@After
public void after() {
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
mongoOF.getGPSFixCollection().drop();
mongoOF.getGPSFixMetadataCollection().drop();
}
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
map(regattaLog, comp, device, from, to);
}
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
protected void testNumberOfRawFixes(Track<?> track, long expected) {
track.lockForRead();
assertEquals(expected, size(track.getRawFixes()));
track.unlockAfterRead();
}
}
package com.sap.sailing.domain.racelogtracking.test;
import static com.sap.sse.common.Util.size;
import static junit.framework.Assert.assertEquals;
import java.util.UUID;
import org.junit.After;
import org.junit.Before;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
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.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
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.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoGPSFixStoreImpl;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.tracking.Track;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.deserialization.impl.DeviceAndSessionIdentifierWithGPSFixesDeserializer;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class AbstractGPSFixStoreTest {
protected RacingEventService service;
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
DeviceAndSessionIdentifierWithGPSFixesDeserializer deserializer =
new MockDeviceAndSessionIdentifierWithGPSFixesDeserializer();
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
protected RaceLog raceLog;
protected RegattaLog regattaLog;
protected GPSFixStore store;
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
}
@Before
public void setServiceAndRaceLog() {
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
raceLog = new RaceLogImpl("racelog");
regattaLog = new RegattaLogImpl("regattalog");
store = new MongoGPSFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
serviceFinderFactory);
}
@After
public void after() {
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
mongoOF.getGPSFixCollection().drop();
mongoOF.getGPSFixMetadataCollection().drop();
}
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
map(regattaLog, comp, device, from, to);
}
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
protected void testNumberOfRawFixes(Track<?> track, long expected) {
track.lockForRead();
assertEquals(expected, size(track.getRawFixes()));
track.unlockAfterRead();
}
}
@@ -170,7 +170,7 @@ public class CreateAndTrackWithRaceLogTest {
// add a mapping and one fix in, one out of mapping
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(0), t(10)));
addFixes0(dev1);
@@ -206,7 +206,7 @@ public class CreateAndTrackWithRaceLogTest {
// add a mapping and one fix in, one out of mapping
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, UUID.randomUUID(), comp1, dev1,
t(0), t(10)));
@@ -1,150 +1,150 @@
package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
@Test
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
map(comp, device, 0, 10000);
map(mark, markDevice, 0, 10000);
store.storeFix(device, createFix(100, 10, 20, 30, 40)); // before
store.storeFix(device, createFix(1100, 10, 20, 30, 40)); // in
store.storeFix(device, createFix(2100, 10, 20, 30, 40)); // after
store.storeFix(markDevice, createFix(100, 10, 20, 30, 40));
store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40));
store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40));
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000));
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
// now extend the tracking interval of the tracked race and assert that the additional fixes are loaded
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500), /* wait for fixes to load */ true);
testNumberOfRawFixes(trackedRace.getTrack(comp), 2);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0), /* wait for fixes to load */ true);
testNumberOfRawFixes(trackedRace.getTrack(comp), 3);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3);
}
@Test
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException,
InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp,
comp2 }));
map(comp, device, 0, 20000);
map(comp2, device2, 0, 600);
// reuse device for two marks
map(mark, device3, 0, 600);
map(mark2, device3, 0, 600);
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(200, 10, 20, 30, 40));
store.storeFix(device2, createFix(100, 10, 20, 30, 40));
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
for (int i = 0; i < 10000; i++) {
store.storeFix(device, createFix(i + 1000, 10, 20, 30, 40));
}
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 10002);
testNumberOfRawFixes(trackedRace.getTrack(comp2), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
}
@Test
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
assertEquals(0, store.getNumberOfFixes(device));
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
map(comp, device, 0, 600);
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(200, 10, 20, 30, 40));
assertEquals(2, store.getNumberOfFixes(device));
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
}
}
package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
@Test
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
map(comp, device, 0, 10000);
map(mark, markDevice, 0, 10000);
store.storeFix(device, createFix(100, 10, 20, 30, 40)); // before
store.storeFix(device, createFix(1100, 10, 20, 30, 40)); // in
store.storeFix(device, createFix(2100, 10, 20, 30, 40)); // after
store.storeFix(markDevice, createFix(100, 10, 20, 30, 40));
store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40));
store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40));
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000));
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
// now extend the tracking interval of the tracked race and assert that the additional fixes are loaded
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500), /* wait for fixes to load */ true);
testNumberOfRawFixes(trackedRace.getTrack(comp), 2);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0), /* wait for fixes to load */ true);
testNumberOfRawFixes(trackedRace.getTrack(comp), 3);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3);
}
@Test
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException,
InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp,
comp2 }));
map(comp, device, 0, 20000);
map(comp2, device2, 0, 600);
// reuse device for two marks
map(mark, device3, 0, 600);
map(mark2, device3, 0, 600);
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(200, 10, 20, 30, 40));
store.storeFix(device2, createFix(100, 10, 20, 30, 40));
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
for (int i = 0; i < 10000; i++) {
store.storeFix(device, createFix(i + 1000, 10, 20, 30, 40));
}
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 10002);
testNumberOfRawFixes(trackedRace.getTrack(comp2), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
}
@Test
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
assertEquals(0, store.getNumberOfFixes(device));
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
map(comp, device, 0, 600);
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(200, 10, 20, 30, 40));
assertEquals(2, store.getNumberOfFixes(device));
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
}
}
@@ -54,7 +54,7 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
public void testStartTimeInferencePrecedenceOrder() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
@@ -1,5 +1,5 @@
trackingInvitationFor=Einladung zum Tracken für
scanQRCodeOrVisitUrlToRegisterAs=Installiere die SAP Sailing Boat Tracker App. Dann scanne den QRCode oder klicke den Link mit deinem Smartphone an, um dich zu registrieren als
scanQRCodeOrVisitUrlToRegisterAs=Installiere die {0} App. Dann scanne den QRCode oder klicke den Link mit deinem Smartphone an, um dich zu registrieren als
welcomeTo=Willkommen zu
iOSUsers=iOS App starten
androidUsers=Android App starten
@@ -7,4 +7,6 @@ alternativelyVisitThisLink=Wenn die App bereits installiert ist, und du diese Ma
buoyTender=Bojenleger
appStoreInstallText=Falls die App noch nicht installiert ist, kannst du sie hier finden:Ÿ
appIos=iOS App installieren
appAndroid=Android App installieren
appAndroid=Android App installieren
buoyPingerAppName=SAP Sailing Buoy Pinger
sailInSightAppName=SAP Sail InSight
@@ -1,5 +1,5 @@
trackingInvitationFor=Tracking Invitation for
scanQRCodeOrVisitUrlToRegisterAs=Make sure you have the SAP Sailing Boat Tracker App installed. Then scan the following QRCode or click the link using your smartphone to register as
scanQRCodeOrVisitUrlToRegisterAs=Make sure you have the {0} App installed. Then scan the following QRCode or click the link using your smartphone to register as
welcomeTo=Welcome to
iOSUsers=Start iOS App
androidUsers=Start Android App
@@ -7,4 +7,6 @@ alternativelyVisitThisLink=If you are reading this mail on the device with the A
buoyTender=buoy tender
appStoreInstallText=If don't have the App yet, please install:
appIos=Install iOS App
appAndroid=Install Android App
appAndroid=Install Android App
buoyPingerAppName=SAP Sailing Buoy Pinger
sailInSightAppName=SAP Sail InSight
@@ -532,7 +532,22 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
for (DeviceMapping<Mark> mapping : markMappingsByDevices.get(device)) {
Mark mark = mapping.getMappedTo();
if (mapping.getTimeRange().includes(timePoint)) {
trackedRace.recordFix(mark, fix);
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
final GPSFix firstFixAtOrAfter;
boolean forceFix;
markTrack.lockForRead();
try {
forceFix = Util.isEmpty(markTrack.getRawFixes()) ||
(firstFixAtOrAfter=markTrack.getFirstFixAtOrAfter(timePoint)) != null &&
firstFixAtOrAfter.getTimePoint().equals(timePoint);
} finally {
markTrack.unlockAfterRead();
}
if (forceFix) {
trackedRace.recordFix(mark, fix, /* only when in tracking interval */ false); // force fix into track
} else {
trackedRace.recordFix(mark, fix);
}
}
}
}
@@ -298,8 +298,9 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
logoUrl = imagesWithTag.get(0).getURL().toString();
}
try {
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName, url, iOSAppUrl,
androidAppUrl, logoUrl);
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName, url, B.get(locale, "sailInSightAppName"),
iOSAppUrl, androidAppUrl, logoUrl);
} catch (MailException e) {
occuredExceptions.append(e.getMessage() + "\r\n");
}
@@ -311,7 +312,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
private void sendInvitationEmail(Locale locale, final String toAddress, String leaderboardName, String invitee,
String url, String iOSAppUrl, String androidAppUrl, String logoUrl) throws MailException {
String url, String appName, String iOSAppUrl, String androidAppUrl, String logoUrl) throws MailException {
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
String subject = String.format("%s %s", B.get(locale, "trackingInvitationFor"), invitee);
@@ -338,7 +339,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
htmlText.append("<p><img src=\"").append(logoUrl).append("\" /></p> ");
}
htmlText.append("<h1>").append(B.get(locale, "welcomeTo")).append(" ").append(leaderboardName).append("</h1> ");
htmlText.append("<p>").append(B.get(locale, "scanQRCodeOrVisitUrlToRegisterAs")).append(" <b>").append(invitee)
htmlText.append("<p>").append(B.get(locale, "scanQRCodeOrVisitUrlToRegisterAs", appName)).append(" <b>").append(invitee)
.append("</b></p> ");
htmlText.append("<p class=\"qr\"><img src=\"cid:image\" title=\"").append(url).append("\" /></p> ");
htmlText.append("<p class=\"spacer\">").append(B.get(locale, "alternativelyVisitThisLink")).append("</p> ");
@@ -407,9 +408,10 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
eventId, NonGwtUrlHelper.INSTANCE);
for (String toAddress : emailArray) {
try {
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
sendInvitationEmail(locale, toAddress, leaderboardName,
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url, iOSAppUrl, androidAppUrl,
logoUrl);
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url, B.get(locale, "buoyPingerAppName"), iOSAppUrl,
androidAppUrl, logoUrl);
} catch (MailException e) {
occuredExceptions.append(e.getMessage() + "\r\n");
}
@@ -19,8 +19,8 @@ import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class CompetitorDeregistrationTest extends AbstractRegattaLogTrackingTest {
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
@Test
public void testCompetitorDeregistration() {
@@ -27,8 +27,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class DeviceMappingFinderTest extends AbstractRegattaLogTrackingTest {
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final DeviceIdentifier device = new SmartphoneImeiIdentifier("imei");
private int time = 0;
@@ -23,6 +23,8 @@ public interface Competitor extends Named, WithID, IsManagedByCache<SharedDomain
boolean hasEmail();
String getSearchTag();
/**
* an alternative flag image (per default the nation flag
* @return the URI of the flag image
@@ -1,20 +1,22 @@
package com.sap.sailing.domain.base;
import java.net.URI;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface CompetitorChangeListener extends BoatChangeListener, NationalityChangeListener {
void colorChanged(Color oldColor, Color newColor);
void nameChanged(String oldName, String newName);
void emailChanged(String oldEmail, String newEmail);
void flagImageChanged(URI oldFlagImageURI, URI newFlagImageURI);
void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor);
void timeOnDistanceAllowancePerNauticalMileChanged(Duration oldTimeOnDistanceAllowancePerNauticalMile, Duration newTimeOnDistanceAllowancePerNauticalMile);
}
package com.sap.sailing.domain.base;
import java.net.URI;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface CompetitorChangeListener extends BoatChangeListener, NationalityChangeListener {
void colorChanged(Color oldColor, Color newColor);
void nameChanged(String oldName, String newName);
void emailChanged(String oldEmail, String newEmail);
void searchTagChanged(String oldSearchTag, String newSearchTag);
void flagImageChanged(URI oldFlagImageURI, URI newFlagImageURI);
void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor);
void timeOnDistanceAllowancePerNauticalMileChanged(Duration oldTimeOnDistanceAllowancePerNauticalMile, Duration newTimeOnDistanceAllowancePerNauticalMile);
}
@@ -1,33 +1,33 @@
package com.sap.sailing.domain.base;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Base interface for classes managing a set of {@link Competitor} objects.
*/
public interface CompetitorFactory {
/**
* If a valid competitor is returned and the caller has information available that could be used to update the competitor,
* the caller must check the result of {@link #isCompetitorToUpdateDuringGetOrCreate(Competitor)}, and if <code>true</code>,
* must call {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} to cause an update of the
* competitor's values.
*/
Competitor getExistingCompetitorById(Serializable competitorId);
/**
* Checks if the <code>competitor</code> shall be updated from the default provided by, e.g., a tracking infrastructure.
* Callers of {@link #getExistingCompetitorById(Serializable)} or {@link #getExistingCompetitorByIdAsString(String)}
* must call this method in case they retrieve a valid competitor by ID and have data available that can be used to update
* the competitor.
*/
boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result);
Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImageURI, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile);
}
package com.sap.sailing.domain.base;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Base interface for classes managing a set of {@link Competitor} objects.
*/
public interface CompetitorFactory {
/**
* If a valid competitor is returned and the caller has information available that could be used to update the competitor,
* the caller must check the result of {@link #isCompetitorToUpdateDuringGetOrCreate(Competitor)}, and if <code>true</code>,
* must call {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} to cause an update of the
* competitor's values.
*/
Competitor getExistingCompetitorById(Serializable competitorId);
/**
* Checks if the <code>competitor</code> shall be updated from the default provided by, e.g., a tracking infrastructure.
* Callers of {@link #getExistingCompetitorById(Serializable)} or {@link #getExistingCompetitorByIdAsString(String)}
* must call this method in case they retrieve a valid competitor by ID and have data available that can be used to update
* the competitor.
*/
boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result);
Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImageURI, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag);
}
@@ -1,80 +1,80 @@
package com.sap.sailing.domain.base;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Manages a set of {@link Competitor} objects. There may be a transient implementation based on a simple cache,
* and there may be persistent implementations.
*
* @author Axel Uhl (d043530)
*
*/
public interface CompetitorStore extends CompetitorFactory {
public interface CompetitorUpdateListener {
void competitorUpdated(Competitor competitor);
}
/**
* If a valid competitor is returned and the caller has information available that could be used to update the competitor,
* the caller must check the result of {@link #isCompetitorToUpdateDuringGetOrCreate(Competitor)}, and if <code>true</code>,
* must call {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} to cause an update of the
* competitor's values.
*/
Competitor getExistingCompetitorByIdAsString(String idAsString);
/**
* When a competitor is queried using {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)}
* , and the competitor object for that ID already exists, it is generally returned unchanged, and the name, team
* and boat parameters are not evaluated. This makes the data in this competitor store generally "write-once." This
* method can be used to reset a competitor object to what a tracking provider or an external system supplies to
* {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)}. After calling this method, the
* next call to {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} with
* <code>competitor</code>'s {@link Competitor#getId() ID} will
* {@link #updateCompetitor(String, String, String, Nationality)} the competitor in its updatable properties such as
* the name, the sail ID and the nationality.
*/
void allowCompetitorResetToDefaults(Competitor competitor);
int size();
/**
* Removes all competitors from this store. Use with due care.
*/
void clear();
/**
* Obtains a non-live snapshot of the list of competitors managed by this store.
*/
Iterable<? extends Competitor> getCompetitors();
void removeCompetitor(Competitor competitor);
/**
* Updates the competitor with {@link Competitor#getId() ID} <code>id</code> by setting the name, sail ID and nationality to
* the values provided. Doing so will not fire any events nor will it replicate this change from a master to any replicas.
* The calling client has to make sure that the changes applied will reach replicas and all other interested clients. It will
* be sufficient to ensure that subsequent DTOs produced from the competitor modified will reflect the changes.<p>
*
* If no competitor with the ID requested is found, the call is a no-op, doing nothing, not even throwing an exception.
*/
Competitor updateCompetitor(String idAsString, String newName, Color newDisplayColor, String newEmail,
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile);
CompetitorDTO convertToCompetitorDTO(Competitor c);
/**
* Listeners added here are notified whenever {@link #updateCompetitor(String, String, Color, String, Nationality)} is called
* for any competitor in this store.
*/
void addCompetitorUpdateListener(CompetitorUpdateListener listener);
void removeCompetitorUpdateListener(CompetitorUpdateListener listener);
}
package com.sap.sailing.domain.base;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Manages a set of {@link Competitor} objects. There may be a transient implementation based on a simple cache,
* and there may be persistent implementations.
*
* @author Axel Uhl (d043530)
*
*/
public interface CompetitorStore extends CompetitorFactory {
public interface CompetitorUpdateListener {
void competitorUpdated(Competitor competitor);
}
/**
* If a valid competitor is returned and the caller has information available that could be used to update the competitor,
* the caller must check the result of {@link #isCompetitorToUpdateDuringGetOrCreate(Competitor)}, and if <code>true</code>,
* must call {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} to cause an update of the
* competitor's values.
*/
Competitor getExistingCompetitorByIdAsString(String idAsString);
/**
* When a competitor is queried using {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)}
* , and the competitor object for that ID already exists, it is generally returned unchanged, and the name, team
* and boat parameters are not evaluated. This makes the data in this competitor store generally "write-once." This
* method can be used to reset a competitor object to what a tracking provider or an external system supplies to
* {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)}. After calling this method, the
* next call to {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} with
* <code>competitor</code>'s {@link Competitor#getId() ID} will
* {@link #updateCompetitor(String, String, String, Nationality)} the competitor in its updatable properties such as
* the name, the sail ID and the nationality.
*/
void allowCompetitorResetToDefaults(Competitor competitor);
int size();
/**
* Removes all competitors from this store. Use with due care.
*/
void clear();
/**
* Obtains a non-live snapshot of the list of competitors managed by this store.
*/
Iterable<? extends Competitor> getCompetitors();
void removeCompetitor(Competitor competitor);
/**
* Updates the competitor with {@link Competitor#getId() ID} <code>id</code> by setting the name, sail ID and nationality to
* the values provided. Doing so will not fire any events nor will it replicate this change from a master to any replicas.
* The calling client has to make sure that the changes applied will reach replicas and all other interested clients. It will
* be sufficient to ensure that subsequent DTOs produced from the competitor modified will reflect the changes.<p>
*
* If no competitor with the ID requested is found, the call is a no-op, doing nothing, not even throwing an exception.
*/
Competitor updateCompetitor(String idAsString, String newName, Color newDisplayColor, String newEmail,
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag);
CompetitorDTO convertToCompetitorDTO(Competitor c);
/**
* Listeners added here are notified whenever {@link #updateCompetitor(String, String, Color, String, Nationality)} is called
* for any competitor in this store.
*/
void addCompetitorUpdateListener(CompetitorUpdateListener listener);
void removeCompetitorUpdateListener(CompetitorUpdateListener listener);
}
@@ -20,6 +20,7 @@ public class CompetitorImpl implements DynamicCompetitor {
private final DynamicBoat boat;
private final Serializable id;
private String name;
private String searchTag;
private Color color;
private transient Set<CompetitorChangeListener> listeners;
private String email;
@@ -27,7 +28,7 @@ public class CompetitorImpl implements DynamicCompetitor {
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorImpl(Serializable id, String name, Color color, String email, URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
public CompetitorImpl(Serializable id, String name, Color color, String email, URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
this.id = id;
this.name = name;
this.team = team;
@@ -37,6 +38,7 @@ public class CompetitorImpl implements DynamicCompetitor {
this.flagImage = flagImage;
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
this.searchTag = searchTag;
this.listeners = new HashSet<CompetitorChangeListener>();
}
@@ -85,10 +87,11 @@ public class CompetitorImpl implements DynamicCompetitor {
public Competitor resolve(SharedDomainFactory domainFactory) {
Competitor result = domainFactory
.getOrCreateCompetitor(getId(), getName(), getColor(), getEmail(), getFlagImage(), getTeam(),
getBoat(), getTimeOnTimeFactor(), getTimeOnDistanceAllowancePerNauticalMile());
getBoat(), getTimeOnTimeFactor(), getTimeOnDistanceAllowancePerNauticalMile(), searchTag);
return result;
}
@Override
public Color getColor() {
return color;
}
@@ -127,6 +130,22 @@ public class CompetitorImpl implements DynamicCompetitor {
}
}
@Override
public String getSearchTag() {
return searchTag;
}
public void setSearchTag(String newSearchTag) {
final String oldSearchTag = this.searchTag;
if (!Util.equalsWithNull(oldSearchTag, newSearchTag)) {
this.searchTag = newSearchTag;
for (CompetitorChangeListener listener : getListeners()) {
listener.searchTagChanged(oldSearchTag, newSearchTag);
}
}
}
@Override
public String getEmail() {
return email;
}
@@ -141,6 +160,7 @@ public class CompetitorImpl implements DynamicCompetitor {
}
}
@Override
public boolean hasEmail(){
return email != null && !email.isEmpty();
}
@@ -1,24 +1,26 @@
package com.sap.sailing.domain.base.impl;
import java.net.URI;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Renamable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface DynamicCompetitor extends Competitor, Renamable {
DynamicBoat getBoat();
DynamicTeam getTeam();
void setColor(Color displayColor);
void setEmail(String email);
void setFlagImage(URI flagImage);
void setTimeOnTimeFactor(Double timeOnTimeFactor);
void setTimeOnDistanceAllowancePerNauticalMile(Duration timeOnDistanceAllowancePerNauticalMile);
}
package com.sap.sailing.domain.base.impl;
import java.net.URI;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Renamable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface DynamicCompetitor extends Competitor, Renamable {
DynamicBoat getBoat();
DynamicTeam getTeam();
void setColor(Color displayColor);
void setEmail(String email);
void setSearchTag(String searchTag);
void setFlagImage(URI flagImage);
void setTimeOnTimeFactor(Double timeOnTimeFactor);
void setTimeOnDistanceAllowancePerNauticalMile(Duration timeOnDistanceAllowancePerNauticalMile);
}
@@ -1,379 +1,379 @@
package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
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.Mark;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
import com.sap.sailing.domain.common.BoatClassMasterdata;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.WithID;
public class SharedDomainFactoryImpl implements SharedDomainFactory {
private static final Logger logger = Logger.getLogger(SharedDomainFactoryImpl.class.getName());
/**
* Ensure that the <em>same</em> string is used as key that is also used to set the {@link Nationality}
* object's {@link Nationality#getThreeLetterIOCAcronym() IOC code}.
*/
private final Map<String, Nationality> nationalityCache;
private final Map<Serializable, Mark> markCache;
private final Map<Serializable, ControlPointWithTwoMarks> controlPointWithTwoMarksCache;
/**
* For all marks ever created by this factory, the mark {@link WithID#getId() ID}'s string representation
* is mapped here to the actual ID. This allows clients to send only the string representation to the server
* and still be able to identify a mark uniquely this way.
*/
private final Map<String, Serializable> markIdCache;
/**
* For all ControlPoints ever created by this factory, the mark {@link WithID#getId() ID}'s string representation
* is mapped here to the actual ID. This allows clients to send only the string representation to the server
* and still be able to identify a ControlPoint uniquely this way.
*/
private final Map<String, Serializable> controlPointWithTwoMarksIdCache;
private final Map<String, BoatClass> boatClassCache;
protected final CompetitorStore competitorStore;
private final Map<Serializable, CourseArea> courseAreaCache;
/**
* Weakly references the waypoints. If a waypoint is no longer strongly referenced, the corresponding reference contained
* as value will have its referred object be <code>null</code>. In this case, the methods reading from this cache will purge
* the record and behave as if the record hadn't existed at the time of the read operation.
*/
private final ConcurrentHashMap<Serializable, WeakWaypointReference> waypointCache;
private final ReferenceQueue<Waypoint> waypointCacheReferenceQueue;
private final Map<Serializable, DeviceConfigurationMatcher> configurationMatcherCache;
/**
* Weak references to {@link Waypoint} objects of this type are registered with
* {@link DomainFactoryImpl#waypointCacheReferenceQueue} upon construction so that when their referents are no
* longer strongly referenced and the reference was nulled, they are entered into that queue.
* Methods managing the {@link #waypointCache} can poll the queue and then remove cache entries based on
* the {@link #id} stored in the reference.
*
* @author Axel Uhl (D043530)
*
*/
private class WeakWaypointReference extends WeakReference<Waypoint> {
private final Serializable id;
public WeakWaypointReference(Waypoint waypoint) {
super(waypoint, waypointCacheReferenceQueue);
this.id = waypoint.getId();
}
public void removeCacheEntry() {
waypointCache.remove(id);
}
}
/**
* Holds the canonicalized boat class names which are known to maybe start other than with an upwind leg.
* The boat class name used here is obtained by using {@link BoatClassMasterdata#unifyBoatClassName(String)}.
*/
private final Set<String> mayStartWithNoUpwindLeg;
private final RaceLogResolver raceLogResolver;
/**
* Uses a transient competitor store
*/
public SharedDomainFactoryImpl(RaceLogResolver raceLogResolver) {
this(new TransientCompetitorStoreImpl(), raceLogResolver);
}
public SharedDomainFactoryImpl(CompetitorStore competitorStore, RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
nationalityCache = new HashMap<String, Nationality>();
markCache = new HashMap<Serializable, Mark>();
markIdCache = new HashMap<String, Serializable>();
controlPointWithTwoMarksCache = new HashMap<Serializable, ControlPointWithTwoMarks>();
controlPointWithTwoMarksIdCache = new HashMap<String, Serializable>();
boatClassCache = new HashMap<String, BoatClass>();
this.competitorStore = competitorStore;
waypointCache = new ConcurrentHashMap<Serializable, WeakWaypointReference>();
// FIXME ass also bug 3347: mapping to lower case should rather work through a common unification / canonicalization of boat class names
mayStartWithNoUpwindLeg = Collections.singleton(BoatClassMasterdata.unifyBoatClassName(BoatClassMasterdata.EXTREME_40.getDisplayName()));
courseAreaCache = new HashMap<Serializable, CourseArea>();
configurationMatcherCache = new HashMap<Serializable, DeviceConfigurationMatcher>();
}
@Override
public Nationality getOrCreateNationality(String threeLetterIOCCode) {
if (threeLetterIOCCode == null) {
threeLetterIOCCode = " ";
}
synchronized (nationalityCache) {
Nationality result = nationalityCache.get(threeLetterIOCCode);
if (result == null) {
result = new NationalityImpl(threeLetterIOCCode);
nationalityCache.put(threeLetterIOCCode, result);
}
return result;
}
}
@Override
public Mark getOrCreateMark(String name) {
return getOrCreateMark(name, name);
}
@Override
public Mark getOrCreateMark(Serializable id, String name) {
return getOrCreateMark(id, name, null, null, null, null);
}
@Override
public Mark getOrCreateMark(String toStringRepresentationOfID, String name) {
return getOrCreateMark(toStringRepresentationOfID, name, null, null, null, null);
}
@Override
public Mark getOrCreateMark(Serializable id, String name, MarkType type, String color, String shape, String pattern) {
Mark result = markCache.get(id);
if (result == null) {
result = new MarkImpl(id, name, type, color, shape, pattern);
cacheMark(id, result);
}
return result;
}
@Override
public Mark getOrCreateMark(String toStringRepresentationOfID, String name, MarkType type,
String color, String shape, String pattern) {
Serializable id = toStringRepresentationOfID;
if (markIdCache.containsKey(toStringRepresentationOfID)) {
id = markIdCache.get(toStringRepresentationOfID);
}
return getOrCreateMark(id, name, type, color, shape, pattern);
}
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(Serializable id, String name, Mark left, Mark right) {
final ControlPointWithTwoMarks result;
final ControlPointWithTwoMarks fromCache = controlPointWithTwoMarksCache.get(id);
if (fromCache != null) {
result = fromCache;
} else {
result = createControlPointWithTwoMarks(id, left, right, name);
}
return result;
}
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(
String toStringRepresentationOfID, String name, Mark left, Mark right) {
Serializable id = toStringRepresentationOfID;
if (controlPointWithTwoMarksIdCache.containsKey(toStringRepresentationOfID)) {
id = controlPointWithTwoMarksIdCache.get(toStringRepresentationOfID);
}
return getOrCreateControlPointWithTwoMarks(id, name, left, right);
}
private void cacheMark(Serializable id, Mark result) {
markCache.put(id, result);
markIdCache.put(id.toString(), id);
}
@Override
public ControlPointWithTwoMarks createControlPointWithTwoMarks(Mark left, Mark right, String name) {
return createControlPointWithTwoMarks(name, left, right, name);
}
@Override
public ControlPointWithTwoMarks createControlPointWithTwoMarks(Serializable id, Mark left, Mark right, String name) {
ControlPointWithTwoMarks result = new ControlPointWithTwoMarksImpl(id, left, right, name);
controlPointWithTwoMarksCache.put(id, result);
controlPointWithTwoMarksIdCache.put(id.toString(), id);
return result;
}
@Override
public Waypoint createWaypoint(ControlPoint controlPoint, PassingInstruction passingInstruction) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = passingInstruction == null ?
new WaypointImpl(controlPoint) : new WaypointImpl(controlPoint, passingInstruction);
waypointCache.put(result.getId(), new WeakWaypointReference(result));
return result;
}
}
@Override
public Waypoint getExistingWaypointById(Waypoint waypointPrototype) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = null;
Reference<Waypoint> ref = waypointCache.get(waypointPrototype.getId());
if (ref != null) {
result = ref.get();
if (result == null) {
// waypoint was finalized; remove entry from cache
waypointCache.remove(waypointPrototype.getId());
}
}
return result;
}
}
@Override
public Waypoint getExistingWaypointByIdOrCache(Waypoint waypoint) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = null;
Reference<Waypoint> ref = waypointCache.get(waypoint.getId());
if (ref != null) {
result = ref.get();
if (result == null) {
// waypoint was finalized; remove entry from cache and add anew
result = waypoint;
waypointCache.put(waypoint.getId(), new WeakWaypointReference(waypoint));
} // else, result is the waypoint found in the cache; return it
} else {
// No entry found in the cache; not even a stale, finalized one. Create a new entry:
result = waypoint;
waypointCache.put(waypoint.getId(), new WeakWaypointReference(waypoint));
}
return result;
}
}
private void expungeStaleWaypointCacheEntries() {
Reference<? extends Waypoint> ref;
while ((ref=waypointCacheReferenceQueue.poll()) != null) {
((WeakWaypointReference) ref).removeCacheEntry();
}
}
@Override
public BoatClass getOrCreateBoatClass(String name, boolean typicallyStartsUpwind) {
final BoatClassMasterdata boatClassMasterdata = BoatClassMasterdata.resolveBoatClass(name);
final String unifiedBoatClassName = BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(name);
BoatClass result;
synchronized (boatClassCache) {
result = boatClassCache.get(unifiedBoatClassName);
if (result == null) {
if (unifiedBoatClassName != null && boatClassMasterdata != null) {
result = new BoatClassImpl(boatClassMasterdata.getDisplayName(), boatClassMasterdata);
} else {
result = new BoatClassImpl(unifiedBoatClassName, typicallyStartsUpwind);
}
boatClassCache.put(unifiedBoatClassName, result);
}
return result;
}
}
@Override
public BoatClass getOrCreateBoatClass(final String name) {
final String unifiedBoatClassName = BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(name);
return getOrCreateBoatClass(name, name == null || /* typicallyStartsUpwind */ !mayStartWithNoUpwindLeg.contains(unifiedBoatClassName));
}
@Override
public CourseArea getOrCreateCourseArea(UUID courseAreaId, String name) {
CourseArea result = getExistingCourseAreaById(courseAreaId);
if (result == null) {
result = new CourseAreaImpl(name, courseAreaId);
courseAreaCache.put(courseAreaId, result);
}
return result;
}
@Override
public CourseArea getExistingCourseAreaById(Serializable courseAreaId) {
return courseAreaCache.get(courseAreaId);
}
@Override
public CompetitorStore getCompetitorStore() {
return competitorStore;
}
@Override
public Competitor getExistingCompetitorById(Serializable competitorId) {
return getCompetitorStore().getExistingCompetitorById(competitorId);
}
@Override
public boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result) {
return getCompetitorStore().isCompetitorToUpdateDuringGetOrCreate(result);
}
@Override
public Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor,
Duration timeOnDistanceAllowancePerNauticalMile) {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "getting or creating competitor "+name+" with ID "+competitorId+" in domain factory "+this);
}
return getCompetitorStore().getOrCreateCompetitor(competitorId, name, displayColor, email, flagImage, team,
boat, timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile);
}
@Override
public DeviceConfigurationMatcher getOrCreateDeviceConfigurationMatcher(List<String> clientIdentifiers) {
DeviceConfigurationMatcher probe = createMatcher(clientIdentifiers);
DeviceConfigurationMatcher matcher = configurationMatcherCache.get(probe.getMatcherIdentifier());
if (matcher == null) {
configurationMatcherCache.put(probe.getMatcherIdentifier(), probe);
matcher = probe;
}
return matcher;
}
private DeviceConfigurationMatcher createMatcher(List<String> clientIdentifiers) {
return new DeviceConfigurationMatcherSingle(clientIdentifiers.get(0));
}
@Override
public Mark getExistingMarkById(Serializable id) {
return markCache.get(id);
}
@Override
public Mark getExistingMarkByIdAsString(String toStringRepresentationOfID) {
return markCache.get(markIdCache.get(toStringRepresentationOfID));
}
@Override
public RaceLogResolver getRaceLogResolver() {
return raceLogResolver;
}
}
package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
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.Mark;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
import com.sap.sailing.domain.common.BoatClassMasterdata;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.WithID;
public class SharedDomainFactoryImpl implements SharedDomainFactory {
private static final Logger logger = Logger.getLogger(SharedDomainFactoryImpl.class.getName());
/**
* Ensure that the <em>same</em> string is used as key that is also used to set the {@link Nationality}
* object's {@link Nationality#getThreeLetterIOCAcronym() IOC code}.
*/
private final Map<String, Nationality> nationalityCache;
private final Map<Serializable, Mark> markCache;
private final Map<Serializable, ControlPointWithTwoMarks> controlPointWithTwoMarksCache;
/**
* For all marks ever created by this factory, the mark {@link WithID#getId() ID}'s string representation
* is mapped here to the actual ID. This allows clients to send only the string representation to the server
* and still be able to identify a mark uniquely this way.
*/
private final Map<String, Serializable> markIdCache;
/**
* For all ControlPoints ever created by this factory, the mark {@link WithID#getId() ID}'s string representation
* is mapped here to the actual ID. This allows clients to send only the string representation to the server
* and still be able to identify a ControlPoint uniquely this way.
*/
private final Map<String, Serializable> controlPointWithTwoMarksIdCache;
private final Map<String, BoatClass> boatClassCache;
protected final CompetitorStore competitorStore;
private final Map<Serializable, CourseArea> courseAreaCache;
/**
* Weakly references the waypoints. If a waypoint is no longer strongly referenced, the corresponding reference contained
* as value will have its referred object be <code>null</code>. In this case, the methods reading from this cache will purge
* the record and behave as if the record hadn't existed at the time of the read operation.
*/
private final ConcurrentHashMap<Serializable, WeakWaypointReference> waypointCache;
private final ReferenceQueue<Waypoint> waypointCacheReferenceQueue;
private final Map<Serializable, DeviceConfigurationMatcher> configurationMatcherCache;
/**
* Weak references to {@link Waypoint} objects of this type are registered with
* {@link DomainFactoryImpl#waypointCacheReferenceQueue} upon construction so that when their referents are no
* longer strongly referenced and the reference was nulled, they are entered into that queue.
* Methods managing the {@link #waypointCache} can poll the queue and then remove cache entries based on
* the {@link #id} stored in the reference.
*
* @author Axel Uhl (D043530)
*
*/
private class WeakWaypointReference extends WeakReference<Waypoint> {
private final Serializable id;
public WeakWaypointReference(Waypoint waypoint) {
super(waypoint, waypointCacheReferenceQueue);
this.id = waypoint.getId();
}
public void removeCacheEntry() {
waypointCache.remove(id);
}
}
/**
* Holds the canonicalized boat class names which are known to maybe start other than with an upwind leg.
* The boat class name used here is obtained by using {@link BoatClassMasterdata#unifyBoatClassName(String)}.
*/
private final Set<String> mayStartWithNoUpwindLeg;
private final RaceLogResolver raceLogResolver;
/**
* Uses a transient competitor store
*/
public SharedDomainFactoryImpl(RaceLogResolver raceLogResolver) {
this(new TransientCompetitorStoreImpl(), raceLogResolver);
}
public SharedDomainFactoryImpl(CompetitorStore competitorStore, RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
nationalityCache = new HashMap<String, Nationality>();
markCache = new HashMap<Serializable, Mark>();
markIdCache = new HashMap<String, Serializable>();
controlPointWithTwoMarksCache = new HashMap<Serializable, ControlPointWithTwoMarks>();
controlPointWithTwoMarksIdCache = new HashMap<String, Serializable>();
boatClassCache = new HashMap<String, BoatClass>();
this.competitorStore = competitorStore;
waypointCache = new ConcurrentHashMap<Serializable, WeakWaypointReference>();
// FIXME ass also bug 3347: mapping to lower case should rather work through a common unification / canonicalization of boat class names
mayStartWithNoUpwindLeg = Collections.singleton(BoatClassMasterdata.unifyBoatClassName(BoatClassMasterdata.EXTREME_40.getDisplayName()));
courseAreaCache = new HashMap<Serializable, CourseArea>();
configurationMatcherCache = new HashMap<Serializable, DeviceConfigurationMatcher>();
}
@Override
public Nationality getOrCreateNationality(String threeLetterIOCCode) {
if (threeLetterIOCCode == null) {
threeLetterIOCCode = " ";
}
synchronized (nationalityCache) {
Nationality result = nationalityCache.get(threeLetterIOCCode);
if (result == null) {
result = new NationalityImpl(threeLetterIOCCode);
nationalityCache.put(threeLetterIOCCode, result);
}
return result;
}
}
@Override
public Mark getOrCreateMark(String name) {
return getOrCreateMark(name, name);
}
@Override
public Mark getOrCreateMark(Serializable id, String name) {
return getOrCreateMark(id, name, null, null, null, null);
}
@Override
public Mark getOrCreateMark(String toStringRepresentationOfID, String name) {
return getOrCreateMark(toStringRepresentationOfID, name, null, null, null, null);
}
@Override
public Mark getOrCreateMark(Serializable id, String name, MarkType type, String color, String shape, String pattern) {
Mark result = markCache.get(id);
if (result == null) {
result = new MarkImpl(id, name, type, color, shape, pattern);
cacheMark(id, result);
}
return result;
}
@Override
public Mark getOrCreateMark(String toStringRepresentationOfID, String name, MarkType type,
String color, String shape, String pattern) {
Serializable id = toStringRepresentationOfID;
if (markIdCache.containsKey(toStringRepresentationOfID)) {
id = markIdCache.get(toStringRepresentationOfID);
}
return getOrCreateMark(id, name, type, color, shape, pattern);
}
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(Serializable id, String name, Mark left, Mark right) {
final ControlPointWithTwoMarks result;
final ControlPointWithTwoMarks fromCache = controlPointWithTwoMarksCache.get(id);
if (fromCache != null) {
result = fromCache;
} else {
result = createControlPointWithTwoMarks(id, left, right, name);
}
return result;
}
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(
String toStringRepresentationOfID, String name, Mark left, Mark right) {
Serializable id = toStringRepresentationOfID;
if (controlPointWithTwoMarksIdCache.containsKey(toStringRepresentationOfID)) {
id = controlPointWithTwoMarksIdCache.get(toStringRepresentationOfID);
}
return getOrCreateControlPointWithTwoMarks(id, name, left, right);
}
private void cacheMark(Serializable id, Mark result) {
markCache.put(id, result);
markIdCache.put(id.toString(), id);
}
@Override
public ControlPointWithTwoMarks createControlPointWithTwoMarks(Mark left, Mark right, String name) {
return createControlPointWithTwoMarks(name, left, right, name);
}
@Override
public ControlPointWithTwoMarks createControlPointWithTwoMarks(Serializable id, Mark left, Mark right, String name) {
ControlPointWithTwoMarks result = new ControlPointWithTwoMarksImpl(id, left, right, name);
controlPointWithTwoMarksCache.put(id, result);
controlPointWithTwoMarksIdCache.put(id.toString(), id);
return result;
}
@Override
public Waypoint createWaypoint(ControlPoint controlPoint, PassingInstruction passingInstruction) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = passingInstruction == null ?
new WaypointImpl(controlPoint) : new WaypointImpl(controlPoint, passingInstruction);
waypointCache.put(result.getId(), new WeakWaypointReference(result));
return result;
}
}
@Override
public Waypoint getExistingWaypointById(Waypoint waypointPrototype) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = null;
Reference<Waypoint> ref = waypointCache.get(waypointPrototype.getId());
if (ref != null) {
result = ref.get();
if (result == null) {
// waypoint was finalized; remove entry from cache
waypointCache.remove(waypointPrototype.getId());
}
}
return result;
}
}
@Override
public Waypoint getExistingWaypointByIdOrCache(Waypoint waypoint) {
synchronized (waypointCache) {
expungeStaleWaypointCacheEntries();
Waypoint result = null;
Reference<Waypoint> ref = waypointCache.get(waypoint.getId());
if (ref != null) {
result = ref.get();
if (result == null) {
// waypoint was finalized; remove entry from cache and add anew
result = waypoint;
waypointCache.put(waypoint.getId(), new WeakWaypointReference(waypoint));
} // else, result is the waypoint found in the cache; return it
} else {
// No entry found in the cache; not even a stale, finalized one. Create a new entry:
result = waypoint;
waypointCache.put(waypoint.getId(), new WeakWaypointReference(waypoint));
}
return result;
}
}
private void expungeStaleWaypointCacheEntries() {
Reference<? extends Waypoint> ref;
while ((ref=waypointCacheReferenceQueue.poll()) != null) {
((WeakWaypointReference) ref).removeCacheEntry();
}
}
@Override
public BoatClass getOrCreateBoatClass(String name, boolean typicallyStartsUpwind) {
final BoatClassMasterdata boatClassMasterdata = BoatClassMasterdata.resolveBoatClass(name);
final String unifiedBoatClassName = BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(name);
BoatClass result;
synchronized (boatClassCache) {
result = boatClassCache.get(unifiedBoatClassName);
if (result == null) {
if (unifiedBoatClassName != null && boatClassMasterdata != null) {
result = new BoatClassImpl(boatClassMasterdata.getDisplayName(), boatClassMasterdata);
} else {
result = new BoatClassImpl(unifiedBoatClassName, typicallyStartsUpwind);
}
boatClassCache.put(unifiedBoatClassName, result);
}
return result;
}
}
@Override
public BoatClass getOrCreateBoatClass(final String name) {
final String unifiedBoatClassName = BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(name);
return getOrCreateBoatClass(name, name == null || /* typicallyStartsUpwind */ !mayStartWithNoUpwindLeg.contains(unifiedBoatClassName));
}
@Override
public CourseArea getOrCreateCourseArea(UUID courseAreaId, String name) {
CourseArea result = getExistingCourseAreaById(courseAreaId);
if (result == null) {
result = new CourseAreaImpl(name, courseAreaId);
courseAreaCache.put(courseAreaId, result);
}
return result;
}
@Override
public CourseArea getExistingCourseAreaById(Serializable courseAreaId) {
return courseAreaCache.get(courseAreaId);
}
@Override
public CompetitorStore getCompetitorStore() {
return competitorStore;
}
@Override
public Competitor getExistingCompetitorById(Serializable competitorId) {
return getCompetitorStore().getExistingCompetitorById(competitorId);
}
@Override
public boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result) {
return getCompetitorStore().isCompetitorToUpdateDuringGetOrCreate(result);
}
@Override
public Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor,
Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "getting or creating competitor "+name+" with ID "+competitorId+" in domain factory "+this);
}
return getCompetitorStore().getOrCreateCompetitor(competitorId, name, displayColor, email, flagImage, team,
boat, timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
}
@Override
public DeviceConfigurationMatcher getOrCreateDeviceConfigurationMatcher(List<String> clientIdentifiers) {
DeviceConfigurationMatcher probe = createMatcher(clientIdentifiers);
DeviceConfigurationMatcher matcher = configurationMatcherCache.get(probe.getMatcherIdentifier());
if (matcher == null) {
configurationMatcherCache.put(probe.getMatcherIdentifier(), probe);
matcher = probe;
}
return matcher;
}
private DeviceConfigurationMatcher createMatcher(List<String> clientIdentifiers) {
return new DeviceConfigurationMatcherSingle(clientIdentifiers.get(0));
}
@Override
public Mark getExistingMarkById(Serializable id) {
return markCache.get(id);
}
@Override
public Mark getExistingMarkByIdAsString(String toStringRepresentationOfID) {
return markCache.get(markIdCache.get(toStringRepresentationOfID));
}
@Override
public RaceLogResolver getRaceLogResolver() {
return raceLogResolver;
}
}
@@ -1,276 +1,277 @@
package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
import com.sap.sse.common.Color;
import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Duration;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
public class TransientCompetitorStoreImpl implements CompetitorStore, Serializable {
private static final Logger logger = Logger.getLogger(TransientCompetitorStoreImpl.class.getName());
private static final long serialVersionUID = -4198298775476586931L;
private final Map<Serializable, Competitor> competitorCache;
private final Map<String, Competitor> competitorsByIdAsString;
private transient Set<CompetitorUpdateListener> listeners;
/**
* The competitors contained in this map will have their changeable properties
* {@link #updateCompetitor(String, String, String, Nationality) updated} upon the next call to
* {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} for their ID.
*/
private final Set<Competitor> competitorsToUpdateDuringGetOrCreate;
private transient WeakHashMap<Competitor, CompetitorDTO> weakCompetitorDTOCache;
private final NamedReentrantReadWriteLock lock;
public TransientCompetitorStoreImpl() {
lock = new NamedReentrantReadWriteLock("CompetitorStore", /* fair */ false);
competitorCache = new HashMap<Serializable, Competitor>();
competitorsByIdAsString = new HashMap<String, Competitor>();
competitorsToUpdateDuringGetOrCreate = new HashSet<Competitor>();
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
listeners = Collections.synchronizedSet(new HashSet<CompetitorStore.CompetitorUpdateListener>());
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
listeners = Collections.synchronizedSet(new HashSet<CompetitorStore.CompetitorUpdateListener>());
}
@Override
public void addCompetitorUpdateListener(CompetitorUpdateListener listener) {
listeners.add(listener);
}
@Override
public void removeCompetitorUpdateListener(CompetitorUpdateListener listener) {
listeners.remove(listener);
}
private Competitor createCompetitor(Serializable id, String name, Color displayColor, String email, URI flagImage,
DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
Competitor result = new CompetitorImpl(id, name, displayColor, email, flagImage, team, boat,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile);
addNewCompetitor(id, result);
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Created competitor "+name+" with ID "+id, new Exception("Here is where it happened"));
}
return result;
}
/**
* Adds the <code>competitor</code> to this transient competitor collection so that it is available in
* {@link #getExistingCompetitorById(Serializable)}. Subclasses may override in case they need to take additional
* measures such as durably storing the competitor. Overriding implementations must call this implementation.
*/
protected void addNewCompetitor(Serializable id, Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
competitorCache.put(id, competitor);
competitorsByIdAsString.put(id.toString(), competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor,
Duration timeOnDistanceAllowancePerNauticalMile) {
Competitor result = getExistingCompetitorById(competitorId); // avoid synchronization for successful read access
if (result == null) {
LockUtil.lockForWrite(lock);
try {
result = getExistingCompetitorById(competitorId); // try again, now while holding the write lock
if (result == null) {
result = createCompetitor(competitorId, name, displayColor, email, flagImage, team, boat,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile);
}
} finally {
LockUtil.unlockAfterWrite(lock);
}
} else if (isCompetitorToUpdateDuringGetOrCreate(result)) {
updateCompetitor(result.getId().toString(), name, displayColor, email, boat.getSailID(), team.getNationality(),
team.getImage(), flagImage, timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile);
competitorNoLongerToUpdateDuringGetOrCreate(result);
}
return result;
}
private void competitorNoLongerToUpdateDuringGetOrCreate(Competitor result) {
competitorsToUpdateDuringGetOrCreate.remove(result);
}
@Override
public boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result) {
return competitorsToUpdateDuringGetOrCreate.contains(result);
}
@Override
public Competitor getExistingCompetitorById(Serializable competitorId) {
LockUtil.lockForRead(lock);
try {
return competitorCache.get(competitorId);
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public Competitor getExistingCompetitorByIdAsString(String competitorIdAsString) {
LockUtil.lockForRead(lock);
try {
return competitorsByIdAsString.get(competitorIdAsString);
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public int size() {
LockUtil.lockForRead(lock);
try {
return competitorCache.size();
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public void clear() {
LockUtil.lockForWrite(lock);
try {
competitorCache.clear();
competitorsByIdAsString.clear();
competitorsToUpdateDuringGetOrCreate.clear();
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Clearing competitor store "+this, new Exception("here is where it happened"));
}
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Iterable<Competitor> getCompetitors() {
LockUtil.lockForRead(lock);
try {
return new ArrayList<Competitor>(competitorCache.values());
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public void removeCompetitor(Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
logger.fine("removing competitor "+competitor+" from competitor store "+this);
competitorCache.remove(competitor.getId());
competitorsByIdAsString.remove(competitor.getId().toString());
weakCompetitorDTOCache.remove(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Competitor updateCompetitor(String idAsString, String newName, Color newDisplayColor, String newEmail,
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
DynamicCompetitor competitor = (DynamicCompetitor) getExistingCompetitorByIdAsString(idAsString);
if (competitor != null) {
LockUtil.lockForWrite(lock);
try {
competitor.setName(newName);
competitor.setColor(newDisplayColor);
competitor.setEmail(newEmail);
competitor.setFlagImage(newFlagImageUri);
competitor.getBoat().setSailId(newSailId);
competitor.getTeam().setNationality(newNationality);
competitor.getTeam().setImage(newTeamImageUri);
competitor.setTimeOnTimeFactor(timeOnTimeFactor);
competitor.setTimeOnDistanceAllowancePerNauticalMile(timeOnDistanceAllowancePerNauticalMile);
weakCompetitorDTOCache.remove(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
synchronized (listeners) {
for (CompetitorUpdateListener listener : listeners) {
listener.competitorUpdated(competitor);
}
}
return competitor;
}
@Override
public CompetitorDTO convertToCompetitorDTO(Competitor c) {
LockUtil.lockForRead(lock);
boolean needToUnlockReadLock = true;
try {
CompetitorDTO competitorDTO = weakCompetitorDTOCache.get(c);
if (competitorDTO == null) {
LockUtil.unlockAfterRead(lock);
needToUnlockReadLock = false;
LockUtil.lockForWrite(lock);
competitorDTO = weakCompetitorDTOCache.get(c);
if (competitorDTO == null) {
final Nationality nationality = c.getTeam().getNationality();
CountryCode countryCode = nationality == null ? null : nationality.getCountryCode();
competitorDTO = new CompetitorDTOImpl(c.getName(), c.getColor(), c.getEmail(), countryCode == null ? ""
: countryCode.getTwoLetterISOCode(), countryCode == null ? ""
: countryCode.getThreeLetterIOCCode(), countryCode == null ? "" : countryCode.getName(),
c.getId().toString(),
c.getTeam().getImage() == null ? null : c.getTeam().getImage().toString(),
c.getFlagImage() == null ? null : c.getFlagImage().toString(),
new BoatDTO(c.getBoat().getName(), c.getBoat().getSailID(), c.getBoat().getColor()),
new BoatClassDTO(c.getBoat().getBoatClass()
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength().getMeters()),
c.getTimeOnTimeFactor(), c.getTimeOnDistanceAllowancePerNauticalMile());
weakCompetitorDTOCache.put(c, competitorDTO);
}
}
return competitorDTO;
} finally {
if (needToUnlockReadLock) {
LockUtil.unlockAfterRead(lock);
} else {
LockUtil.unlockAfterWrite(lock);
}
}
}
@Override
public void allowCompetitorResetToDefaults(Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
competitorsToUpdateDuringGetOrCreate.add(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
}
package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
import com.sap.sse.common.Color;
import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Duration;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
public class TransientCompetitorStoreImpl implements CompetitorStore, Serializable {
private static final Logger logger = Logger.getLogger(TransientCompetitorStoreImpl.class.getName());
private static final long serialVersionUID = -4198298775476586931L;
private final Map<Serializable, Competitor> competitorCache;
private final Map<String, Competitor> competitorsByIdAsString;
private transient Set<CompetitorUpdateListener> listeners;
/**
* The competitors contained in this map will have their changeable properties
* {@link #updateCompetitor(String, String, String, Nationality) updated} upon the next call to
* {@link #getOrCreateCompetitor(Serializable, String, DynamicTeam, DynamicBoat)} for their ID.
*/
private final Set<Competitor> competitorsToUpdateDuringGetOrCreate;
private transient WeakHashMap<Competitor, CompetitorDTO> weakCompetitorDTOCache;
private final NamedReentrantReadWriteLock lock;
public TransientCompetitorStoreImpl() {
lock = new NamedReentrantReadWriteLock("CompetitorStore", /* fair */ false);
competitorCache = new HashMap<Serializable, Competitor>();
competitorsByIdAsString = new HashMap<String, Competitor>();
competitorsToUpdateDuringGetOrCreate = new HashSet<Competitor>();
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
listeners = Collections.synchronizedSet(new HashSet<CompetitorStore.CompetitorUpdateListener>());
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
listeners = Collections.synchronizedSet(new HashSet<CompetitorStore.CompetitorUpdateListener>());
}
@Override
public void addCompetitorUpdateListener(CompetitorUpdateListener listener) {
listeners.add(listener);
}
@Override
public void removeCompetitorUpdateListener(CompetitorUpdateListener listener) {
listeners.remove(listener);
}
private Competitor createCompetitor(Serializable id, String name, Color displayColor, String email, URI flagImage,
DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
Competitor result = new CompetitorImpl(id, name, displayColor, email, flagImage, team, boat,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
addNewCompetitor(id, result);
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Created competitor "+name+" with ID "+id, new Exception("Here is where it happened"));
}
return result;
}
/**
* Adds the <code>competitor</code> to this transient competitor collection so that it is available in
* {@link #getExistingCompetitorById(Serializable)}. Subclasses may override in case they need to take additional
* measures such as durably storing the competitor. Overriding implementations must call this implementation.
*/
protected void addNewCompetitor(Serializable id, Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
competitorCache.put(id, competitor);
competitorsByIdAsString.put(id.toString(), competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Competitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email,
URI flagImage, DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor,
Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
Competitor result = getExistingCompetitorById(competitorId); // avoid synchronization for successful read access
if (result == null) {
LockUtil.lockForWrite(lock);
try {
result = getExistingCompetitorById(competitorId); // try again, now while holding the write lock
if (result == null) {
result = createCompetitor(competitorId, name, displayColor, email, flagImage, team, boat,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
}
} finally {
LockUtil.unlockAfterWrite(lock);
}
} else if (isCompetitorToUpdateDuringGetOrCreate(result)) {
updateCompetitor(result.getId().toString(), name, displayColor, email, boat.getSailID(), team.getNationality(),
team.getImage(), flagImage, timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
competitorNoLongerToUpdateDuringGetOrCreate(result);
}
return result;
}
private void competitorNoLongerToUpdateDuringGetOrCreate(Competitor result) {
competitorsToUpdateDuringGetOrCreate.remove(result);
}
@Override
public boolean isCompetitorToUpdateDuringGetOrCreate(Competitor result) {
return competitorsToUpdateDuringGetOrCreate.contains(result);
}
@Override
public Competitor getExistingCompetitorById(Serializable competitorId) {
LockUtil.lockForRead(lock);
try {
return competitorCache.get(competitorId);
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public Competitor getExistingCompetitorByIdAsString(String competitorIdAsString) {
LockUtil.lockForRead(lock);
try {
return competitorsByIdAsString.get(competitorIdAsString);
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public int size() {
LockUtil.lockForRead(lock);
try {
return competitorCache.size();
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public void clear() {
LockUtil.lockForWrite(lock);
try {
competitorCache.clear();
competitorsByIdAsString.clear();
competitorsToUpdateDuringGetOrCreate.clear();
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Clearing competitor store "+this, new Exception("here is where it happened"));
}
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Iterable<Competitor> getCompetitors() {
LockUtil.lockForRead(lock);
try {
return new ArrayList<Competitor>(competitorCache.values());
} finally {
LockUtil.unlockAfterRead(lock);
}
}
@Override
public void removeCompetitor(Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
logger.fine("removing competitor "+competitor+" from competitor store "+this);
competitorCache.remove(competitor.getId());
competitorsByIdAsString.remove(competitor.getId().toString());
weakCompetitorDTOCache.remove(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
@Override
public Competitor updateCompetitor(String idAsString, String newName, Color newDisplayColor, String newEmail,
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String newSearchTag) {
DynamicCompetitor competitor = (DynamicCompetitor) getExistingCompetitorByIdAsString(idAsString);
if (competitor != null) {
LockUtil.lockForWrite(lock);
try {
competitor.setName(newName);
competitor.setColor(newDisplayColor);
competitor.setEmail(newEmail);
competitor.setFlagImage(newFlagImageUri);
competitor.getBoat().setSailId(newSailId);
competitor.getTeam().setNationality(newNationality);
competitor.getTeam().setImage(newTeamImageUri);
competitor.setTimeOnTimeFactor(timeOnTimeFactor);
competitor.setTimeOnDistanceAllowancePerNauticalMile(timeOnDistanceAllowancePerNauticalMile);
competitor.setSearchTag(newSearchTag);
weakCompetitorDTOCache.remove(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
synchronized (listeners) {
for (CompetitorUpdateListener listener : listeners) {
listener.competitorUpdated(competitor);
}
}
return competitor;
}
@Override
public CompetitorDTO convertToCompetitorDTO(Competitor c) {
LockUtil.lockForRead(lock);
boolean needToUnlockReadLock = true;
try {
CompetitorDTO competitorDTO = weakCompetitorDTOCache.get(c);
if (competitorDTO == null) {
LockUtil.unlockAfterRead(lock);
needToUnlockReadLock = false;
LockUtil.lockForWrite(lock);
competitorDTO = weakCompetitorDTOCache.get(c);
if (competitorDTO == null) {
final Nationality nationality = c.getTeam().getNationality();
CountryCode countryCode = nationality == null ? null : nationality.getCountryCode();
competitorDTO = new CompetitorDTOImpl(c.getName(), c.getColor(), c.getEmail(), countryCode == null ? ""
: countryCode.getTwoLetterISOCode(), countryCode == null ? ""
: countryCode.getThreeLetterIOCCode(), countryCode == null ? "" : countryCode.getName(),
c.getId().toString(),
c.getTeam().getImage() == null ? null : c.getTeam().getImage().toString(),
c.getFlagImage() == null ? null : c.getFlagImage().toString(),
new BoatDTO(c.getBoat().getName(), c.getBoat().getSailID(), c.getBoat().getColor()),
new BoatClassDTO(c.getBoat().getBoatClass()
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength().getMeters()),
c.getTimeOnTimeFactor(), c.getTimeOnDistanceAllowancePerNauticalMile(), c.getSearchTag());
weakCompetitorDTOCache.put(c, competitorDTO);
}
}
return competitorDTO;
} finally {
if (needToUnlockReadLock) {
LockUtil.unlockAfterRead(lock);
} else {
LockUtil.unlockAfterWrite(lock);
}
}
}
@Override
public void allowCompetitorResetToDefaults(Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
competitorsToUpdateDuringGetOrCreate.add(competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
}
}
@@ -126,7 +126,7 @@ public class DomainFactoryImpl implements DomainFactory {
}
DynamicTeam team = new TeamImpl(competitor.getName(), teamMembers, /* coach */ null);
result = competitorStore.getOrCreateCompetitor(competitor.getID(), competitor.getName(), null /*displayColor*/, null /*email*/, null, team, boat,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
}
return result;
}
@@ -143,7 +143,7 @@ public class DomainFactoryImpl implements DomainFactory {
DynamicTeam team = new TeamImpl(competitor.getName(), teamMembers, /* coach */ null);
result = baseDomainFactory.getCompetitorStore().getOrCreateCompetitor(getCompetitorID(competitor.getBoatID(), raceId, boatClass),
competitor.getName(), null /*displayColor*/, null /*email*/, null, team, boat,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
return result;
}
@@ -1,372 +1,372 @@
package com.sap.sailing.domain.common.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
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 org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.IncrementalLeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.domain.test.StoredTrackBasedTest;
import com.sap.sse.common.Cloner;
import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.util.ClonerImpl;
/**
* Tests the compressing / de-compressing functionality of {@link LeaderboardDTO} and {@link IncrementalLeaderboardDTO}.
* See also bug 1417.<p>
*
* The data of a meaningful and non-trivial {@link LeaderboardDTO} is obtained by using an instrumented version of
* <code>SailingServiceImpl.getLeaderboardByName(...)</code> which serializes the leaderboard at the end of the method
* to a file used by this test. The leaderboard that this test wants to use is that of the 505 Worlds 2013, obtained
* for an expanded Race R9 at time 2013-05-03T17:21:40Z.
*
* @author Axel Uhl (d043530)
*
*/
public class LeaderboardDTODiffingTest {
private LeaderboardDTO previousVersion;
private IncrementalLeaderboardDTO newVersion;
private final Cloner cloner = new ClonerImpl();
@Before
public void setUp() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = StoredTrackBasedTest.getObjectInputStream("IncrementalLeaderboardDTO.ser");
previousVersion = (LeaderboardDTO) ois.readObject();
ois.close();
newVersion = new IncrementalLeaderboardDTO("12345", cloner);
cloner.clone(previousVersion, newVersion);
}
private CompetitorDTO getPreviousCompetitorByName(String name) {
for (CompetitorDTO competitor : previousVersion.competitors) {
if (competitor.getName().equals(name)) {
return competitor;
}
}
return null;
}
@Test
public void testEmptyLegDetailsGetFilled() throws FileNotFoundException, IOException, ClassNotFoundException {
// remove legDetails for R9 for all competitors from previousVersion; remember which ones did contain data
Set<CompetitorDTO> hadLegDetailsInR9 = new HashSet<>();
Map<CompetitorDTO, LeaderboardRowDTO> newRows = new HashMap<>();
for (CompetitorDTO competitor : previousVersion.rows.keySet()) {
LeaderboardRowDTO competitorRow = new LeaderboardRowDTO();
cloner.clone(newVersion.rows.get(competitor), competitorRow);
Map<String, LeaderboardEntryDTO> newFieldsByRaceColumnName = new HashMap<>();
for (Entry<String, LeaderboardEntryDTO> e : competitorRow.fieldsByRaceColumnName.entrySet()) {
LeaderboardEntryDTO newEntry = new LeaderboardEntryDTO();
cloner.clone(e.getValue(), newEntry);
newFieldsByRaceColumnName.put(e.getKey(), newEntry);
}
competitorRow.fieldsByRaceColumnName = newFieldsByRaceColumnName;
newRows.put(competitor, competitorRow); // use a copy of the row so we can null out legDetails for R9 in previousVersion only
LeaderboardRowDTO previousRow = previousVersion.rows.get(competitor);
assertNotSame(previousRow, competitorRow);
if (previousRow.fieldsByRaceColumnName.get("R9").legDetails != null) {
hadLegDetailsInR9.add(competitor);
previousRow.fieldsByRaceColumnName.get("R9").legDetails = null;
assertNotNull(competitorRow.fieldsByRaceColumnName.get("R9").legDetails != null);
}
}
newVersion.rows = newRows;
newVersion.strip(previousVersion); // should contain the leg details now
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
// now applied must contain the leg details
for (CompetitorDTO competitor : hadLegDetailsInR9) {
assertNotNull(applied.rows.get(competitor).fieldsByRaceColumnName.get("R9").legDetails);
}
}
@Test
public void testLeaderboardSuccessfullyRead() {
assertNotNull(previousVersion);
assertNotNull(newVersion);
}
@Test
public void testPreviousAndNewVersionHaveEqualRows() {
assertEquals(previousVersion.rows, newVersion.rows);
}
@Test
public void testTotalStripping() {
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNull(newVersion.rows);
}
@Test
public void testMajorStripping() {
newVersion.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>(newVersion.rows);
List<RaceColumnDTO> raceListBeforeStripping = new ArrayList<RaceColumnDTO>(newVersion.getRaceList());
CompetitorDTO wolfgang = getPreviousCompetitorByName("HUNGER +JESS");
assertNotNull(wolfgang);
LeaderboardRowDTO wolfgangsRow = new LeaderboardRowDTO();
cloner.clone(newVersion.rows.get(wolfgang), wolfgangsRow);
newVersion.rows.put(wolfgang, wolfgangsRow);
wolfgangsRow.totalDistanceTraveledInMeters += 1;
Map<CompetitorDTO, LeaderboardRowDTO> rowsBeforeStripping = newVersion.rows;
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNotNull(newVersion.rows);
assertEquals(1, newVersion.rows.size()); // only wolfgang's row should show
assertEquals(wolfgang, newVersion.rows.keySet().iterator().next().getCompetitorFromPrevious(previousVersion));
assertTrue(newVersion.rows.values().iterator().next().fieldsByRaceColumnName.isEmpty());
for (RaceColumnDTO nullRaceColumn : newVersion.getRaceList()) {
assertNull(nullRaceColumn); // there were no changes to the columns; expect all of them to have been eliminiated
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(rowsBeforeStripping, applied.rows);
assertNotSame(raceListBeforeStripping, applied.getRaceList());
assertEquals(raceListBeforeStripping, applied.getRaceList());
}
@Test
public void testStrippingExceptOneColumnInOneRace() {
HashMap<CompetitorDTO, LeaderboardRowDTO> newRows = new HashMap<CompetitorDTO, LeaderboardRowDTO>(newVersion.rows);
double newDistance = 1234;
String nameOfRaceColumnToChange = "R9";
int indexOfLegToChange = 7; // ( zero based: ) 8th leg is the last leg
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : newVersion.rows.entrySet()) {
LeaderboardRowDTO newRow = new LeaderboardRowDTO();
cloner.clone(e.getValue(), newRow);
newRows.put(e.getKey(), newRow);
newRow.fieldsByRaceColumnName = new HashMap<String, LeaderboardEntryDTO>(newRow.fieldsByRaceColumnName); // clone entry map
LeaderboardEntryDTO newEntry = new LeaderboardEntryDTO();
cloner.clone(newRow.fieldsByRaceColumnName.get(nameOfRaceColumnToChange), newEntry);
newRow.fieldsByRaceColumnName.put(nameOfRaceColumnToChange, newEntry);
if (newEntry.legDetails != null) {
newEntry.legDetails = new ArrayList<LegEntryDTO>(newEntry.legDetails); // clone leg details list
if (newEntry.legDetails.get(indexOfLegToChange) != null) {
LegEntryDTO newLegDetail = new LegEntryDTO();
cloner.clone(newEntry.legDetails.get(indexOfLegToChange), newLegDetail);
newEntry.legDetails.set(indexOfLegToChange, newLegDetail);
newLegDetail.distanceTraveledInMeters = newDistance;
newDistance += 1;
}
}
}
newVersion.rows = newRows;
Map<CompetitorDTO, LeaderboardRowDTO> rowsBeforeStripping = newVersion.rows;
Map<com.sap.sse.common.Util.Pair<CompetitorDTO, String>, List<LegEntryDTO>> previousLegDetailsBeforeStripping = new HashMap<>();
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : rowsBeforeStripping.entrySet()) {
for (Map.Entry<String, LeaderboardEntryDTO> e2 : e.getValue().fieldsByRaceColumnName.entrySet()) {
if (e2.getValue().legDetails != null) {
previousLegDetailsBeforeStripping.put(new com.sap.sse.common.Util.Pair<CompetitorDTO, String>(e.getKey(), e2.getKey()),
new ArrayList<>(e2.getValue().legDetails));
}
}
}
newVersion.strip(previousVersion);
// see bug 1455; check that the stripping doesn't kill the previous leaderboard's legDetails lists
for (Map.Entry<com.sap.sse.common.Util.Pair<CompetitorDTO, String>, List<LegEntryDTO>> e : previousLegDetailsBeforeStripping.entrySet()) {
final LeaderboardRowDTO leaderboardRowDTO = rowsBeforeStripping.get(e.getKey().getA());
if (leaderboardRowDTO != null) {
List<LegEntryDTO> newLegDetails = leaderboardRowDTO.fieldsByRaceColumnName.get(e.getKey().getB()).legDetails;
assertEquals(e.getValue(), newLegDetails);
}
}
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNotNull(newVersion.rows);
assertEquals(previousVersion.rows.size()-17, newVersion.rows.size()); // all rows have changed except for 17 that have no leg details in leg 8
// now assert that for all rows there is no leaderboard entry for all races but R9 and
// for R9 there either are no leg details or all leg details for all legs other than L8 are null
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : newVersion.rows.entrySet()) {
if (e.getValue().fieldsByRaceColumnName != null) {
assertTrue(e.getValue().fieldsByRaceColumnName.size() <= 1);
for (Map.Entry<String, LeaderboardEntryDTO> e2 : e.getValue().fieldsByRaceColumnName.entrySet()) {
if (e2.getKey().equals(nameOfRaceColumnToChange)) {
List<LegEntryDTO> r9LegDetails = e2.getValue().legDetails;
if (r9LegDetails != null) {
for (int i=0; i<r9LegDetails.size(); i++) {
if (i != indexOfLegToChange) {
assertNull(r9LegDetails.get(i));
} else {
assertNotNull(r9LegDetails.get(i));
}
}
}
} else {
// if there is an entry for any column other than R9 (which is not really expected) then the entry is expected to be null
assertNull(e2.getValue());
}
}
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(rowsBeforeStripping, applied.rows);
}
@Test
public void testCompetitorListChange() {
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null);
newVersion.competitors.add(13, somebodyNew); // insert a competitor; this should mess up all others' indexes; check if this works
CompetitorDTO wolfgang = getPreviousCompetitorByName("HUNGER +JESS");
newVersion.competitors.remove(wolfgang);
newVersion.rows.remove(wolfgang); // remove another competitor
List<CompetitorDTO> newCompetitorsBeforeStripping = new ArrayList<CompetitorDTO>(newVersion.competitors);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNull(newVersion.competitors); // but there should be an added competitor that we can't see through the public interface
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newCompetitorsBeforeStripping, applied.competitors);
}
@Test
public void testSuppressionChange() {
final List<CompetitorDTO> newSuppressedCompetitors = new ArrayList<CompetitorDTO>();
Util.addAll(newVersion.getSuppressedCompetitors(), newSuppressedCompetitors);
newVersion.setSuppressedCompetitors(newSuppressedCompetitors);
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null);
newVersion.setSuppressed(newVersion.competitors.get(13), true); // suppress an existing competitor; compaction should reduce this to a single number only
newVersion.setSuppressed(somebodyNew, true); // check that mixed mode with existing and new competitors works as well
List<CompetitorDTO> newSuppressedCompetitorsBeforeStripping = new ArrayList<CompetitorDTO>();
Util.addAll(newVersion.getSuppressedCompetitors(), newSuppressedCompetitorsBeforeStripping);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertEquals(2, Util.size(newVersion.getSuppressedCompetitors()));
assertTrue(Util.contains(newVersion.getSuppressedCompetitors(), somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.getSuppressedCompetitors()) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newSuppressedCompetitorsBeforeStripping, applied.getSuppressedCompetitors());
}
@Test
public void testDisplayNameChange() {
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null);
newVersion.competitors.add(somebodyNew);
newVersion.competitorDisplayNames = new HashMap<CompetitorDTO, String>(newVersion.competitorDisplayNames);
newVersion.competitorDisplayNames.put(newVersion.competitors.get(13), "Humba");
newVersion.competitorDisplayNames.put(somebodyNew, "Trala");
final HashMap<CompetitorDTO, String> newDisplayNamesBeforeStripping = new HashMap<CompetitorDTO, String>();
newDisplayNamesBeforeStripping.putAll(newVersion.competitorDisplayNames);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertEquals(2, newVersion.competitorDisplayNames.size());
assertTrue(newVersion.competitorDisplayNames.keySet().contains(somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.competitorDisplayNames.keySet()) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newDisplayNamesBeforeStripping, applied.competitorDisplayNames);
}
@Test
public void testCompetitorOrderingInRaceChange() {
RaceColumnDTO r9 = newVersion.getRaceColumnByName("R9");
Map<String, List<CompetitorDTO>> newCompetitorOrderingPerRace = new HashMap<String, List<CompetitorDTO>>(newVersion.getCompetitorOrderingPerRaceColumnName());
newVersion.setCompetitorOrderingPerRace(newCompetitorOrderingPerRace);
List<CompetitorDTO> newOrdering = new ArrayList<CompetitorDTO>(newVersion.getCompetitorsFromBestToWorst(r9));
newVersion.setCompetitorsFromBestToWorst(r9, newOrdering);
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null);
newVersion.competitors.add(somebodyNew);
newOrdering.add(somebodyNew);
CompetitorDTO formerRank13 = newOrdering.remove(13);
newOrdering.add(12, formerRank13);
List<CompetitorDTO> newOrderBeforeStripping = new ArrayList<CompetitorDTO>(newOrdering);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
for (int i=1; i<9; i++) {
assertNull(newVersion.getCompetitorsFromBestToWorst("R"+i));
}
assertEquals(newVersion.getCompetitorsFromBestToWorst(r9).size()-1, newVersion.getCompetitorsFromBestToWorst(r9).indexOf(somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.getCompetitorsFromBestToWorst(r9)) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newOrderBeforeStripping, applied.getCompetitorsFromBestToWorst(applied.getRaceColumnByName("R9")));
}
private void assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(LeaderboardDTO leaderboard) {
if (leaderboard.rows != null) {
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : leaderboard.rows.entrySet()) {
assertSame(e.getKey(), e.getValue().competitor);
}
}
}
@Test
public void testPartialRaceColumnDTOCompaction() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
// create a modified R9 RaceDTO clone in newVersion to make sure that even changing a property in the RaceDTO will keep the RaceColumnDTO from being omitted
RaceColumnDTO r9 = newVersion.getRaceColumnByName("R9");
RaceColumnDTO clonedR9 = new RaceColumnDTO();
cloner.clone(r9, clonedR9);
// also clone the racesPerFleet map, or else we'd be modifying the previous version's one too
final Field racesPerFleetField = clonedR9.getClass().getDeclaredField("racesPerFleet");
racesPerFleetField.setAccessible(true);
@SuppressWarnings("unchecked")
final Map<FleetDTO, RaceDTO> m = (Map<FleetDTO, RaceDTO>) racesPerFleetField.get(clonedR9);
racesPerFleetField.set(clonedR9, new HashMap<FleetDTO, RaceDTO>(m));
final FleetDTO defaultFleet = r9.getFleets().iterator().next();
RaceDTO r9Race = r9.getRace(defaultFleet);
RaceDTO clonedR9Race = new RaceDTO();
cloner.clone(r9Race, clonedR9Race);
clonedR9.setRace(defaultFleet, clonedR9Race);
clonedR9Race.endOfRace = new MillisecondsTimePoint(r9Race.endOfRace).plus(1234).asDate();
List<RaceColumnDTO> clonedRaceList = new ArrayList<RaceColumnDTO>(newVersion.getRaceList());
clonedRaceList.set(clonedRaceList.indexOf(r9), clonedR9);
newVersion.setRaceList(clonedRaceList);
List<RaceColumnDTO> raceListBeforeStripping = new ArrayList<RaceColumnDTO>(clonedRaceList);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
for (int i=0; i<8; i++) {
assertNull(newVersion.getRaceList().get(i));
}
assertNotNull(newVersion.getRaceList().get(8));
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(raceListBeforeStripping, applied.getRaceList());
}
}
package com.sap.sailing.domain.common.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
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 org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.IncrementalLeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.domain.test.StoredTrackBasedTest;
import com.sap.sse.common.Cloner;
import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.util.ClonerImpl;
/**
* Tests the compressing / de-compressing functionality of {@link LeaderboardDTO} and {@link IncrementalLeaderboardDTO}.
* See also bug 1417.<p>
*
* The data of a meaningful and non-trivial {@link LeaderboardDTO} is obtained by using an instrumented version of
* <code>SailingServiceImpl.getLeaderboardByName(...)</code> which serializes the leaderboard at the end of the method
* to a file used by this test. The leaderboard that this test wants to use is that of the 505 Worlds 2013, obtained
* for an expanded Race R9 at time 2013-05-03T17:21:40Z.
*
* @author Axel Uhl (d043530)
*
*/
public class LeaderboardDTODiffingTest {
private LeaderboardDTO previousVersion;
private IncrementalLeaderboardDTO newVersion;
private final Cloner cloner = new ClonerImpl();
@Before
public void setUp() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = StoredTrackBasedTest.getObjectInputStream("IncrementalLeaderboardDTO.ser");
previousVersion = (LeaderboardDTO) ois.readObject();
ois.close();
newVersion = new IncrementalLeaderboardDTO("12345", cloner);
cloner.clone(previousVersion, newVersion);
}
private CompetitorDTO getPreviousCompetitorByName(String name) {
for (CompetitorDTO competitor : previousVersion.competitors) {
if (competitor.getName().equals(name)) {
return competitor;
}
}
return null;
}
@Test
public void testEmptyLegDetailsGetFilled() throws FileNotFoundException, IOException, ClassNotFoundException {
// remove legDetails for R9 for all competitors from previousVersion; remember which ones did contain data
Set<CompetitorDTO> hadLegDetailsInR9 = new HashSet<>();
Map<CompetitorDTO, LeaderboardRowDTO> newRows = new HashMap<>();
for (CompetitorDTO competitor : previousVersion.rows.keySet()) {
LeaderboardRowDTO competitorRow = new LeaderboardRowDTO();
cloner.clone(newVersion.rows.get(competitor), competitorRow);
Map<String, LeaderboardEntryDTO> newFieldsByRaceColumnName = new HashMap<>();
for (Entry<String, LeaderboardEntryDTO> e : competitorRow.fieldsByRaceColumnName.entrySet()) {
LeaderboardEntryDTO newEntry = new LeaderboardEntryDTO();
cloner.clone(e.getValue(), newEntry);
newFieldsByRaceColumnName.put(e.getKey(), newEntry);
}
competitorRow.fieldsByRaceColumnName = newFieldsByRaceColumnName;
newRows.put(competitor, competitorRow); // use a copy of the row so we can null out legDetails for R9 in previousVersion only
LeaderboardRowDTO previousRow = previousVersion.rows.get(competitor);
assertNotSame(previousRow, competitorRow);
if (previousRow.fieldsByRaceColumnName.get("R9").legDetails != null) {
hadLegDetailsInR9.add(competitor);
previousRow.fieldsByRaceColumnName.get("R9").legDetails = null;
assertNotNull(competitorRow.fieldsByRaceColumnName.get("R9").legDetails != null);
}
}
newVersion.rows = newRows;
newVersion.strip(previousVersion); // should contain the leg details now
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
// now applied must contain the leg details
for (CompetitorDTO competitor : hadLegDetailsInR9) {
assertNotNull(applied.rows.get(competitor).fieldsByRaceColumnName.get("R9").legDetails);
}
}
@Test
public void testLeaderboardSuccessfullyRead() {
assertNotNull(previousVersion);
assertNotNull(newVersion);
}
@Test
public void testPreviousAndNewVersionHaveEqualRows() {
assertEquals(previousVersion.rows, newVersion.rows);
}
@Test
public void testTotalStripping() {
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNull(newVersion.rows);
}
@Test
public void testMajorStripping() {
newVersion.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>(newVersion.rows);
List<RaceColumnDTO> raceListBeforeStripping = new ArrayList<RaceColumnDTO>(newVersion.getRaceList());
CompetitorDTO wolfgang = getPreviousCompetitorByName("HUNGER +JESS");
assertNotNull(wolfgang);
LeaderboardRowDTO wolfgangsRow = new LeaderboardRowDTO();
cloner.clone(newVersion.rows.get(wolfgang), wolfgangsRow);
newVersion.rows.put(wolfgang, wolfgangsRow);
wolfgangsRow.totalDistanceTraveledInMeters += 1;
Map<CompetitorDTO, LeaderboardRowDTO> rowsBeforeStripping = newVersion.rows;
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNotNull(newVersion.rows);
assertEquals(1, newVersion.rows.size()); // only wolfgang's row should show
assertEquals(wolfgang, newVersion.rows.keySet().iterator().next().getCompetitorFromPrevious(previousVersion));
assertTrue(newVersion.rows.values().iterator().next().fieldsByRaceColumnName.isEmpty());
for (RaceColumnDTO nullRaceColumn : newVersion.getRaceList()) {
assertNull(nullRaceColumn); // there were no changes to the columns; expect all of them to have been eliminiated
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(rowsBeforeStripping, applied.rows);
assertNotSame(raceListBeforeStripping, applied.getRaceList());
assertEquals(raceListBeforeStripping, applied.getRaceList());
}
@Test
public void testStrippingExceptOneColumnInOneRace() {
HashMap<CompetitorDTO, LeaderboardRowDTO> newRows = new HashMap<CompetitorDTO, LeaderboardRowDTO>(newVersion.rows);
double newDistance = 1234;
String nameOfRaceColumnToChange = "R9";
int indexOfLegToChange = 7; // ( zero based: ) 8th leg is the last leg
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : newVersion.rows.entrySet()) {
LeaderboardRowDTO newRow = new LeaderboardRowDTO();
cloner.clone(e.getValue(), newRow);
newRows.put(e.getKey(), newRow);
newRow.fieldsByRaceColumnName = new HashMap<String, LeaderboardEntryDTO>(newRow.fieldsByRaceColumnName); // clone entry map
LeaderboardEntryDTO newEntry = new LeaderboardEntryDTO();
cloner.clone(newRow.fieldsByRaceColumnName.get(nameOfRaceColumnToChange), newEntry);
newRow.fieldsByRaceColumnName.put(nameOfRaceColumnToChange, newEntry);
if (newEntry.legDetails != null) {
newEntry.legDetails = new ArrayList<LegEntryDTO>(newEntry.legDetails); // clone leg details list
if (newEntry.legDetails.get(indexOfLegToChange) != null) {
LegEntryDTO newLegDetail = new LegEntryDTO();
cloner.clone(newEntry.legDetails.get(indexOfLegToChange), newLegDetail);
newEntry.legDetails.set(indexOfLegToChange, newLegDetail);
newLegDetail.distanceTraveledInMeters = newDistance;
newDistance += 1;
}
}
}
newVersion.rows = newRows;
Map<CompetitorDTO, LeaderboardRowDTO> rowsBeforeStripping = newVersion.rows;
Map<com.sap.sse.common.Util.Pair<CompetitorDTO, String>, List<LegEntryDTO>> previousLegDetailsBeforeStripping = new HashMap<>();
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : rowsBeforeStripping.entrySet()) {
for (Map.Entry<String, LeaderboardEntryDTO> e2 : e.getValue().fieldsByRaceColumnName.entrySet()) {
if (e2.getValue().legDetails != null) {
previousLegDetailsBeforeStripping.put(new com.sap.sse.common.Util.Pair<CompetitorDTO, String>(e.getKey(), e2.getKey()),
new ArrayList<>(e2.getValue().legDetails));
}
}
}
newVersion.strip(previousVersion);
// see bug 1455; check that the stripping doesn't kill the previous leaderboard's legDetails lists
for (Map.Entry<com.sap.sse.common.Util.Pair<CompetitorDTO, String>, List<LegEntryDTO>> e : previousLegDetailsBeforeStripping.entrySet()) {
final LeaderboardRowDTO leaderboardRowDTO = rowsBeforeStripping.get(e.getKey().getA());
if (leaderboardRowDTO != null) {
List<LegEntryDTO> newLegDetails = leaderboardRowDTO.fieldsByRaceColumnName.get(e.getKey().getB()).legDetails;
assertEquals(e.getValue(), newLegDetails);
}
}
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNotNull(newVersion.rows);
assertEquals(previousVersion.rows.size()-17, newVersion.rows.size()); // all rows have changed except for 17 that have no leg details in leg 8
// now assert that for all rows there is no leaderboard entry for all races but R9 and
// for R9 there either are no leg details or all leg details for all legs other than L8 are null
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : newVersion.rows.entrySet()) {
if (e.getValue().fieldsByRaceColumnName != null) {
assertTrue(e.getValue().fieldsByRaceColumnName.size() <= 1);
for (Map.Entry<String, LeaderboardEntryDTO> e2 : e.getValue().fieldsByRaceColumnName.entrySet()) {
if (e2.getKey().equals(nameOfRaceColumnToChange)) {
List<LegEntryDTO> r9LegDetails = e2.getValue().legDetails;
if (r9LegDetails != null) {
for (int i=0; i<r9LegDetails.size(); i++) {
if (i != indexOfLegToChange) {
assertNull(r9LegDetails.get(i));
} else {
assertNotNull(r9LegDetails.get(i));
}
}
}
} else {
// if there is an entry for any column other than R9 (which is not really expected) then the entry is expected to be null
assertNull(e2.getValue());
}
}
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(rowsBeforeStripping, applied.rows);
}
@Test
public void testCompetitorListChange() {
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
newVersion.competitors.add(13, somebodyNew); // insert a competitor; this should mess up all others' indexes; check if this works
CompetitorDTO wolfgang = getPreviousCompetitorByName("HUNGER +JESS");
newVersion.competitors.remove(wolfgang);
newVersion.rows.remove(wolfgang); // remove another competitor
List<CompetitorDTO> newCompetitorsBeforeStripping = new ArrayList<CompetitorDTO>(newVersion.competitors);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertNull(newVersion.competitors); // but there should be an added competitor that we can't see through the public interface
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newCompetitorsBeforeStripping, applied.competitors);
}
@Test
public void testSuppressionChange() {
final List<CompetitorDTO> newSuppressedCompetitors = new ArrayList<CompetitorDTO>();
Util.addAll(newVersion.getSuppressedCompetitors(), newSuppressedCompetitors);
newVersion.setSuppressedCompetitors(newSuppressedCompetitors);
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
newVersion.setSuppressed(newVersion.competitors.get(13), true); // suppress an existing competitor; compaction should reduce this to a single number only
newVersion.setSuppressed(somebodyNew, true); // check that mixed mode with existing and new competitors works as well
List<CompetitorDTO> newSuppressedCompetitorsBeforeStripping = new ArrayList<CompetitorDTO>();
Util.addAll(newVersion.getSuppressedCompetitors(), newSuppressedCompetitorsBeforeStripping);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertEquals(2, Util.size(newVersion.getSuppressedCompetitors()));
assertTrue(Util.contains(newVersion.getSuppressedCompetitors(), somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.getSuppressedCompetitors()) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newSuppressedCompetitorsBeforeStripping, applied.getSuppressedCompetitors());
}
@Test
public void testDisplayNameChange() {
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
newVersion.competitors.add(somebodyNew);
newVersion.competitorDisplayNames = new HashMap<CompetitorDTO, String>(newVersion.competitorDisplayNames);
newVersion.competitorDisplayNames.put(newVersion.competitors.get(13), "Humba");
newVersion.competitorDisplayNames.put(somebodyNew, "Trala");
final HashMap<CompetitorDTO, String> newDisplayNamesBeforeStripping = new HashMap<CompetitorDTO, String>();
newDisplayNamesBeforeStripping.putAll(newVersion.competitorDisplayNames);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
assertEquals(2, newVersion.competitorDisplayNames.size());
assertTrue(newVersion.competitorDisplayNames.keySet().contains(somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.competitorDisplayNames.keySet()) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newDisplayNamesBeforeStripping, applied.competitorDisplayNames);
}
@Test
public void testCompetitorOrderingInRaceChange() {
RaceColumnDTO r9 = newVersion.getRaceColumnByName("R9");
Map<String, List<CompetitorDTO>> newCompetitorOrderingPerRace = new HashMap<String, List<CompetitorDTO>>(newVersion.getCompetitorOrderingPerRaceColumnName());
newVersion.setCompetitorOrderingPerRace(newCompetitorOrderingPerRace);
List<CompetitorDTO> newOrdering = new ArrayList<CompetitorDTO>(newVersion.getCompetitorsFromBestToWorst(r9));
newVersion.setCompetitorsFromBestToWorst(r9, newOrdering);
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
newVersion.competitors.add(somebodyNew);
newOrdering.add(somebodyNew);
CompetitorDTO formerRank13 = newOrdering.remove(13);
newOrdering.add(12, formerRank13);
List<CompetitorDTO> newOrderBeforeStripping = new ArrayList<CompetitorDTO>(newOrdering);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
for (int i=1; i<9; i++) {
assertNull(newVersion.getCompetitorsFromBestToWorst("R"+i));
}
assertEquals(newVersion.getCompetitorsFromBestToWorst(r9).size()-1, newVersion.getCompetitorsFromBestToWorst(r9).indexOf(somebodyNew));
for (CompetitorDTO compactSuppressedCompetitor : newVersion.getCompetitorsFromBestToWorst(r9)) {
if (compactSuppressedCompetitor != somebodyNew) {
assertFalse(compactSuppressedCompetitor instanceof CompetitorDTOImpl); // assert that the existing competitor was compacted
}
}
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(newOrderBeforeStripping, applied.getCompetitorsFromBestToWorst(applied.getRaceColumnByName("R9")));
}
private void assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(LeaderboardDTO leaderboard) {
if (leaderboard.rows != null) {
for (Map.Entry<CompetitorDTO, LeaderboardRowDTO> e : leaderboard.rows.entrySet()) {
assertSame(e.getKey(), e.getValue().competitor);
}
}
}
@Test
public void testPartialRaceColumnDTOCompaction() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
// create a modified R9 RaceDTO clone in newVersion to make sure that even changing a property in the RaceDTO will keep the RaceColumnDTO from being omitted
RaceColumnDTO r9 = newVersion.getRaceColumnByName("R9");
RaceColumnDTO clonedR9 = new RaceColumnDTO();
cloner.clone(r9, clonedR9);
// also clone the racesPerFleet map, or else we'd be modifying the previous version's one too
final Field racesPerFleetField = clonedR9.getClass().getDeclaredField("racesPerFleet");
racesPerFleetField.setAccessible(true);
@SuppressWarnings("unchecked")
final Map<FleetDTO, RaceDTO> m = (Map<FleetDTO, RaceDTO>) racesPerFleetField.get(clonedR9);
racesPerFleetField.set(clonedR9, new HashMap<FleetDTO, RaceDTO>(m));
final FleetDTO defaultFleet = r9.getFleets().iterator().next();
RaceDTO r9Race = r9.getRace(defaultFleet);
RaceDTO clonedR9Race = new RaceDTO();
cloner.clone(r9Race, clonedR9Race);
clonedR9.setRace(defaultFleet, clonedR9Race);
clonedR9Race.endOfRace = new MillisecondsTimePoint(r9Race.endOfRace).plus(1234).asDate();
List<RaceColumnDTO> clonedRaceList = new ArrayList<RaceColumnDTO>(newVersion.getRaceList());
clonedRaceList.set(clonedRaceList.indexOf(r9), clonedR9);
newVersion.setRaceList(clonedRaceList);
List<RaceColumnDTO> raceListBeforeStripping = new ArrayList<RaceColumnDTO>(clonedRaceList);
newVersion.strip(previousVersion);
assertAllRowsKeysAreIdenticalToAllLeaderboardRowDTOCompetitors(newVersion);
for (int i=0; i<8; i++) {
assertNull(newVersion.getRaceList().get(i));
}
assertNotNull(newVersion.getRaceList().get(8));
LeaderboardDTO applied = newVersion.getLeaderboardDTO(previousVersion);
assertEquals(raceListBeforeStripping, applied.getRaceList());
}
}
@@ -20,7 +20,7 @@ public abstract class AbstractLeaderboardTest {
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
}
public static Competitor createCompetitor(String competitorName, CompetitorFactory competitorFactory) {
@@ -30,7 +30,7 @@ public abstract class AbstractLeaderboardTest {
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
}
public static CompetitorImpl createCompetitor(String competitorName, Serializable id) {
@@ -39,6 +39,6 @@ public abstract class AbstractLeaderboardTest {
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
}
}
@@ -179,4 +179,8 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest {
public static String getTracTracPassword() {
return "tracTest";
}
protected void addReceiverToStopDuringTearDown(Receiver receiver) {
receivers.add(receiver);
}
}
@@ -1,299 +1,320 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.CompetitorChangeListener;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.Team;
import com.sap.sailing.domain.base.WithNationality;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.RGBColor;
/**
* Tests the {@link CompetitorChangeListener} stuff including the serialization of the transitive listener
* pattern on the {@link Team} structure.
*
* @author Axel Uhl (D043530)
*
*/
public class CompetitorListenerTest extends AbstractSerializationTest {
private CompetitorChangeListener listener;
private boolean nationalityChanged;
private Object whatChangedNationality;
private Object oldNationality;
private Object newNationality;
private boolean sailIdChanged;
private String oldSailId;
private String newSailId;
private boolean nameChanged;
private String oldName;
private String newName;
private boolean colorChanged;
private Color oldColor;
private Color newColor;
private DynamicCompetitor competitor;
private DomainFactoryImpl baseDomainFactory;
private boolean emailChanged;
private String oldEmail;
private String newEmail;
private boolean flagImageChanged;
private URI oldFlagImageURL;
private URI newFlagImageURL;
private boolean timeOnTimeFactorChanged;
private Double oldTimeOnTimeFactor;
private Double newTimeOnTimeFactor;
private boolean timeOnDistanceAllowancePerNauticalMileChanged;
private Duration oldTimeOnDistanceAllowancePerNauticalMile;
private Duration newTimeOnDistanceAllowancePerNauticalMile;
@Before
public void setUp() {
baseDomainFactory = new DomainFactoryImpl((srlid)->null);
competitor = TrackBasedTest.createCompetitor("Hasso");
nationalityChanged = false;
whatChangedNationality = null;
oldNationality = null;
newNationality = null;
sailIdChanged = false;
oldSailId = null;
newSailId = null;
nameChanged = false;
oldName = null;
newName = null;
colorChanged = false;
oldColor = null;
newColor = null;
emailChanged = false;
oldEmail = null;
newEmail = null;
flagImageChanged = false;
oldFlagImageURL = null;
newFlagImageURL = null;
timeOnTimeFactorChanged = false;
oldTimeOnTimeFactor = null;
newTimeOnTimeFactor = null;
timeOnDistanceAllowancePerNauticalMileChanged = false;
oldTimeOnDistanceAllowancePerNauticalMile = null;
newTimeOnDistanceAllowancePerNauticalMile = null;
listener = new CompetitorChangeListener() {
private static final long serialVersionUID = 4581029778988240209L;
@Override
public void nationalityChanged(WithNationality what, Nationality oldNationality, Nationality newNationality) {
nationalityChanged = true;
whatChangedNationality = what;
CompetitorListenerTest.this.oldNationality = oldNationality;
CompetitorListenerTest.this.newNationality = newNationality;
}
@Override
public void sailIdChanged(String oldSailId, String newSailId) {
sailIdChanged = true;
CompetitorListenerTest.this.oldSailId = oldSailId;
CompetitorListenerTest.this.newSailId = newSailId;
}
@Override
public void nameChanged(String oldName, String newName) {
nameChanged = true;
CompetitorListenerTest.this.oldName = oldName;
CompetitorListenerTest.this.newName = newName;
}
@Override
public void colorChanged(Color oldColor, Color newColor) {
colorChanged = true;
CompetitorListenerTest.this.oldColor = oldColor;
CompetitorListenerTest.this.newColor = newColor;
}
@Override
public void emailChanged(String oldEmail, String newEmail) {
emailChanged = true;
CompetitorListenerTest.this.oldEmail = oldEmail;
CompetitorListenerTest.this.newEmail = newEmail;
}
@Override
public void flagImageChanged(URI oldFlagImageURL, URI newFlagImageURL) {
flagImageChanged = true;
CompetitorListenerTest.this.oldFlagImageURL = oldFlagImageURL;
CompetitorListenerTest.this.newFlagImageURL = newFlagImageURL;
}
@Override
public void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor) {
timeOnTimeFactorChanged = true;
CompetitorListenerTest.this.oldTimeOnTimeFactor = oldTimeOnTimeFactor;
CompetitorListenerTest.this.newTimeOnTimeFactor = newTimeOnTimeFactor;
}
@Override
public void timeOnDistanceAllowancePerNauticalMileChanged(
Duration oldTimeOnDistanceAllowancePerNauticalMile,
Duration newTimeOnDistanceAllowancePerNauticalMile) {
timeOnDistanceAllowancePerNauticalMileChanged = true;
CompetitorListenerTest.this.oldTimeOnDistanceAllowancePerNauticalMile = oldTimeOnDistanceAllowancePerNauticalMile;
CompetitorListenerTest.this.newTimeOnDistanceAllowancePerNauticalMile = newTimeOnDistanceAllowancePerNauticalMile;
}
};
competitor.addCompetitorChangeListener(listener);
}
@Test
public void testNullNationality() {
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
competitor.getTeam().setNationality(baseDomainFactory.getOrCreateNationality("GER"));
assertEquals(baseDomainFactory.getOrCreateNationality("GER"), competitor.getTeam().getNationality());
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
}
@Test
public void testChangeTimeOnTimeFactor() {
competitor.setTimeOnTimeFactor(1.209);
assertTrue(timeOnTimeFactorChanged);
assertNull(oldTimeOnTimeFactor);
assertEquals(1.209, newTimeOnTimeFactor, 0.00000001);
}
@Test
public void testChangeTimeOnDistanceAllowancePerNauticalMile() {
competitor.setTimeOnDistanceAllowancePerNauticalMile(Duration.ONE_HOUR);
assertTrue(timeOnDistanceAllowancePerNauticalMileChanged);
assertNull(oldTimeOnDistanceAllowancePerNauticalMile);
assertEquals(Duration.ONE_HOUR.asMillis(), newTimeOnDistanceAllowancePerNauticalMile.asMillis());
}
@Test
public void testSimpleCompetitorListenerPatternForName() {
competitor.setName("Dr. Hasso Plattner");
assertTrue(nameChanged);
assertEquals("Hasso", oldName);
assertEquals("Dr. Hasso Plattner", newName);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testFlagChange() throws URISyntaxException {
competitor.setFlagImage(new URI("http://www.something.de/pic.png"));
assertTrue(flagImageChanged);
assertNull(oldFlagImageURL);
assertEquals(new URI("http://www.something.de/pic.png"), newFlagImageURL);
}
@Test
public void testEmailChange() throws URISyntaxException {
competitor.setEmail("hasso.plattner@sap.com");
assertTrue(emailChanged);
assertNull(oldEmail);
assertEquals("hasso.plattner@sap.com", newEmail);
}
@Test
public void testSimpleCompetitorListenerPatternForSailId() {
final String myOldSailId = competitor.getBoat().getSailID();
competitor.getBoat().setSailId("POR 40");
assertFalse(nameChanged);
assertTrue(sailIdChanged);
assertEquals(myOldSailId, oldSailId);
assertEquals("POR 40", newSailId);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testSimpleCompetitorListenerPatternForColor() {
final Color myOldColor = competitor.getColor();
final RGBColor myNewColor = new RGBColor(123, 12, 234);
competitor.setColor(myNewColor);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertTrue(colorChanged);
assertEquals(myOldColor, oldColor);
assertEquals(myNewColor, newColor);
assertFalse(nationalityChanged);
}
@Test
public void testSimpleCompetitorListenerPatternForNationality() {
final Nationality myOldNationality = competitor.getTeam().getNationality();
final Nationality myNewNationality = DomainFactory.INSTANCE.getOrCreateNationality("POR");
competitor.getTeam().setNationality(myNewNationality);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertTrue(nationalityChanged);
assertEquals(myOldNationality, oldNationality);
assertEquals(myNewNationality, newNationality);
assertSame(competitor.getTeam(), whatChangedNationality);
}
@Test
public void testCompetitorSerializationLosesAllExternalListeners() throws ClassNotFoundException, IOException {
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
clonedCompetitor.setName("Dr. Hasso Plattner");
clonedCompetitor.getBoat().setSailId("POR 40");
final RGBColor myNewColor = new RGBColor(123, 12, 234);
clonedCompetitor.setColor(myNewColor);
final Nationality myNewNationality = baseDomainFactory.getOrCreateNationality("POR");
clonedCompetitor.getTeam().setNationality(myNewNationality);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testCompetitorSerializationListenerPatternForNameOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForName();
}
@Test
public void testCompetitorSerializationListenerPatternForColorOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForColor();
}
@Test
public void testCompetitorSerializationListenerPatternForSailIdOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForSailId();
}
@Test
public void testCompetitorSerializationListenerPatternForNationalityOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForNationality();
}
}
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.CompetitorChangeListener;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.Team;
import com.sap.sailing.domain.base.WithNationality;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.RGBColor;
/**
* Tests the {@link CompetitorChangeListener} stuff including the serialization of the transitive listener
* pattern on the {@link Team} structure.
*
* @author Axel Uhl (D043530)
*
*/
public class CompetitorListenerTest extends AbstractSerializationTest {
private CompetitorChangeListener listener;
private boolean nationalityChanged;
private Object whatChangedNationality;
private Object oldNationality;
private Object newNationality;
private boolean sailIdChanged;
private String oldSailId;
private String newSailId;
private boolean nameChanged;
private String oldName;
private String newName;
private boolean colorChanged;
private Color oldColor;
private Color newColor;
private DynamicCompetitor competitor;
private DomainFactoryImpl baseDomainFactory;
private boolean emailChanged;
private String oldEmail;
private String newEmail;
private boolean searchTagChanged;
private String oldSearchTag;
private String newSearchTag;
private boolean flagImageChanged;
private URI oldFlagImageURL;
private URI newFlagImageURL;
private boolean timeOnTimeFactorChanged;
private Double oldTimeOnTimeFactor;
private Double newTimeOnTimeFactor;
private boolean timeOnDistanceAllowancePerNauticalMileChanged;
private Duration oldTimeOnDistanceAllowancePerNauticalMile;
private Duration newTimeOnDistanceAllowancePerNauticalMile;
@Before
public void setUp() {
baseDomainFactory = new DomainFactoryImpl((srlid)->null);
competitor = TrackBasedTest.createCompetitor("Hasso");
nationalityChanged = false;
whatChangedNationality = null;
oldNationality = null;
newNationality = null;
sailIdChanged = false;
oldSailId = null;
newSailId = null;
nameChanged = false;
oldName = null;
newName = null;
colorChanged = false;
oldColor = null;
newColor = null;
emailChanged = false;
oldEmail = null;
newEmail = null;
searchTagChanged = false;
oldSearchTag = null;
newSearchTag = null;
flagImageChanged = false;
oldFlagImageURL = null;
newFlagImageURL = null;
timeOnTimeFactorChanged = false;
oldTimeOnTimeFactor = null;
newTimeOnTimeFactor = null;
timeOnDistanceAllowancePerNauticalMileChanged = false;
oldTimeOnDistanceAllowancePerNauticalMile = null;
newTimeOnDistanceAllowancePerNauticalMile = null;
listener = new CompetitorChangeListener() {
private static final long serialVersionUID = 4581029778988240209L;
@Override
public void nationalityChanged(WithNationality what, Nationality oldNationality, Nationality newNationality) {
nationalityChanged = true;
whatChangedNationality = what;
CompetitorListenerTest.this.oldNationality = oldNationality;
CompetitorListenerTest.this.newNationality = newNationality;
}
@Override
public void sailIdChanged(String oldSailId, String newSailId) {
sailIdChanged = true;
CompetitorListenerTest.this.oldSailId = oldSailId;
CompetitorListenerTest.this.newSailId = newSailId;
}
@Override
public void nameChanged(String oldName, String newName) {
nameChanged = true;
CompetitorListenerTest.this.oldName = oldName;
CompetitorListenerTest.this.newName = newName;
}
@Override
public void colorChanged(Color oldColor, Color newColor) {
colorChanged = true;
CompetitorListenerTest.this.oldColor = oldColor;
CompetitorListenerTest.this.newColor = newColor;
}
@Override
public void emailChanged(String oldEmail, String newEmail) {
emailChanged = true;
CompetitorListenerTest.this.oldEmail = oldEmail;
CompetitorListenerTest.this.newEmail = newEmail;
}
@Override
public void searchTagChanged(String oldSearchTag, String newSearchTag) {
searchTagChanged = true;
CompetitorListenerTest.this.oldSearchTag = oldSearchTag;
CompetitorListenerTest.this.newSearchTag = newSearchTag;
}
@Override
public void flagImageChanged(URI oldFlagImageURL, URI newFlagImageURL) {
flagImageChanged = true;
CompetitorListenerTest.this.oldFlagImageURL = oldFlagImageURL;
CompetitorListenerTest.this.newFlagImageURL = newFlagImageURL;
}
@Override
public void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor) {
timeOnTimeFactorChanged = true;
CompetitorListenerTest.this.oldTimeOnTimeFactor = oldTimeOnTimeFactor;
CompetitorListenerTest.this.newTimeOnTimeFactor = newTimeOnTimeFactor;
}
@Override
public void timeOnDistanceAllowancePerNauticalMileChanged(
Duration oldTimeOnDistanceAllowancePerNauticalMile,
Duration newTimeOnDistanceAllowancePerNauticalMile) {
timeOnDistanceAllowancePerNauticalMileChanged = true;
CompetitorListenerTest.this.oldTimeOnDistanceAllowancePerNauticalMile = oldTimeOnDistanceAllowancePerNauticalMile;
CompetitorListenerTest.this.newTimeOnDistanceAllowancePerNauticalMile = newTimeOnDistanceAllowancePerNauticalMile;
}
};
competitor.addCompetitorChangeListener(listener);
}
@Test
public void testNullNationality() {
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
competitor.getTeam().setNationality(baseDomainFactory.getOrCreateNationality("GER"));
assertEquals(baseDomainFactory.getOrCreateNationality("GER"), competitor.getTeam().getNationality());
competitor.getTeam().setNationality(null);
assertNull(competitor.getTeam().getNationality());
}
@Test
public void testChangeTimeOnTimeFactor() {
competitor.setTimeOnTimeFactor(1.209);
assertTrue(timeOnTimeFactorChanged);
assertNull(oldTimeOnTimeFactor);
assertEquals(1.209, newTimeOnTimeFactor, 0.00000001);
}
@Test
public void testChangeTimeOnDistanceAllowancePerNauticalMile() {
competitor.setTimeOnDistanceAllowancePerNauticalMile(Duration.ONE_HOUR);
assertTrue(timeOnDistanceAllowancePerNauticalMileChanged);
assertNull(oldTimeOnDistanceAllowancePerNauticalMile);
assertEquals(Duration.ONE_HOUR.asMillis(), newTimeOnDistanceAllowancePerNauticalMile.asMillis());
}
@Test
public void testSimpleCompetitorListenerPatternForName() {
competitor.setName("Dr. Hasso Plattner");
assertTrue(nameChanged);
assertEquals("Hasso", oldName);
assertEquals("Dr. Hasso Plattner", newName);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testFlagChange() throws URISyntaxException {
competitor.setFlagImage(new URI("http://www.something.de/pic.png"));
assertTrue(flagImageChanged);
assertNull(oldFlagImageURL);
assertEquals(new URI("http://www.something.de/pic.png"), newFlagImageURL);
}
@Test
public void testEmailChange() throws URISyntaxException {
competitor.setEmail("hasso.plattner@sap.com");
assertTrue(emailChanged);
assertNull(oldEmail);
assertEquals("hasso.plattner@sap.com", newEmail);
}
@Test
public void testSearchTagChange() throws URISyntaxException {
competitor.setSearchTag("hasso");
assertTrue(searchTagChanged);
assertNull(oldSearchTag);
assertEquals("hasso", newSearchTag);
}
@Test
public void testSimpleCompetitorListenerPatternForSailId() {
final String myOldSailId = competitor.getBoat().getSailID();
competitor.getBoat().setSailId("POR 40");
assertFalse(nameChanged);
assertTrue(sailIdChanged);
assertEquals(myOldSailId, oldSailId);
assertEquals("POR 40", newSailId);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testSimpleCompetitorListenerPatternForColor() {
final Color myOldColor = competitor.getColor();
final RGBColor myNewColor = new RGBColor(123, 12, 234);
competitor.setColor(myNewColor);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertTrue(colorChanged);
assertEquals(myOldColor, oldColor);
assertEquals(myNewColor, newColor);
assertFalse(nationalityChanged);
}
@Test
public void testSimpleCompetitorListenerPatternForNationality() {
final Nationality myOldNationality = competitor.getTeam().getNationality();
final Nationality myNewNationality = DomainFactory.INSTANCE.getOrCreateNationality("POR");
competitor.getTeam().setNationality(myNewNationality);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertTrue(nationalityChanged);
assertEquals(myOldNationality, oldNationality);
assertEquals(myNewNationality, newNationality);
assertSame(competitor.getTeam(), whatChangedNationality);
}
@Test
public void testCompetitorSerializationLosesAllExternalListeners() throws ClassNotFoundException, IOException {
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
clonedCompetitor.setName("Dr. Hasso Plattner");
clonedCompetitor.getBoat().setSailId("POR 40");
final RGBColor myNewColor = new RGBColor(123, 12, 234);
clonedCompetitor.setColor(myNewColor);
final Nationality myNewNationality = baseDomainFactory.getOrCreateNationality("POR");
clonedCompetitor.getTeam().setNationality(myNewNationality);
assertFalse(nameChanged);
assertFalse(sailIdChanged);
assertFalse(colorChanged);
assertFalse(nationalityChanged);
}
@Test
public void testCompetitorSerializationListenerPatternForNameOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForName();
}
@Test
public void testCompetitorSerializationListenerPatternForColorOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForColor();
}
@Test
public void testCompetitorSerializationListenerPatternForSailIdOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForSailId();
}
@Test
public void testCompetitorSerializationListenerPatternForNationalityOnSerializedCompetitor() throws ClassNotFoundException, IOException {
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
competitor = clonedCompetitor;
competitor.addCompetitorChangeListener(listener);
testSimpleCompetitorListenerPatternForNationality();
}
}
@@ -105,6 +105,9 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
}
});
addListenersForStoredDataAndStartController(receivers);
for (final Receiver receiver : receivers) {
addReceiverToStopDuringTearDown(receiver);
}
// now we expect that there is no
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace.getId()));
race = domainFactory.getAndWaitForRaceDefinition(tractracRace.getId());
@@ -1,182 +1,182 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
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.Series;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class LeaderboardCourseChangeTest {
/**
* See bug 2011
*
* @throws NoWindException
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public void testLeaderboardDTOCreationForCourseChange() throws NoWindException, InterruptedException, ExecutionException {
Date date = Calendar.getInstance().getTime();
TimePoint timePoint = new MillisecondsTimePoint(date);
TrackedRegattaRegistry trackedRegattaRegistry = mock(TrackedRegattaRegistry.class);
Fleet fleet = new FleetImpl("TestFleet");
Series series = createSeries(trackedRegattaRegistry, fleet);
Set<Series> seriesSet = new HashSet<>();
seriesSet.add(series);
BoatClass boatClass = new BoatClassImpl("TestClass", true);
String raceColumnName = "TestRace";
RaceColumn raceColumn = series.addRaceColumn(raceColumnName, trackedRegattaRegistry);
ScoringScheme scoringScheme = new LowPoint();
Regatta mockedRegatta = new RegattaImpl(RegattaImpl.getDefaultName("TestRegatta", boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, seriesSet, false, scoringScheme,
UUID.randomUUID(), mock(CourseArea.class), OneDesignRankingMetric::new);
ControlPoint start = new MarkImpl("Start");
ControlPoint m1 = new MarkImpl("M1");
ControlPoint m2 = new MarkImpl("M2");
ControlPoint finish = new MarkImpl("Finish");
Set<Waypoint> waypoints = new HashSet<>();
Waypoint startWaypoint = new WaypointImpl(start);
waypoints.add(startWaypoint);
Waypoint m1Waypoint1 = new WaypointImpl(m1);
Waypoint m2Waypoint1 = new WaypointImpl(m2);
Waypoint m1Waypoint2 = new WaypointImpl(m1);
Waypoint m2Waypoint2 = new WaypointImpl(m2);
Waypoint m1Waypoint3 = new WaypointImpl(m1);
waypoints.add(m1Waypoint1);
waypoints.add(m2Waypoint1);
waypoints.add(m1Waypoint2);
waypoints.add(m2Waypoint2);
waypoints.add(m1Waypoint3);
Waypoint finishWaypoint = new WaypointImpl(finish);
waypoints.add(finishWaypoint);
Course course = new CourseImpl(raceColumnName, waypoints);
TrackedRace mockedTrackedRace = createSpyedTrackedRace(mockedRegatta, course, timePoint, boatClass);
raceColumn.setTrackedRace(fleet, mockedTrackedRace);
Set<String> raceColumnNames = new HashSet<>();
raceColumnNames.add(raceColumnName);
int[] ruleRaw = { 5, 3, 2 };
ThresholdBasedResultDiscardingRule rule = new ThresholdBasedResultDiscardingRuleImpl(ruleRaw);
Leaderboard leaderboard = new RegattaLeaderboardImpl(mockedRegatta, rule);
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false,
trackedRegattaRegistry, baseDomainFactory, /* fillNetPointsUncorrected */ false);
assertEquals(6, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
course.removeWaypoint(2);
course.removeWaypoint(3);
leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false, trackedRegattaRegistry,
baseDomainFactory, /* fillNetPointsUncorrected */ false);
assertEquals(4, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
}
private TrackedRace createSpyedTrackedRace(Regatta regatta, Course course, TimePoint timePoint, BoatClass boatClass) {
TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta);
RaceDefinition mockedRace = createMockedRace(course, boatClass);
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class)));
return spyedTrackedRace;
}
private RaceDefinition createMockedRace(Course course, BoatClass boatClass) {
RaceDefinition mockedRaceDefinition = mock(RaceDefinition.class);
when(mockedRaceDefinition.getCompetitors()).thenReturn(new HashSet<Competitor>());
when(mockedRaceDefinition.getCourse()).thenReturn(course);
when(mockedRaceDefinition.getBoatClass()).thenReturn(new BoatClassImpl("TestClass", true));
when(mockedRaceDefinition.getName()).thenReturn("TestRace");
Iterable<Competitor> competitorSet = createCompetitorSet(boatClass);
when(mockedRaceDefinition.getCompetitors()).thenReturn(competitorSet);
return mockedRaceDefinition;
}
private Iterable<Competitor> createCompetitorSet(BoatClass boatClass) {
Set<Competitor> competitors = new HashSet<>();
DynamicBoat mockedBoat = mock(DynamicBoat.class);
when(mockedBoat.getBoatClass()).thenReturn(boatClass);
competitors.add(new CompetitorImpl(UUID.randomUUID(), "TestCompetitor", Color.BLACK, null, null,
mock(DynamicTeam.class), mockedBoat, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null));
return competitors;
}
private TrackedRegatta createMockedTrackedRegatta(Regatta regatta) {
TrackedRegatta mockedTrackedRegatta = mock(DynamicTrackedRegatta.class);
when(mockedTrackedRegatta.getRegatta()).thenReturn(regatta);
return mockedTrackedRegatta;
}
private Series createSeries(TrackedRegattaRegistry trackedRegattaRegistry, Fleet fleet) {
Set<Fleet> fleets = new HashSet<>();
fleets.add(fleet);
Series series = new SeriesImpl("TestSeries", false, fleets, new HashSet<String>(), trackedRegattaRegistry);
return series;
}
}
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
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.Series;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class LeaderboardCourseChangeTest {
/**
* See bug 2011
*
* @throws NoWindException
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public void testLeaderboardDTOCreationForCourseChange() throws NoWindException, InterruptedException, ExecutionException {
Date date = Calendar.getInstance().getTime();
TimePoint timePoint = new MillisecondsTimePoint(date);
TrackedRegattaRegistry trackedRegattaRegistry = mock(TrackedRegattaRegistry.class);
Fleet fleet = new FleetImpl("TestFleet");
Series series = createSeries(trackedRegattaRegistry, fleet);
Set<Series> seriesSet = new HashSet<>();
seriesSet.add(series);
BoatClass boatClass = new BoatClassImpl("TestClass", true);
String raceColumnName = "TestRace";
RaceColumn raceColumn = series.addRaceColumn(raceColumnName, trackedRegattaRegistry);
ScoringScheme scoringScheme = new LowPoint();
Regatta mockedRegatta = new RegattaImpl(RegattaImpl.getDefaultName("TestRegatta", boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, seriesSet, false, scoringScheme,
UUID.randomUUID(), mock(CourseArea.class), OneDesignRankingMetric::new);
ControlPoint start = new MarkImpl("Start");
ControlPoint m1 = new MarkImpl("M1");
ControlPoint m2 = new MarkImpl("M2");
ControlPoint finish = new MarkImpl("Finish");
Set<Waypoint> waypoints = new HashSet<>();
Waypoint startWaypoint = new WaypointImpl(start);
waypoints.add(startWaypoint);
Waypoint m1Waypoint1 = new WaypointImpl(m1);
Waypoint m2Waypoint1 = new WaypointImpl(m2);
Waypoint m1Waypoint2 = new WaypointImpl(m1);
Waypoint m2Waypoint2 = new WaypointImpl(m2);
Waypoint m1Waypoint3 = new WaypointImpl(m1);
waypoints.add(m1Waypoint1);
waypoints.add(m2Waypoint1);
waypoints.add(m1Waypoint2);
waypoints.add(m2Waypoint2);
waypoints.add(m1Waypoint3);
Waypoint finishWaypoint = new WaypointImpl(finish);
waypoints.add(finishWaypoint);
Course course = new CourseImpl(raceColumnName, waypoints);
TrackedRace mockedTrackedRace = createSpyedTrackedRace(mockedRegatta, course, timePoint, boatClass);
raceColumn.setTrackedRace(fleet, mockedTrackedRace);
Set<String> raceColumnNames = new HashSet<>();
raceColumnNames.add(raceColumnName);
int[] ruleRaw = { 5, 3, 2 };
ThresholdBasedResultDiscardingRule rule = new ThresholdBasedResultDiscardingRuleImpl(ruleRaw);
Leaderboard leaderboard = new RegattaLeaderboardImpl(mockedRegatta, rule);
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false,
trackedRegattaRegistry, baseDomainFactory, /* fillNetPointsUncorrected */ false);
assertEquals(6, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
course.removeWaypoint(2);
course.removeWaypoint(3);
leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false, trackedRegattaRegistry,
baseDomainFactory, /* fillNetPointsUncorrected */ false);
assertEquals(4, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
}
private TrackedRace createSpyedTrackedRace(Regatta regatta, Course course, TimePoint timePoint, BoatClass boatClass) {
TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta);
RaceDefinition mockedRace = createMockedRace(course, boatClass);
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class)));
return spyedTrackedRace;
}
private RaceDefinition createMockedRace(Course course, BoatClass boatClass) {
RaceDefinition mockedRaceDefinition = mock(RaceDefinition.class);
when(mockedRaceDefinition.getCompetitors()).thenReturn(new HashSet<Competitor>());
when(mockedRaceDefinition.getCourse()).thenReturn(course);
when(mockedRaceDefinition.getBoatClass()).thenReturn(new BoatClassImpl("TestClass", true));
when(mockedRaceDefinition.getName()).thenReturn("TestRace");
Iterable<Competitor> competitorSet = createCompetitorSet(boatClass);
when(mockedRaceDefinition.getCompetitors()).thenReturn(competitorSet);
return mockedRaceDefinition;
}
private Iterable<Competitor> createCompetitorSet(BoatClass boatClass) {
Set<Competitor> competitors = new HashSet<>();
DynamicBoat mockedBoat = mock(DynamicBoat.class);
when(mockedBoat.getBoatClass()).thenReturn(boatClass);
competitors.add(new CompetitorImpl(UUID.randomUUID(), "TestCompetitor", Color.BLACK, null, null,
mock(DynamicTeam.class), mockedBoat, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null));
return competitors;
}
private TrackedRegatta createMockedTrackedRegatta(Regatta regatta) {
TrackedRegatta mockedTrackedRegatta = mock(DynamicTrackedRegatta.class);
when(mockedTrackedRegatta.getRegatta()).thenReturn(regatta);
return mockedTrackedRegatta;
}
private Series createSeries(TrackedRegattaRegistry trackedRegattaRegistry, Fleet fleet) {
Set<Fleet> fleets = new HashSet<>();
fleets.add(fleet);
Series series = new SeriesImpl("TestSeries", false, fleets, new HashSet<String>(), trackedRegattaRegistry);
return series;
}
}
@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
@@ -36,7 +37,7 @@ public class MarkPositionTimeFilterTest {
m = new MarkImpl("Test Mark");
track = new DynamicGPSFixTrackImpl<Mark>(m, /* millisecondsOverWhichToAverage */ 5000);
when(trackedRace.getOrCreateTrack(m)).thenReturn(track);
doCallRealMethod().when(trackedRace).recordFix(same(m), (GPSFixMoving) anyObject());
doCallRealMethod().when(trackedRace).recordFix(same(m), (GPSFixMoving) anyObject(), anyBoolean());
}
@Test
@@ -47,7 +48,7 @@ public class MarkPositionTimeFilterTest {
@Test
public void testAddFixForMark() {
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), MillisecondsTimePoint.now(),
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -64,7 +65,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -81,7 +82,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertTrue(track.getRawFixes().isEmpty());
@@ -98,7 +99,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertTrue(track.getRawFixes().isEmpty());
@@ -107,7 +108,7 @@ public class MarkPositionTimeFilterTest {
}
when(trackedRace.getEndOfTracking()).thenReturn(fix.plus(10000));
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -193,7 +193,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", senderDomainFactory.getOrCreateNationality("GER"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
senderDomainFactory.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
senderDomainFactory.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Competitor receiversCompetitor1 = cloneBySerialization(sendersCompetitor1, receiverDomainFactory);
Competitor receiversSecondCopyOfCompetitor1 = cloneBySerialization(sendersCompetitor1, receiverDomainFactory);
assertSame(receiversCompetitor1, receiversSecondCopyOfCompetitor1);
@@ -112,6 +112,7 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS,
ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS)) {
receivers.add(r);
addReceiverToStopDuringTearDown(r);
}
addListenersForStoredDataAndStartController(receivers);
raceDefinition = DomainFactory.INSTANCE.getAndWaitForRaceDefinition(race.getId());
@@ -54,7 +54,6 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
@Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
System.out.println("Received fix "+fix);
synchronized (semaphor) {
if (first) {
firstTracked[0] = competitor;
@@ -89,6 +88,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) {
receiver.subscribe();
getRaceSubscriber().start();
addReceiverToStopDuringTearDown(receiver);
}
addListenersForStoredDataAndStartController(domainFactory
.getUpdateReceivers(trackedRegatta, /* delayToLiveInMillis */0l, null, /* simulator */
@@ -118,7 +118,7 @@ public abstract class StoredTrackBasedTest extends TrackBasedTest {
DynamicPerson p = new PersonImpl(competitorName, /* nationality */ null, /* dateOfBirth */ null, /* description */ null);
DynamicTeam t = new TeamImpl(competitorName, Collections.singleton(p), /* coach */ null);
Competitor c = new CompetitorImpl(competitorName, competitorName, Color.RED, null, null, t, new BoatImpl(competitorName,
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = readTrack(c, KIELER_WOCHE);
if (track != null) {
tracks.put(c, track);
@@ -40,7 +40,7 @@ public class TackTest extends StoredTrackBasedTestWithTrackedRace {
/* dateOfBirth */null, "This is famous Wolfgang Hunger")), new PersonImpl("Rigo van Maas",
new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl("Wolfgang Hunger's boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
setTrackedRace(createTestTrackedRace("Kieler Woche", "505 Race 2", "505", Collections.singleton(competitor),
new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime())));
}
@@ -69,7 +69,7 @@ public abstract class TrackBasedTest {
/* dateOfBirth */null, "This is famous " + competitorName)), new PersonImpl("Rigo van Maas",
new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
}
/**
@@ -278,7 +278,7 @@ public class WindTest {
/* dateOfBirth */null, "This is famous " + "Test Competitor")), new PersonImpl("Rigo van Maas",
new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl("Test Competitor" + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
new BoatClassImpl("505", /* typicallyStartsUpwind */true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
final BoatClass boatClass = domainFactory.getOrCreateBoatClass("ESS40");
DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(
new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
@@ -123,7 +123,7 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
Map<Competitor, Map<Waypoint, MarkPassing>> computedPasses = new HashMap<>();
// Get calculatedMarkPasses
long time = System.currentTimeMillis();
new MarkPassingCalculator(getTrackedRace(), false);
new MarkPassingCalculator(getTrackedRace(), false, /* waitForInitialMarkPassingCalculation */ true);
time = System.currentTimeMillis() - time;
for (Competitor c : getRace().getCompetitors()) {
@@ -46,9 +46,9 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
public class AbstractMockedRaceMarkPassingTest {
final BoatClassImpl boatClass = new BoatClassImpl("boat", true, "boat", new MeterDistance(10), new MeterDistance(5), null);
protected Competitor ron = new CompetitorImpl("Ron", "Ron", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
protected Competitor tom = new CompetitorImpl("Tom", "Tom", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
protected Competitor ben = new CompetitorImpl("Ben", "Ben", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
protected Competitor ron = new CompetitorImpl("Ron", "Ron", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
protected Competitor tom = new CompetitorImpl("Tom", "Tom", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
protected Competitor ben = new CompetitorImpl("Ben", "Ben", null, null, null, null, new BoatImpl("boat", boatClass, "boot"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
protected Mark m = new MarkImpl("Mark");
protected Mark gate1 = new MarkImpl("Gate1");
@@ -54,7 +54,7 @@ public class StarIDM2013MarkPassingTest extends AbstractMarkPassingTest {
}
private void testWholeRace5() throws InvalidDateException {
new MarkPassingCalculator(getTrackedRace(), false); // do our calculation, injecting into TrackedRace
new MarkPassingCalculator(getTrackedRace(), false, /* waitForInitialMarkPassingCalculation */ true); // do our calculation, injecting into TrackedRace
final Competitor GER7897 = getCompetitorByName("Tusch, Frank,Winkelmann, Sven");
assertMarkPassing(GER7897, Util.get(getWaypoints(), 0), DateParser.parse("2013-05-04T14:50:10+0200"));
assertMarkPassing(GER7897, Util.get(getWaypoints(), 1), DateParser.parse("2013-05-04T14:57:12+0200"));
@@ -79,7 +79,7 @@ public interface DomainFactory {
com.sap.sailing.domain.base.Competitor getOrCreateCompetitor(ICompetitor competitor);
com.sap.sailing.domain.base.Competitor getOrCreateCompetitor(UUID competitorId, String competitorClassName,
String nationalityAsString, String name, String shortName, float timeOnTimeFactor, float timeOnDistanceAllowanceInSecondsPerNauticalMile);
String nationalityAsString, String name, String shortName, float timeOnTimeFactor, float timeOnDistanceAllowanceInSecondsPerNauticalMile, String searchTag);
/**
* Looks up or, if not found, creates a {@link Nationality} object and re-uses <code>threeLetterIOCCode</code> also as the
@@ -241,14 +241,14 @@ public class DomainFactoryImpl implements DomainFactory {
final String name = competitor.getName();
final String shortName = competitor.getShortName();
Competitor result = getOrCreateCompetitor(competitorId, competitorClassName, nationalityAsString, name,
shortName, competitor.getHandicapToT(), competitor.getHandicapToD());
shortName, competitor.getHandicapToT(), competitor.getHandicapToD(), null);
return result;
}
@Override
public Competitor getOrCreateCompetitor(final UUID competitorId, final String competitorClassName,
final String nationalityAsString, final String name, final String shortName, float timeOnTimeFactor,
float timeOnDistanceAllowanceInSecondsPerNauticalMile) {
float timeOnDistanceAllowanceInSecondsPerNauticalMile, String searchTag) {
CompetitorStore competitorStore = baseDomainFactory.getCompetitorStore();
Competitor result = competitorStore.getExistingCompetitorById(competitorId);
if (result == null || competitorStore.isCompetitorToUpdateDuringGetOrCreate(result)) {
@@ -265,7 +265,7 @@ public class DomainFactoryImpl implements DomainFactory {
DynamicBoat boat = new BoatImpl(shortName, boatClass, shortName);
result = competitorStore.getOrCreateCompetitor(competitorId, name, null /* displayColor */,
null /* email */, null /* flagImag */, team, boat, (double) timeOnTimeFactor,
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile*1000)));
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile*1000)), searchTag);
}
return result;
}
@@ -1,21 +1,21 @@
package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface DynamicCompetitorStore extends CompetitorStore {
@Override
DynamicCompetitor getExistingCompetitorById(Serializable competitorId);
@Override
DynamicCompetitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email, URI flagImage,
DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile);
@Override
Iterable<? extends DynamicCompetitor> getCompetitors();
}
package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface DynamicCompetitorStore extends CompetitorStore {
@Override
DynamicCompetitor getExistingCompetitorById(Serializable competitorId);
@Override
DynamicCompetitor getOrCreateCompetitor(Serializable competitorId, String name, Color displayColor, String email, URI flagImage,
DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag);
@Override
Iterable<? extends DynamicCompetitor> getCompetitors();
}
@@ -124,6 +124,11 @@ public class LeaderboardCacheManager {
//ignore (email not shown in leaderboard)
}
@Override
public void searchTagChanged(String oldSearchTag, String newSearchTag) {
//ignore (email not shown in leaderboard)
}
@Override
public void flagImageChanged(URI oldFlagImageURL, URI newFlagImageURL) {
removeFromCache(leaderboard);
@@ -1,9 +1,10 @@
package com.sap.sailing.domain.markpassingcalculation;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sse.common.TimePoint;
import com.sap.sailing.domain.markpassingcalculation.impl.CandidateChooserImpl;
import com.sap.sailing.domain.markpassingcalculation.impl.CandidateImpl;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sse.common.TimePoint;
/**
* Represent the possible {@link MarkPassing} of a {@link Waypoint}. It contains the {@link Waypoint} it might be passing, a
@@ -15,9 +15,6 @@ import com.sap.sse.common.Util;
* @author Nicolas Klose
*/
public interface CandidateFinder {
/**
* @param fixes
* Either new fixes or fixes that may have changed their status, e.g. as a result of new mark
@@ -26,8 +23,6 @@ public interface CandidateFinder {
*/
Util.Pair<Iterable<Candidate>, Iterable<Candidate>> getCandidateDeltas(Competitor c, Iterable<GPSFix> fixes);
/**
* When initializing or refreshing the calculator, the whole race until now is evaluated. For that purpose all of the
* {@link Candidate}s are needed instead of just the deltas.
@@ -41,5 +36,4 @@ public interface CandidateFinder {
* mark fixes..
*/
Map<Competitor, List<GPSFix>> calculateFixesAffectedByNewMarkFixes(Map<Mark, List<GPSFix>> newMarkFixes);
}
@@ -34,7 +34,7 @@ import com.sap.sse.util.impl.ThreadFactoryWithPriority;
* Calculates the {@link MarkPassing}s for a {@link DynamicTrackedRace} using an {@link CandidateFinder} and an
* {@link CandidateChooser}. The finder evaluates the fixes and finds possible MarkPassings as {@link Candidate}s . The
* chooser than finds the most likely sequence of {@link Candidate}s and updates the race with new {@link MarkPassing}s
* for this sequence. Upon calling the constructor {@link #MarkPassingCalculator(DynamicTrackedRace, boolean)} this
* for this sequence. Upon calling the constructor {@link #MarkPassingCalculator(DynamicTrackedRace, boolean, boolean)} this
* happens for the current state of the race. In addition, for live races, the <code>listen</code> parameter of the
* constructor should be true. Then a {@link MarkPassingUpdateListener} is initialized which puts new fixes into a queue
* as {@link StorePositionUpdateStrategy}. A new thread will also be started to evaluate the new fixes (See
@@ -58,7 +58,7 @@ public class MarkPassingCalculator {
private boolean suspended = false;
public MarkPassingCalculator(DynamicTrackedRace race, boolean listen) {
public MarkPassingCalculator(DynamicTrackedRace race, boolean listen, boolean waitForInitialMarkPassingCalculation) {
if (listen) {
listener = new MarkPassingUpdateListener(race);
} else {
@@ -67,14 +67,21 @@ public class MarkPassingCalculator {
this.race = race;
finder = new CandidateFinderImpl(race);
chooser = new CandidateChooserImpl(race);
for (Competitor c : race.getRace().getCompetitors()) {
Util.Pair<Iterable<Candidate>, Iterable<Candidate>> allCandidates = finder.getAllCandidates(c);
chooser.calculateMarkPassDeltas(c, allCandidates.getA(), allCandidates.getB());
}
if (listen) {
final Thread listenerThread = new Thread(new Listen(race.getRace().getName()), "MarkPassingCalculator for race " + race.getRace().getName());
listenerThread.setDaemon(true);
listenerThread.start();
Thread t = new Thread(() -> {
for (Competitor c : race.getRace().getCompetitors()) {
Util.Pair<Iterable<Candidate>, Iterable<Candidate>> allCandidates = finder.getAllCandidates(c);
chooser.calculateMarkPassDeltas(c, allCandidates.getA(), allCandidates.getB());
}
if (listen) {
final Thread listenerThread = new Thread(new Listen(race.getRace().getName()), "MarkPassingCalculator for race " + race.getRace().getName());
listenerThread.setDaemon(true);
listenerThread.start();
}
}, "MarkPassingCalculator for race "+race.getRace().getName()+" initialization");
if (waitForInitialMarkPassingCalculation) {
t.run();
} else {
t.start();
}
}
@@ -30,6 +30,8 @@ import com.sap.sse.common.Util.Triple;
public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
private static final Logger logger = Logger.getLogger(MarkPassingUpdateListener.class.getName());
private LinkedBlockingQueue<StorePositionUpdateStrategy> queue;
private final String raceName;
private final StorePositionUpdateStrategy endMarker = new StorePositionUpdateStrategy() {
@Override
public void storePositionUpdate(Map<Competitor, List<GPSFix>> competitorFixes,
@@ -44,6 +46,7 @@ public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
* Adds itself automatically as a Listener on the <code>race</code> and its course.
*/
public MarkPassingUpdateListener(DynamicTrackedRace race) {
raceName = race.getRace().getName();
queue = new LinkedBlockingQueue<>();
race.addListener(this);
race.getRace().getCourse().addCourseListener(this);
@@ -98,7 +101,7 @@ public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
}
public void stop() {
logger.info("Stopping " + this);
logger.info("Stopping " + this + " for race " + raceName);
queue.add(endMarker);
}
@@ -31,6 +31,7 @@ import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sse.common.Duration;
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.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -106,7 +107,7 @@ public class CandidateChooserImpl implements CandidateChooser {
private final CandidateWithSettableTime start;
private final CandidateWithSettableWaypointIndex end;
private final DynamicTrackedRace race;
public CandidateChooserImpl(DynamicTrackedRace race) {
this.race = race;
waypointPositionAndDistanceCache = new WaypointPositionAndDistanceCache(race, Duration.ONE_MINUTE);
@@ -395,8 +396,9 @@ public class CandidateChooserImpl implements CandidateChooser {
}
}
}
Candidate marker = candidateWithParentAndHighestTotalProbability.get(endOfFixedInterval).getA();
while (marker.getOneBasedIndexOfWaypoint() > 0) {
final Pair<Candidate, Double> bestCandidateAndProbabilityForEndOfFixedInterval = candidateWithParentAndHighestTotalProbability.get(endOfFixedInterval);
Candidate marker = bestCandidateAndProbabilityForEndOfFixedInterval == null ? null : bestCandidateAndProbabilityForEndOfFixedInterval.getA();
while (marker != null && marker.getOneBasedIndexOfWaypoint() > 0) {
mostLikelyCandidates.add(marker);
marker = candidateWithParentAndHighestTotalProbability.get(marker).getA();
}
@@ -49,7 +49,6 @@ import com.sap.sse.common.Util.Pair;
*
*/
public class CandidateFinderImpl implements CandidateFinder {
// The higher this is, the closer the fixes have to be to waypoint to become a Candidate
private final int STRICTNESS_OF_DISTANCE_BASED_PROBABILITY = 7;
@@ -775,18 +774,21 @@ public class CandidateFinderImpl implements CandidateFinder {
final DynamicGPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(otherCompetitor);
if (track != null) {
final Position estimatedPositionAtT = track.getEstimatedPosition(t, /* extrapolate */ true);
final Distance otherCompetitorsDistanceToStartAtT = getMinDistanceOrNull(calculateDistance(estimatedPositionAtT, start, t));
if (otherCompetitorsDistanceToStartAtT != null) {
final Distance crossTrackError;
if (startIsLine) {
Pair<Position, Bearing> crossingInformationForStartLine = crossingInformationForStart.iterator().next();
crossTrackError = estimatedPositionAtT.crossTrackError(crossingInformationForStartLine.getA(),
crossingInformationForStartLine.getB());
} else {
crossTrackError = null;
// consider that a position may not be available for that other competitor, although a track exists
if (estimatedPositionAtT != null) {
final Distance otherCompetitorsDistanceToStartAtT = getMinDistanceOrNull(calculateDistance(estimatedPositionAtT, start, t));
if (otherCompetitorsDistanceToStartAtT != null) {
final Distance crossTrackError;
if (startIsLine) {
Pair<Position, Bearing> crossingInformationForStartLine = crossingInformationForStart.iterator().next();
crossTrackError = estimatedPositionAtT.crossTrackError(crossingInformationForStartLine.getA(),
crossingInformationForStartLine.getB());
} else {
crossTrackError = null;
}
distancesToStartLineOfOtherCompetitors.add(new
AbsoluteGeometricDistanceAndSignedProjectedDistanceToStartLine(otherCompetitorsDistanceToStartAtT, crossTrackError));
}
distancesToStartLineOfOtherCompetitors.add(new
AbsoluteGeometricDistanceAndSignedProjectedDistanceToStartLine(otherCompetitorsDistanceToStartAtT, crossTrackError));
}
}
}
@@ -960,7 +962,11 @@ public class CandidateFinderImpl implements CandidateFinder {
result = 1;
} else {
//TODO There should be a constant (either the 1.5 or the -0.2) which controls how strict the the curve is.
result = (1-PENALTY_FOR_WRONG_SIDE) * Math.pow(1.5, -0.2 * onWrongSide.getMeters()) + PENALTY_FOR_WRONG_SIDE;
result = Math.min(1.0, (1-PENALTY_FOR_WRONG_SIDE) *
// consider the possibility that both, mark and boat could have been GPSFix.TYPICAL_HDOP off and
// only start penalizing beyond this distance
Math.pow(1.5, -0.2 * onWrongSide.add(GPSFix.TYPICAL_HDOP.scale(-2.0)).getMeters())
+ PENALTY_FOR_WRONG_SIDE);
}
return result;
}
@@ -1003,7 +1009,9 @@ public class CandidateFinderImpl implements CandidateFinder {
Distance legLength = getAverageLengthOfAdjacentLegs(t, w);
if (legLength != null) {
result = 1 / (STRICTNESS_OF_DISTANCE_BASED_PROBABILITY/* Raising this will make it stricter */
* Math.abs(distance.getMeters() / legLength.getMeters()) + 1);
// reduce distance by 2x the typical HDOP, accounting for the possibility that some distance from the mark
// may have been caused by inaccurate GPS tracking
* Math.abs(Math.max(0.0, distance.add(GPSFix.TYPICAL_HDOP.scale(-2)).getMeters()) / legLength.getMeters()) + 1);
} else {
result = null;
}
@@ -131,7 +131,7 @@ public abstract class AbstractRankingMetric implements RankingMetric {
* Helper instance used to encode <code>null</code> values in {@link ConcurrentHashMap} instances which do not accept
* <code>null</code> as key nor value.
*/
private final static Competitor NULL_COMPETITOR = new CompetitorImpl(null, null, null, null, null, null, null, null, null);
private final static Competitor NULL_COMPETITOR = new CompetitorImpl(null, null, null, null, null, null, null, null, null, null);
public abstract class AbstractRankingInfo implements RankingMetric.RankingInfo {
private static final long serialVersionUID = 6845168655725234325L;
@@ -100,6 +100,11 @@ public class DummyMarkPassingWithTimePointOnly implements MarkPassing {
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return null;
}
@Override
public String getSearchTag() {
return null;
}
};
}
@@ -104,9 +104,6 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
this.startTimeChangedListeners = new HashSet<>();
this.raceAbortedListeners = new HashSet<>();
this.raceIsKnownToStartUpwind = race.getBoatClass().typicallyStartsUpwind();
if (markPassingCalculator != null) {
logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener());
}
if (!raceIsKnownToStartUpwind) {
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
for (WindSource windSourceToExclude : getWindSourcesToExclude()) {
@@ -135,6 +132,14 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
startTimeChangedListeners = new HashSet<>();
raceAbortedListeners = new HashSet<>();
}
protected Object readResolve() {
super.readResolve();
if (markPassingCalculator != null) {
logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener());
}
return this;
}
/**
* {@link #raceIsKnownToStartUpwind} (see also {@link #raceIsKnownToStartUpwind()}) is initialized based on the <code>race</code>'s
@@ -1011,7 +1016,11 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
@Override
protected MarkPassingCalculator createMarkPassingCalculator() {
return new MarkPassingCalculator(this, true);
// not waiting for initial mark passing creation is essential for not holding up, e.g.,
// an initial load during replication where it is perfectly fine to obtain the results from
// mark passing analysis as they become available; for test cases, however, "true" would
// be a more appropriate choice
return new MarkPassingCalculator(this, true, /* waitForInitialMarkPassingCalculation */ false);
}
@Override
@@ -281,7 +281,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
private transient ConcurrentHashMap<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
protected final MarkPassingCalculator markPassingCalculator;
protected transient MarkPassingCalculator markPassingCalculator;
private final boolean hasMarkPassingCalculator;
private final ConcurrentHashMap<Mark, GPSFixTrack<Mark, GPSFix>> markTracks;
@@ -535,13 +536,16 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public void raceAdded(TrackedRace trackedRace) {}
@Override
public void raceRemoved(TrackedRace trackedRace) {
// stop mark passing calculator when tracked race is removed:
markPassingCalculator.stop();
if (trackedRace == TrackedRaceImpl.this) {
// stop mark passing calculator when tracked race is removed:
markPassingCalculator.stop();
}
}
});
} else {
markPassingCalculator = null;
}
hasMarkPassingCalculator = useInternalMarkPassingAlgorithm;
// now wait until wind loading has at least started; then we know that the serialization lock is safely held by the loader
try {
waitUntilLoadingFromWindStoreComplete();
@@ -643,6 +647,17 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
triggerManeuverCacheRecalculationForAllCompetitors();
logger.info("Deserialized race " + getRace().getName());
}
/**
* After the object graph has entirely been re-constructed, create the mark passing calculator if
* the original object had one.
*/
protected Object readResolve() {
if (hasMarkPassingCalculator) {
markPassingCalculator = createMarkPassingCalculator();
}
return this;
}
/**
* When the {@link TrackedRace} object and the {@link RaceDefinition} and in particular its {@link CourseImpl} objects are not
@@ -72,7 +72,7 @@
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
</launchConfiguration>
@@ -7,14 +7,14 @@ import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsPresent
public class UserProfileDetailsPresenter implements UserProfileDetailsView.Presenter {
private final UserProfileDetailsView view;
private final UserProfileView.Presenter userProfilePresenter;
private final UserDetailsPresenter userDetailsPresenter;
public UserProfileDetailsPresenter(UserProfileDetailsView view, UserProfileView.Presenter userProfilePresenter) {
this.view = view;
this.userProfilePresenter = userProfilePresenter;
view.setPresenter(this);
userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(),
this.userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(),
userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(),
userProfilePresenter.getMailVerifiedUrl());
}
@@ -24,4 +24,9 @@ public class UserProfileDetailsPresenter implements UserProfileDetailsView.Prese
view.getDecorator().setAuthenticationContext(authenticationContext);
userDetailsPresenter.setAuthenticationContext(authenticationContext);
}
@Override
public void doTriggerLoginForm() {
userProfilePresenter.doTriggerLoginForm();
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.detailstab;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
public interface UserProfileDetailsView extends IsWidget {
@@ -13,7 +14,7 @@ public interface UserProfileDetailsView extends IsWidget {
NeedsAuthenticationContext getDecorator();
public interface Presenter {
public interface Presenter extends NotLoggedInPresenter {
void setAuthenticationContext(AuthenticationContext userManagementContext);
}
}
@@ -6,7 +6,6 @@ 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.common.client.SharedResources;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.userprofile.desktop.userdetails.UserAccountDetails;
@@ -28,19 +27,13 @@ public class UserProfileDetailsViewImpl extends Composite implements UserProfile
@UiField(provided = true)
UserAccountDetails accountDetailsUi;
private UserProfileView.Presenter currentPresenter;
public UserProfileDetailsViewImpl() {
}
public UserDetailsView getUserDetailsView() {
return accountDetailsUi;
}
@Override
public void setPresenter(Presenter presenter) {
decoratorUi = new AuthorizedContentDecoratorDesktop(currentPresenter);
decoratorUi = new AuthorizedContentDecoratorDesktop(presenter);
accountDetailsUi = new UserAccountDetails(SharedResources.INSTANCE);
initWidget(ourUiBinder.createAndBindUi(this));
}
@@ -242,7 +242,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
protected void fillCourseAreaListBox(EventDTO selectedEvent) {
courseAreaListBox.addItem(stringMessages.selectCourseArea());
for (CourseAreaDTO courseArea : selectedEvent.venue.getCourseAreas()) {
courseAreaListBox.addItem(courseArea.getName());
courseAreaListBox.addItem(courseArea.getName(), courseArea.id.toString());
if (courseArea.id.equals(regatta.defaultCourseAreaUuid)) {
courseAreaListBox.setSelectedIndex(courseAreaListBox.getItemCount() - 1);
}
@@ -270,9 +270,9 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
EventDTO event = getSelectedEvent();
int selIndex = courseAreaListBox.getSelectedIndex();
if (selIndex > 0 && event != null) { // the zero index represents the 'no selection' text
String itemText = courseAreaListBox.getItemText(selIndex);
String selectedCourseAreaIdAsString = courseAreaListBox.getValue(selIndex);
for (CourseAreaDTO courseAreaDTO : event.venue.getCourseAreas()) {
if (courseAreaDTO.getName().equals(itemText)) {
if (courseAreaDTO.id.toString().equals(selectedCourseAreaIdAsString)) {
result = courseAreaDTO;
break;
}
@@ -45,6 +45,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
private final ListBox threeLetterIocCountryCode;
private final TextBox sailId;
private final TextBox email;
private final TextBox searchTag;
private final StringMessages stringMessages;
private final URLFieldWithFileUpload flagImageURL;
private final URLFieldWithFileUpload imageUrlAndUploadComposite;
@@ -58,7 +59,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
* The 'competitorToEdit' parameter contains the competitor which should be changed or initialized.
* @param boatClass
* The boat class is the default shown boat class for new competitors. Set <code>null</code> if your competitor is
* already initialized or you don´t want a default boat class.
* already initialized or you don�t want a default boat class.
*/
public CompetitorEditDialog(final StringMessages stringMessages, CompetitorDTO competitorToEdit,
DialogCallback<CompetitorDTO> callback, String boatClass) {
@@ -102,6 +103,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
this.name = createTextBox(competitorToEdit.getName());
name.ensureDebugId("NameTextBox");
this.email = createTextBox(competitorToEdit.getEmail());
this.searchTag = createTextBox(competitorToEdit.getSearchTag());
this.displayColorTextBox = createTextBox(competitorToEdit.getColor() == null ? "" : competitorToEdit.getColor().getAsHtml());
this.threeLetterIocCountryCode = createListBox(/* isMultipleSelect */ false);
CountryCodeFactory ccf = CountryCodeFactory.INSTANCE;
@@ -198,13 +200,13 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
imageUrlAndUploadComposite.getURL(), flagImageURL.getURL(), boat, boatClass,
timeOnTimeFactor.getValue(),
timeOnDistanceAllowanceInSecondsPerNauticalMile.getValue() == null ? null :
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile.getValue()*1000)));
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile.getValue()*1000)), searchTag.getValue());
return result;
}
@Override
protected Widget getAdditionalWidget() {
Grid result = new Grid(10, 2);
Grid result = new Grid(11, 2);
result.setWidget(0, 0, new Label(stringMessages.name()));
result.setWidget(0, 1, name);
result.setWidget(1, 0, new Label(stringMessages.sailNumber()));
@@ -215,16 +217,18 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
result.setWidget(3, 1, displayColorTextBox);
result.setWidget(4, 0, new Label(stringMessages.email()));
result.setWidget(4, 1, email);
result.setWidget(5, 0, new Label(stringMessages.boatClass()));
result.setWidget(5, 1, boatClassName);
result.setWidget(6, 0, new Label(stringMessages.flagImageURL()));
result.setWidget(6, 1, flagImageURL);
result.setWidget(7, 0, new Label(stringMessages.imageURL()));
result.setWidget(7, 1, imageUrlAndUploadComposite);
result.setWidget(8, 0, new Label(stringMessages.timeOnTimeFactor()));
result.setWidget(8, 1, timeOnTimeFactor);
result.setWidget(9, 0, new Label(stringMessages.timeOnDistanceAllowanceInSecondsPerNauticalMile()));
result.setWidget(9, 1, timeOnDistanceAllowanceInSecondsPerNauticalMile);
result.setWidget(5, 0, new Label(stringMessages.searchTag()));
result.setWidget(5, 1, searchTag);
result.setWidget(6, 0, new Label(stringMessages.boatClass()));
result.setWidget(6, 1, boatClassName);
result.setWidget(7, 0, new Label(stringMessages.flagImageURL()));
result.setWidget(7, 1, flagImageURL);
result.setWidget(8, 0, new Label(stringMessages.imageURL()));
result.setWidget(8, 1, imageUrlAndUploadComposite);
result.setWidget(9, 0, new Label(stringMessages.timeOnTimeFactor()));
result.setWidget(9, 1, timeOnTimeFactor);
result.setWidget(10, 0, new Label(stringMessages.timeOnDistanceAllowanceInSecondsPerNauticalMile()));
result.setWidget(10, 1, timeOnDistanceAllowanceInSecondsPerNauticalMile);
return result;
}
@@ -170,6 +170,20 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
}
});
TextColumn<CompetitorDTO> competitorSearchTagColumn = new TextColumn<CompetitorDTO>() {
@Override
public String getValue(CompetitorDTO competitor) {
return competitor.getSearchTag();
}
};
competitorSearchTagColumn.setSortable(true);
competitorColumnListHandler.setComparator(competitorSearchTagColumn, new Comparator<CompetitorDTO>() {
@Override
public int compare(CompetitorDTO o1, CompetitorDTO o2) {
return new NaturalComparator(false).compare(o1.getSearchTag(), o2.getSearchTag());
}
});
TextColumn<CompetitorDTO> timeOnTimeFactorColumn = new TextColumn<CompetitorDTO>() {
@Override
public String getValue(CompetitorDTO competitor) {
@@ -212,6 +226,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
string.add(t.getSailID());
string.add(t.getBoatClass().getName());
string.add(t.getIdAsString());
string.add(t.getSearchTag());
return string;
}
};
@@ -241,6 +256,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
table.addColumn(displayColorColumn, stringMessages.color());
table.addColumn(imageColumn, stringMessages.image());
table.addColumn(competitorEMailColumn, stringMessages.email());
table.addColumn(competitorSearchTagColumn, stringMessages.searchTag());
table.addColumn(competitorIdColumn, stringMessages.id());
table.addColumn(competitorActionColumn, stringMessages.actions());
table.ensureDebugId("CompetitorsTable");
@@ -0,0 +1,58 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.List;
import com.google.gwt.resources.client.ImageResource;
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.StringMessages;
import com.sap.sse.gwt.client.controls.listedit.ExpandedListEditorUi;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.ListEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.ListEditorUiStrategy;
public class CourseAreaListInlineEditorComposite extends GenericStringListInlineEditorComposite<CourseAreaDTO> {
public CourseAreaListInlineEditorComposite(Iterable<CourseAreaDTO> initialValues,
ListEditorUiStrategy<CourseAreaDTO> activeUi) {
super(initialValues, activeUi);
}
public CourseAreaListInlineEditorComposite(Iterable<CourseAreaDTO> initialValues, StringMessages stringMessages,
ImageResource removeImage, List<String> suggestValues, int textBoxSize) {
super(initialValues, stringMessages, removeImage, suggestValues, textBoxSize);
}
public static class CollapsedUi extends GenericStringListEditorComposite.CollapsedUi<CourseAreaDTO> {
public CollapsedUi(StringMessages stringMessages, String dialogTitle, ExpandedListEditorUi<CourseAreaDTO> expandedUi) {
super(stringMessages, dialogTitle, expandedUi);
}
@Override
protected ListEditorComposite<CourseAreaDTO> createExpandedUi(Iterable<CourseAreaDTO> initialValues, ExpandedListEditorUi<CourseAreaDTO> ui) {
return new CourseAreaListInlineEditorComposite(initialValues, ui);
}
}
@Override
protected CourseAreaDTO parse(String s) {
return new CourseAreaDTO(s);
}
@Override
protected CourseAreaDTO parse(String s, CourseAreaDTO valueToUpdate) {
final CourseAreaDTO result;
if (Util.equalsWithNull(valueToUpdate.getName(), s)) {
result = valueToUpdate;
} else {
result = parse(s);
}
return result;
}
@Override
protected String toString(CourseAreaDTO value) {
return value.getName();
}
}
@@ -7,6 +7,7 @@ import java.util.List;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
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.gwt.client.media.ImageDTO;
@@ -45,6 +46,6 @@ public class EventCreateDialog extends EventDialog {
imagesListComposite.fillImages(Collections.<ImageDTO>emptyList());
videosListComposite.fillVideos(Collections.<VideoDTO>emptyList());
// add default course area
courseAreaNameList.setValue(Collections.singletonList("Default"));
courseAreaNameList.setValue(Collections.singletonList(new CourseAreaDTO("Default")));
}
}
@@ -34,8 +34,8 @@ import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
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;
@@ -50,12 +50,12 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
protected UUID id;
protected TextBox officialWebsiteURLEntryField;
protected Map<String, TextBox> sailorsInfoWebsiteURLEntryFields = new HashMap<>();
protected StringListInlineEditorComposite courseAreaNameList;
protected CourseAreaListInlineEditorComposite courseAreaNameList;
protected StringConstantsListEditorComposite leaderboardGroupList;
protected Map<String, LeaderboardGroupDTO> availableLeaderboardGroupsByName;
protected ImagesListComposite imagesListComposite;
protected VideosListComposite videosListComposite;
protected ImagesListComposite imagesListComposite;
protected VideosListComposite videosListComposite;
protected static class EventParameterValidator implements Validator<EventDTO> {
private StringMessages stringMessages;
@@ -76,8 +76,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
if (courseAreaNotEmpty) {
for (CourseAreaDTO courseArea : eventToValidate.venue.getCourseAreas()) {
courseAreaNotEmpty = courseArea.getName() != null && courseArea.getName().length() > 0;
if (!courseAreaNotEmpty)
if (!courseAreaNotEmpty) {
break;
}
}
}
@@ -138,11 +139,17 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
validate();
}
};
final ValueChangeHandler<Iterable<CourseAreaDTO>> courseAreaValueChangeHandler = new ValueChangeHandler<Iterable<CourseAreaDTO>>() {
@Override
public void onValueChange(ValueChangeEvent<Iterable<CourseAreaDTO>> event) {
validate();
}
};
courseAreaNameList = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
courseAreaNameList = new CourseAreaListInlineEditorComposite(Collections.<CourseAreaDTO> emptyList(),
new GenericStringListInlineEditorComposite.ExpandedUi<CourseAreaDTO>(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
SuggestedCourseAreaNames.suggestedCourseAreaNames, stringMessages.enterCourseAreaName(), 50));
courseAreaNameList.addValueChangeHandler(valueChangeHandler);
courseAreaNameList.addValueChangeHandler(courseAreaValueChangeHandler);
List<String> leaderboardGroupNames = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: availableLeaderboardGroups) {
leaderboardGroupNames.add(leaderboardGroupDTO.getName());
@@ -178,16 +185,11 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
result.endDate = endDateBox.getValue();
result.isPublic = isPublicCheckBox.getValue();
result.id = id;
List<CourseAreaDTO> courseAreas = new ArrayList<CourseAreaDTO>();
for (String courseAreaName : courseAreaNameList.getValue()) {
CourseAreaDTO courseAreaDTO = new CourseAreaDTO();
courseAreaDTO.setName(courseAreaName);
courseAreas.add(courseAreaDTO);
}
for (ImageDTO image: imagesListComposite.getAllImages()) {
List<CourseAreaDTO> courseAreas = courseAreaNameList.getValue();
for (ImageDTO image : imagesListComposite.getAllImages()) {
result.addImage(image);
}
for (VideoDTO video: videosListComposite.getAllVideos()) {
for (VideoDTO video : videosListComposite.getAllVideos()) {
result.addVideo(video);
}
result.venue = new VenueDTO(venueEntryField.getText(), courseAreas);
@@ -6,7 +6,6 @@ import java.util.List;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
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;
@@ -29,17 +28,10 @@ public class EventEditDialog extends EventDialog {
isPublicCheckBox = createCheckbox("");
isPublicCheckBox.setValue(event.isPublic);
id = event.id;
List<String> courseAreaNames = new ArrayList<>();
if (event.venue.getCourseAreas() != null && event.venue.getCourseAreas().size() > 0) {
for (CourseAreaDTO courseArea : event.venue.getCourseAreas()) {
courseAreaNames.add(courseArea.getName());
}
}
officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL());
officialWebsiteURLEntryField.setVisibleLength(50);
sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(event.getSailorsInfoWebsiteURLs());
courseAreaNameList.setValue(courseAreaNames);
courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas()));
List<String> leaderboardGroupNames = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) {
leaderboardGroupNames.add(leaderboardGroupDTO.getName());
@@ -130,9 +130,9 @@ public abstract class FlexibleLeaderboardDialog extends AbstractLeaderboardDialo
}
private void fillCourseAreaListBox(EventDTO selectedEvent) {
courseAreaListBox.addItem("Please select a course area...");
courseAreaListBox.addItem(stringMessages.pleaseSelectACourseArea());
for (CourseAreaDTO courseArea : selectedEvent.venue.getCourseAreas()) {
courseAreaListBox.addItem(courseArea.getName());
courseAreaListBox.addItem(courseArea.getName(), courseArea.id.toString());
}
courseAreaListBox.setEnabled(true);
}
@@ -156,10 +156,10 @@ public abstract class FlexibleLeaderboardDialog extends AbstractLeaderboardDialo
CourseAreaDTO result = null;
EventDTO event = getSelectedEvent();
int selIndex = courseAreaListBox.getSelectedIndex();
if(selIndex > 0 && event != null) { // the zero index represents the 'no selection' text
String itemText = courseAreaListBox.getItemText(selIndex);
for(CourseAreaDTO courseAreaDTO: event.venue.getCourseAreas()) {
if(courseAreaDTO.getName().equals(itemText)) {
if (selIndex > 0 && event != null) { // the zero index represents the 'no selection' text
String selectedCourseAreaId = courseAreaListBox.getValue(selIndex);
for (CourseAreaDTO courseAreaDTO : event.venue.getCourseAreas()) {
if (courseAreaDTO.id.toString().equals(selectedCourseAreaId)) {
result = courseAreaDTO;
break;
}
@@ -27,6 +27,7 @@ import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
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;
@@ -139,7 +140,7 @@ public abstract class ImageDialog extends DataEntryDialog<ImageDTO> {
});
tagsListEditor = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
new GenericStringListInlineEditorComposite.ExpandedUi<String>(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
MediaConstants.imageTagSuggestions, "Enter tags for the image", 30));
}
@@ -31,6 +31,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.StringListEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
@@ -234,7 +235,7 @@ public class SeriesEditDialog extends DataEntryDialog<SeriesDescriptor> {
return selectedSeries;
}
private class RaceNamesEditorUi extends StringListInlineEditorComposite.ExpandedUi {
private class RaceNamesEditorUi extends GenericStringListInlineEditorComposite.ExpandedUi<String> {
private final RegattaDTO regatta;
private final ListBox addRacesFromListBox;
@@ -217,7 +217,11 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
private boolean doesTrackerExist(RaceColumnDTOAndFleetDTOWithNameBasedEquality race) {
return race.getA().getRaceLogTrackingInfo(race.getB()).raceLogTrackerExists;
}
private boolean doesCourseExist(RaceColumnDTOAndFleetDTOWithNameBasedEquality race) {
return race.getA().getRaceLogTrackingInfo(race.getB()).courseExists;
}
private boolean doCompetitorResgistrationsExist(RaceColumnDTOAndFleetDTOWithNameBasedEquality race) {
return race.getA().getRaceLogTrackingInfo(race.getB()).competitorRegistrationsExists;
}
@@ -240,6 +244,13 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
}
};
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> courseStateColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality raceColumnAndFleetName) {
return doesCourseExist(raceColumnAndFleetName) ? stringMessages.ok() : stringMessages.none();
}
};
raceActionColumn =
new ImagesBarColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality, RaceLogTrackingEventManagementRaceImagesBarCell>(
new RaceLogTrackingEventManagementRaceImagesBarCell(stringMessages, this));
@@ -348,6 +359,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
racesTable.addColumn(raceLogTrackingStateColumn, stringMessages.raceStatusColumn());
racesTable.addColumn(trackerStateColumn, stringMessages.trackerStatus());
racesTable.addColumn(courseStateColumn, stringMessages.courseStatus());
racesTable.addColumn(raceActionColumn, stringMessages.actions());
racesTable.setWidth("600px");
}
@@ -22,6 +22,7 @@ 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.GenericStringListInlineEditorComposite;
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;
@@ -89,7 +90,7 @@ public abstract class VideoDialog extends DataEntryDialog<VideoDTO> {
});
thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
tagsListEditor = new StringListInlineEditorComposite(Collections.<String> emptyList(),
new StringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
new GenericStringListInlineEditorComposite.ExpandedUi<String>(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */
MediaConstants.videoTagSuggestions, "Enter tags for the video", 50));
}
@@ -1006,6 +1006,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String eMailMustNotBeEmpty();
String emailAddress();
String password();
String searchTag();
String doYouReallyWantToRemoveLeaderboard(String name);
String metaLeaderboardCannotBeChanged();
String failedToSetNewStartTime();
@@ -1039,6 +1040,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String removeLeaderboardFilter();
String competitorRegistrations();
String trackerStatus();
String courseStatus();
String canOnlyBeEditedBeforeStartingTracking();
String defineCourse();
String mapDevices();
@@ -977,6 +977,7 @@ successfullyRemoveIgtimiAccount=Successfully removed Igtimi account for user {0}
eMailMustNotBeEmpty=e-Mail address must not be empty
emailAddress=e-mail address
password=Password
searchTag=Search tag
doYouReallyWantToRemoveLeaderboard=Do you really want to remove the leaderboard: ''{0}''?
metaLeaderboardCannotBeChanged=This is a meta leaderboard. It can''t be changed here.
failedToSetNewStartTime=Failed to set new start time. This can happen when the same start time is already present in the race log or someone has added a start time that is newer (in terms of a pass id and logical time) than the one that you just added.
@@ -1009,6 +1010,7 @@ filterByLeaderboard=Filter by Leaderboard
removeLeaderboardFilter=Remove Leaderboard filter
competitorRegistrations=Competitor Registrations
trackerStatus=Tracker Status
courseStatus=Course Status
canOnlyBeEditedBeforeStartingTracking=Can only be edited before starting tracking
defineCourse=Define Course Layout
mapDevices=Map Devices to Competitors and Marks
@@ -415,8 +415,8 @@ successfullyUpdatedCourse=Kurs erfolgreich aktualisiert
selectTwoMarksForGate=Zwei Marken auswählen, um ein Gate zu erstellen
errorTryingToObtainTheMarksOfTheRace=Fehler beim Ermitteln der Marken des Regattakurses: {0}
errorTryingToObtainRaceCourse=Fehler beim Ermitteln des Rennkurses: {0}
insertWaypointBeforeSelected=Wegpunkt nach dem selektierten einfügen
insertWaypointAfterSelected=Wegpunkt vor dem selektierten einfügen
insertWaypointBeforeSelected=Wegpunkt vor dem selektierten einfügen
insertWaypointAfterSelected=Wegpunkt nach dem selektierten einfügen
addGate=Gate hinzufügen
scoringSchemeLowPointSystem=Low Point System
scoringSchemeHighPointSystem=High Point System
@@ -968,6 +968,7 @@ successfullyRemoveIgtimiAccount=Zugang zum Igtimi-Benutzerkonto {0} erfolgreich
eMailMustNotBeEmpty=e-Mailadresse darf nicht leer sein
emailAddress=e-Mailadresse
password=Kennwort
searchTag=Suchhilfe
doYouReallyWantToRemoveLeaderboard=Möchten Sie wirklich die Ergebnlisliste ''{0}'' löschen?
metaLeaderboardCannotBeChanged=Dies ist ein Meta-Leaderboard, das hier nicht geändert werden kann.
failedToSetNewStartTime=Neue Startzeit konnte nicht gesetzt werden.
@@ -998,8 +999,9 @@ denoteForRaceLogTracking=Für RaceLog Tracking markieren
startRaceLogTracking=RaceLog Tracking starten
filterByLeaderboard=Nach Rangliste filtern
removeLeaderboardFilter=Nicht nach Rangliste filtern
competitorRegistrations=Team Anmeldungen
trackerStatus=Tracker-Status
competitorRegistrations=Teamanmeldungen
trackerStatus=Trackerstatus
courseStatus=Kursstatus
canOnlyBeEditedBeforeStartingTracking=Kann nur vor Beginn des Trackings bearbeitet werden
defineCourse=Kurs definieren
mapDevices=Gerätezuordnung zu Teams und Tonnen
@@ -1416,7 +1418,7 @@ couldNotRetrieveImageSizeYet=Bildgröße konnte noch nicht ermittelt werden.
pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Bitte nur Inhalte hochladen, für die alle Verwendungsrechte vorliegen. Bitte beachten: Bilder können verändert wiedergegeben werden.
registerCompetitorsOnRace=Teilnehmer auf dem Rennen registrieren (z.B. für Split-Fleets)
doYouWantToRegisterCompetitorsDirectlyOnTheRace=Wollen Sie Teilnehmer direkt auf dem Rennen registrieren?
warningDirectCompetitorRegistration=Warnung! Diese Einstellung führt dazu, dass Teilnehmer dieses Rennens sich von nunan auf Rennebene registriert werden müssen. Dies ist nur sinnvoll, wenn sich die Teilnehmer verschiedener Rennen einer Regatta unterscheiden.
warningDirectCompetitorRegistration=Warnung! Diese Einstellung führt dazu, dass Teilnehmer dieses Rennens von nun an auf Rennebene registriert werden müssen. Dies ist nur sinnvoll, wenn sich die Teilnehmer verschiedener Rennen einer Regatta unterscheiden.
warningRegattaCompetitorRegistration=Warnung! Diese Einstellung reaktiviert die Teilnehmerregistrierung auf Regatta-Ebene. Alle Teilnehmer der zu diesem Rennen gehörenden Regatta werden automatisch Teilnehmer dieses Rennens.
doYouWantToDisableCompetitorsRegistrationsOnTheRace=Wollen Sie Teilnehmer auf Regatta- statt Rennebene registrieren?
competitorRegistrationsOnRaceDisabled=Teilnehmeranmeldung ist für dieses Rennen auf Rennebene deaktiviert. Aktivieren durch selektieren der CheckBox auf der linken Seite.
@@ -973,6 +973,7 @@ successfullyRemoveIgtimiAccount=已成功移除用户{0}的 Igtimi 账户
eMailMustNotBeEmpty=电子邮件地址不得为空
emailAddress=电子邮件地址
password=密码
searchTag=Search tag
doYouReallyWantToRemoveLeaderboard=是否确定移除积分榜: ''{0}''?
metaLeaderboardCannotBeChanged=此为元积分榜。无法在此处更改。
failedToSetNewStartTime=设置新开始时间失败。 相同的开始时间可能已存在于比赛轮次日志中或某人已添加(场次编号和逻辑时间)更新的开始时间。
@@ -1005,6 +1006,7 @@ filterByLeaderboard=按积分榜筛选
removeLeaderboardFilter=移除积分榜筛选器
competitorRegistrations=参赛队注册
trackerStatus=跟踪器状态
courseStatus=Course Status
canOnlyBeEditedBeforeStartingTracking=只可以在开始跟踪前编辑
defineCourse=定义场地设置
mapDevices=将设备映射到参赛队和标志
@@ -975,6 +975,7 @@ successfullyRemoveIgtimiAccount=已成功移除用户{0}的 Igtimi 账户
eMailMustNotBeEmpty=电子邮件地址不得为空
emailAddress=电子邮件地址
password=密码
searchTag=Search tag
doYouReallyWantToRemoveLeaderboard=是否确定移除积分榜: ''{0}''?
metaLeaderboardCannotBeChanged=此为元积分榜。无法在此处更改。
failedToSetNewStartTime=设置新开始时间失败。 相同的开始时间可能已存在于比赛轮次日志中或某人已添加(场次编号和逻辑时间)更新的开始时间。
@@ -1007,6 +1008,7 @@ filterByLeaderboard=按积分榜筛选
removeLeaderboardFilter=移除积分榜筛选器
competitorRegistrations=参赛队注册
trackerStatus=跟踪器状态
courseStatus=Course Status
canOnlyBeEditedBeforeStartingTracking=只可以在开始跟踪前编辑
defineCourse=定义场地设置
mapDevices=将设备映射到参赛队和标志
@@ -2453,8 +2453,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
new RaceLogTrackingStateAnalyzer(raceLog).analyze();
final boolean raceLogTrackerExists = raceLog == null ? false : getService().getRaceTrackerById(raceLog.getId()) != null;
final boolean competitorRegistrationsExist = raceLog == null ? false : !Util.isEmpty(raceColumn.getAllCompetitors(fleet));
final boolean courseExist = raceLog == null ? false : !Util.isEmpty(raceColumn.getCourseMarks(fleet));
final RaceLogTrackingInfoDTO raceLogTrackingInfo = new RaceLogTrackingInfoDTO(raceLogTrackerExists,
competitorRegistrationsExist, raceLogTrackingState);
competitorRegistrationsExist, courseExist, raceLogTrackingState);
raceColumnDTO.setRaceLogTrackingInfo(fleetDTO, raceLogTrackingInfo);
}
}
@@ -4718,7 +4719,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
competitor.getColor(), competitor.getEmail(),
competitor.getFlagImageURL() == null ? null : new URI(competitor.getFlagImageURL()), team, boat,
competitor.getTimeOnTimeFactor(),
competitor.getTimeOnDistanceAllowancePerNauticalMile()));
competitor.getTimeOnDistanceAllowancePerNauticalMile(), competitor.getSearchTag()));
} else {
result = getBaseDomainFactory().convertToCompetitorDTO(
getService().apply(
@@ -4727,7 +4728,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
competitor.getImageURL() == null ? null : new URI(competitor.getImageURL()),
competitor.getFlagImageURL() == null ? null : new URI(competitor.getFlagImageURL()),
competitor.getTimeOnTimeFactor(),
competitor.getTimeOnDistanceAllowancePerNauticalMile())));
competitor.getTimeOnDistanceAllowancePerNauticalMile(),
competitor.getSearchTag())));
}
return result;
}
@@ -5161,14 +5163,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
private Mark convertToMark(MarkDTO dto, boolean resolve) {
Mark result = null;
if (resolve) {
Mark existing = baseDomainFactory.getExistingMarkByIdAsString(dto.getIdAsString());
if (existing != null) {
return existing;
result = existing;
}
}
Serializable id = UUID.randomUUID();
return baseDomainFactory.getOrCreateMark(id, dto.getName(), dto.type, dto.color, dto.shape, dto.pattern);
if (result == null) {
Serializable id = UUID.randomUUID();
result = baseDomainFactory.getOrCreateMark(id, dto.getName(), dto.type, dto.color, dto.shape, dto.pattern);
}
return result;
}
/**
@@ -6,7 +6,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.common.dto.NamedDTO;
/**
* Equality and hash code are based on the course area's name, as inherited from {@link NamedDTO}.
* Equality and hash code are based on the course area's {@link #id}.
*/
public class CourseAreaDTO extends NamedDTO implements IsSerializable {
private static final long serialVersionUID = -5279690838452265454L;
@@ -18,4 +18,26 @@ public class CourseAreaDTO extends NamedDTO implements IsSerializable {
public CourseAreaDTO(String name) {
super(name);
}
@Override
public int hashCode() {
final int prime = 31;
int result = prime * ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
CourseAreaDTO other = (CourseAreaDTO) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
@@ -75,7 +75,7 @@ public class StoreAndLoadDeviceIdentifierTest extends AbstractMongoDBTest {
private DeviceIdentifier storeAndLoad(DeviceIdentifier device, TypeBasedServiceFinderFactory forStoring, TypeBasedServiceFinderFactory forLoading) {
createFactories(forStoring);
Competitor c = DomainFactory.INSTANCE.getOrCreateCompetitor("a", "a", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
Competitor c = DomainFactory.INSTANCE.getOrCreateCompetitor("a", "a", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(now(), now(), author, 0,
c, device, now(), now()));
createFactories(forLoading);
@@ -213,7 +213,7 @@ public class StoreAndLoadRaceLogEventsTest extends AbstractMongoDBTest {
RaceLogRegisterCompetitorEvent expectedEvent = new RaceLogRegisterCompetitorEventImpl(expectedEventTime,
expectedEventTime, author, expectedId, expectedPassId, DomainFactory.INSTANCE.getOrCreateCompetitor(
"comp", "comp", null, null, null, null, null,
/* timeOnTimeFactor */null, /* timeOnDistanceAllowancePerNauticalMile */null));
/* timeOnTimeFactor */null, /* timeOnDistanceAllowancePerNauticalMile */null, null));
DBObject dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent);
RaceLogRegisterCompetitorEvent actualEvent = loadEvent(dbObject);
@@ -1,122 +1,122 @@
package com.sap.sailing.mongodb.test;
import static org.junit.Assert.assertEquals;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.impl.CollectionNames;
import com.sap.sailing.domain.test.AbstractLeaderboardTest;
import com.sap.sse.common.Util;
public class StoreCompetitorTest extends AbstractMongoDBTest {
private DomainFactory domainFactory;
public StoreCompetitorTest() throws UnknownHostException, MongoException {
super();
}
@Before
public void setUp() {
// clear the domainFactory competitor store for a clean start:
domainFactory = new DomainFactoryImpl((srlid)->null);
}
private void dropCompetitorCollection() {
DB db = getMongoService().getDB();
DBCollection competitorCollection = db.getCollection(CollectionNames.COMPETITORS.name());
competitorCollection.setWriteConcern(WriteConcern.SAFE); // ensure that the drop() has happened
competitorCollection.drop();
}
@Test
public void testStoreAndUpdateCompetitor() throws URISyntaxException {
URI flagImageURI1 = new URI("http://www.sapsailing/flagimage1.jpg");
URI flagImageURI2 = new URI("http://www.sapsailing/flagimage2.jpg");
String competitorName1 = "Hasso";
String competitorName2 = "Hasso Plattner";
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor(competitorName1);
c.setFlagImage(flagImageURI1);
mongoObjectFactory.storeCompetitor(c);
Collection<Competitor> allCompetitors = domainObjectFactory.loadAllCompetitors();
assertEquals(1, Util.size(allCompetitors));
DynamicCompetitor loadedCompetitor = (DynamicCompetitor) allCompetitors.iterator().next();
assertEquals(flagImageURI1, loadedCompetitor.getFlagImage());
assertEquals(competitorName1, loadedCompetitor.getName());
loadedCompetitor.setName(competitorName2);
loadedCompetitor.setFlagImage(flagImageURI2);
mongoObjectFactory.storeCompetitor(loadedCompetitor);
allCompetitors = domainObjectFactory.loadAllCompetitors();
assertEquals(1, Util.size(allCompetitors));
loadedCompetitor = (DynamicCompetitor) allCompetitors.iterator().next();
assertEquals(flagImageURI2, loadedCompetitor.getFlagImage());
assertEquals(competitorName2, loadedCompetitor.getName());
}
@Test
public void testStoreAndUpdateCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
c.setName("Hasso Plattner");
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
}
@Test
public void testStoreAndRemoveCompetitor() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso");
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
mongoObjectFactory.removeCompetitor(c);
assertEquals(0, Util.size(domainObjectFactory.loadAllCompetitors()));
}
@Test
public void testStoreAndRemoveCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
mongoObjectFactory.removeCompetitor(c);
assertEquals(0, Util.size(domainObjectFactory.loadAllCompetitors()));
}
}
package com.sap.sailing.mongodb.test;
import static org.junit.Assert.assertEquals;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.impl.CollectionNames;
import com.sap.sailing.domain.test.AbstractLeaderboardTest;
import com.sap.sse.common.Util;
public class StoreCompetitorTest extends AbstractMongoDBTest {
private DomainFactory domainFactory;
public StoreCompetitorTest() throws UnknownHostException, MongoException {
super();
}
@Before
public void setUp() {
// clear the domainFactory competitor store for a clean start:
domainFactory = new DomainFactoryImpl((srlid)->null);
}
private void dropCompetitorCollection() {
DB db = getMongoService().getDB();
DBCollection competitorCollection = db.getCollection(CollectionNames.COMPETITORS.name());
competitorCollection.setWriteConcern(WriteConcern.SAFE); // ensure that the drop() has happened
competitorCollection.drop();
}
@Test
public void testStoreAndUpdateCompetitor() throws URISyntaxException {
URI flagImageURI1 = new URI("http://www.sapsailing/flagimage1.jpg");
URI flagImageURI2 = new URI("http://www.sapsailing/flagimage2.jpg");
String competitorName1 = "Hasso";
String competitorName2 = "Hasso Plattner";
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor(competitorName1);
c.setFlagImage(flagImageURI1);
mongoObjectFactory.storeCompetitor(c);
Collection<Competitor> allCompetitors = domainObjectFactory.loadAllCompetitors();
assertEquals(1, Util.size(allCompetitors));
DynamicCompetitor loadedCompetitor = (DynamicCompetitor) allCompetitors.iterator().next();
assertEquals(flagImageURI1, loadedCompetitor.getFlagImage());
assertEquals(competitorName1, loadedCompetitor.getName());
loadedCompetitor.setName(competitorName2);
loadedCompetitor.setFlagImage(flagImageURI2);
mongoObjectFactory.storeCompetitor(loadedCompetitor);
allCompetitors = domainObjectFactory.loadAllCompetitors();
assertEquals(1, Util.size(allCompetitors));
loadedCompetitor = (DynamicCompetitor) allCompetitors.iterator().next();
assertEquals(flagImageURI2, loadedCompetitor.getFlagImage());
assertEquals(competitorName2, loadedCompetitor.getName());
}
@Test
public void testStoreAndUpdateCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
c.setName("Hasso Plattner");
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
}
@Test
public void testStoreAndRemoveCompetitor() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso");
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
mongoObjectFactory.removeCompetitor(c);
assertEquals(0, Util.size(domainObjectFactory.loadAllCompetitors()));
}
@Test
public void testStoreAndRemoveCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
mongoObjectFactory.storeCompetitor(c);
assertEquals(1, Util.size(domainObjectFactory.loadAllCompetitors()));
mongoObjectFactory.removeCompetitor(c);
assertEquals(0, Util.size(domainObjectFactory.loadAllCompetitors()));
}
}
@@ -60,7 +60,7 @@ public class StoreGPSFixTrackTest extends AbstractMongoDBTest {
TypeBasedServiceFinderFactory factory = new MockSmartphoneImeiServiceFinderFactory();
AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService(), factory);
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE, factory);
@@ -820,7 +820,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new);
List<Competitor> competitors = new ArrayList<Competitor>();
competitors.add(new CompetitorImpl("Axel", "Axel Uhl", Color.RED, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null));
competitors.add(new CompetitorImpl("Axel", "Axel Uhl", Color.RED, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null));
Iterable<Waypoint> waypoints = Collections.emptyList();
Course course = new CourseImpl("Course", waypoints);
@@ -116,12 +116,12 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
Competitor wolfgang = new CompetitorImpl(123, "$$$Dr. Wolfgang+Hunger$$$", Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Competitor hasso = new CompetitorImpl(234, "Hasso Plattner", Color.RED, null, null,
new TeamImpl("STG", Collections.singleton(
new PersonImpl("Hasso Plattner", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Hasso Plattner")), new PersonImpl("Lutz Patrunky", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
final String raceColumnName1 = "My First Race 1";
MockedTrackedRaceWithFixedRankAndManyCompetitors raceWithTwoCompetitors = new MockedTrackedRaceWithFixedRankAndManyCompetitors(wolfgang, /* rank */ 1, /* started */ true);
raceWithTwoCompetitors.addCompetitor(hasso);
@@ -172,12 +172,12 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
Competitor wolfgang = new CompetitorImpl(123, "$$$Dr. Wolfgang+Hunger$$$", Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Competitor hasso = new CompetitorImpl(234, "Hasso Plattner", Color.RED, null, null,
new TeamImpl("STG", Collections.singleton(
new PersonImpl("Hasso Plattner", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Hasso Plattner")), new PersonImpl("Lutz Patrunky", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
final String raceColumnName1 = "My First Race 1";
MockedTrackedRaceWithFixedRankAndManyCompetitors raceWithTwoCompetitors = new MockedTrackedRaceWithFixedRankAndManyCompetitors(wolfgang, /* rank */ 1, /* started */ true);
raceWithTwoCompetitors.addCompetitor(hasso);
@@ -228,12 +228,12 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
Competitor wolfgang = new CompetitorImpl(123, "$$$Dr. Wolfgang+Hunger$$$", Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Competitor hasso = new CompetitorImpl(234, "Hasso Plattner", Color.RED, null,null,
new TeamImpl("STG", Collections.singleton(
new PersonImpl("Hasso Plattner", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Hasso Plattner")), new PersonImpl("Lutz Patrunky", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
final String raceColumnName1 = "My First Race 1";
MockedTrackedRaceWithFixedRankAndManyCompetitors raceWithTwoCompetitors = new MockedTrackedRaceWithFixedRankAndManyCompetitors(wolfgang, /* rank */ 1, /* started */ true);
raceWithTwoCompetitors.addCompetitor(hasso);
@@ -81,7 +81,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
new TeamImpl("STG", Collections.singleton(
new PersonImpl("Hasso Plattner", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Hasso Plattner")), new PersonImpl("Lutz Patrunky", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Patty, the coach")), new BoatImpl("Dr. Hasso Plattner's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
final String raceColumnName1 = "My First Race 1";
MockedTrackedRaceWithFixedRankAndManyCompetitors raceWithTwoCompetitors = new MockedTrackedRaceWithFixedRankAndManyCompetitors(wolfgang, /* rank */ 1, /* started */ true);
raceWithTwoCompetitors.addCompetitor(hasso);
@@ -355,7 +355,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
leaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace */ false);
@@ -382,7 +382,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
Competitor competitor = new CompetitorImpl(123, "$$$Dr. Wolfgang+Hunger$$$", Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* dateOfBirth */ null, "This is Rigo, the coach")), new BoatImpl("Dr. Wolfgang Hunger's boat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
return competitor;
}
@@ -298,7 +298,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogFinishPositioningConfirmedEvent() {
Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team",
Color.RED, "someone@nowhere.de", null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
CompetitorResults storedPositioningList = new CompetitorResultsImpl();
storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */
1, MaxPointsReason.NONE, /* score */ null, /* finishingTimePoint */null, /* comment */null));
@@ -322,7 +322,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogFinishPositioningConfirmedEventWithContents() {
Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team",
Color.RED, "someone@nowhere.de", null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
CompetitorResults storedPositioningList = new CompetitorResultsImpl();
final TimePoint finishingTimePoint = MillisecondsTimePoint.now();
final String comment = "This is a comment";
@@ -392,7 +392,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
@Test
public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogFinishPositioningListChangeEvent() {
Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED,
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
CompetitorResults storedPositioningList = new CompetitorResultsImpl();
storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */
1, MaxPointsReason.NONE, /* score */ null, /* finishingTimePoint */null, /* comment */null));
@@ -200,7 +200,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin
@Test
public void testStoreAndRetrieveRegattaWithRaceLogFinishPositioningListChangeEvent() {
Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED,
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
CompetitorResults storedPositioningList = new CompetitorResultsImpl();
storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ 1, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null));
RaceLogFinishPositioningListChangedEvent event = new RaceLogFinishPositioningListChangedEventImpl(now, author, 0, storedPositioningList);
@@ -224,7 +224,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin
@Test
public void testStoreAndRetrieveRegattaWithRaceLogFinishPositioningConfirmedEvent() {
Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED,
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
"someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
CompetitorResults storedPositioningList = new CompetitorResultsImpl();
storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ 1, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null));
RaceLogFinishPositioningConfirmedEvent event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, storedPositioningList);
@@ -92,6 +92,9 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
}, /* trackedRegattaRegistry */ null, mock(RaceLogResolver.class),
/*courseDesignUpdateURI*/ null, /*tracTracUsername*/ null, /*tracTracPassword*/ null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE);
addListenersForStoredDataAndStartController(typeControllers);
for (final Receiver receiver : typeControllers) {
addReceiverToStopDuringTearDown(receiver);
}
RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaces().iterator().next().getId());
DynamicTrackedRace trackedRace = trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 10000, new DynamicRaceDefinitionSet() {
@@ -31,7 +31,6 @@ public class MarkDeserializer implements JsonDeserializer<Mark> {
String shape = (String) object.get(MarkJsonSerializer.FIELD_SHAPE);
MarkType type = MarkType.valueOf((String) object.get(MarkJsonSerializer.FIELD_TYPE));
String name = (String) object.get(MarkJsonSerializer.FIELD_NAME);
Mark mark = factory.getOrCreateMark(id, name, type, color, shape, pattern);
return mark;
}
@@ -1,99 +1,100 @@
package com.sap.sailing.server.gateway.deserialization.impl;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.util.UUID;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorFactory;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.common.tracking.impl.CompetitorJsonConstants;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
import com.sap.sse.common.Color;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.RGBColor;
public class CompetitorJsonDeserializer implements JsonDeserializer<Competitor> {
protected final CompetitorFactory competitorStore;
protected final JsonDeserializer<DynamicTeam> teamJsonDeserializer;
protected final JsonDeserializer<DynamicBoat> boatJsonDeserializer;
private static final Logger logger = Logger.getLogger(CompetitorJsonDeserializer.class.getName());
public static CompetitorJsonDeserializer create(SharedDomainFactory baseDomainFactory) {
return new CompetitorJsonDeserializer(baseDomainFactory, new TeamJsonDeserializer(new PersonJsonDeserializer(
new NationalityJsonDeserializer(baseDomainFactory))), new BoatJsonDeserializer(new BoatClassJsonDeserializer(baseDomainFactory)));
}
public CompetitorJsonDeserializer(CompetitorStore store) {
this(store, null, /* boatDeserializer */ null);
}
public CompetitorJsonDeserializer(CompetitorFactory competitorStore, JsonDeserializer<DynamicTeam> teamJsonDeserializer, JsonDeserializer<DynamicBoat> boatDeserializer) {
this.competitorStore = competitorStore;
this.teamJsonDeserializer = teamJsonDeserializer;
this.boatJsonDeserializer = boatDeserializer;
}
@Override
public Competitor deserialize(JSONObject object) throws JsonDeserializationException {
Serializable competitorId = (Serializable) object.get(CompetitorJsonSerializer.FIELD_ID);
try {
Class<?> idClass = Class.forName((String) object.get(CompetitorJsonConstants.FIELD_ID_TYPE));
if (Number.class.isAssignableFrom(idClass)) {
Constructor<?> constructorFromString = idClass.getConstructor(String.class);
competitorId = (Serializable) constructorFromString.newInstance(competitorId.toString());
} else if (UUID.class.isAssignableFrom(idClass)) {
competitorId = Helpers.tryUuidConversion(competitorId);
}
String name = (String) object.get(CompetitorJsonConstants.FIELD_NAME);
String displayColorAsString = (String) object.get(CompetitorJsonConstants.FIELD_DISPLAY_COLOR);
String email = (String) object.get(CompetitorJsonConstants.FIELD_EMAIL);
URI flagImageURI = null;
String flagImageURIAsString = (String) object.get(CompetitorJsonConstants.FIELD_FLAG_IMAGE_URI);
if (flagImageURIAsString != null) {
try {
flagImageURI = URI.create(flagImageURIAsString);
} catch (IllegalArgumentException e) {
logger.warning("Illegal flag image URI " + e.getMessage());
}
}
final Color displayColor;
if (displayColorAsString == null || displayColorAsString.isEmpty()) {
displayColor = null;
} else {
displayColor = new RGBColor(displayColorAsString);
}
DynamicTeam team = null;
DynamicBoat boat = null;
if (teamJsonDeserializer != null && object.get(CompetitorJsonConstants.FIELD_TEAM) != null) {
team = teamJsonDeserializer.deserialize(Helpers.getNestedObjectSafe(object,
CompetitorJsonConstants.FIELD_TEAM));
}
if (boatJsonDeserializer != null && object.get(CompetitorJsonConstants.FIELD_BOAT) != null) {
boat = boatJsonDeserializer.deserialize(Helpers.getNestedObjectSafe(object,
CompetitorJsonConstants.FIELD_BOAT));
}
final Double timeOnTimeFactor = (Double) object.get(CompetitorJsonConstants.FIELD_TIME_ON_TIME_FACTOR);
final Double timeOnDistanceAllowanceInSecondsPerNauticalMile = (Double) object
.get(CompetitorJsonConstants.FIELD_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE);
Competitor competitor = competitorStore.getOrCreateCompetitor(competitorId, name, displayColor, email,
flagImageURI, team, boat, timeOnTimeFactor,
timeOnDistanceAllowanceInSecondsPerNauticalMile == null ? null :
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile*1000)));
return competitor;
} catch (Exception e) {
throw new JsonDeserializationException(e);
}
}
}
package com.sap.sailing.server.gateway.deserialization.impl;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.util.UUID;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorFactory;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.common.tracking.impl.CompetitorJsonConstants;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
import com.sap.sse.common.Color;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.RGBColor;
public class CompetitorJsonDeserializer implements JsonDeserializer<Competitor> {
protected final CompetitorFactory competitorStore;
protected final JsonDeserializer<DynamicTeam> teamJsonDeserializer;
protected final JsonDeserializer<DynamicBoat> boatJsonDeserializer;
private static final Logger logger = Logger.getLogger(CompetitorJsonDeserializer.class.getName());
public static CompetitorJsonDeserializer create(SharedDomainFactory baseDomainFactory) {
return new CompetitorJsonDeserializer(baseDomainFactory, new TeamJsonDeserializer(new PersonJsonDeserializer(
new NationalityJsonDeserializer(baseDomainFactory))), new BoatJsonDeserializer(new BoatClassJsonDeserializer(baseDomainFactory)));
}
public CompetitorJsonDeserializer(CompetitorStore store) {
this(store, null, /* boatDeserializer */ null);
}
public CompetitorJsonDeserializer(CompetitorFactory competitorStore, JsonDeserializer<DynamicTeam> teamJsonDeserializer, JsonDeserializer<DynamicBoat> boatDeserializer) {
this.competitorStore = competitorStore;
this.teamJsonDeserializer = teamJsonDeserializer;
this.boatJsonDeserializer = boatDeserializer;
}
@Override
public Competitor deserialize(JSONObject object) throws JsonDeserializationException {
Serializable competitorId = (Serializable) object.get(CompetitorJsonSerializer.FIELD_ID);
try {
Class<?> idClass = Class.forName((String) object.get(CompetitorJsonConstants.FIELD_ID_TYPE));
if (Number.class.isAssignableFrom(idClass)) {
Constructor<?> constructorFromString = idClass.getConstructor(String.class);
competitorId = (Serializable) constructorFromString.newInstance(competitorId.toString());
} else if (UUID.class.isAssignableFrom(idClass)) {
competitorId = Helpers.tryUuidConversion(competitorId);
}
String name = (String) object.get(CompetitorJsonConstants.FIELD_NAME);
String displayColorAsString = (String) object.get(CompetitorJsonConstants.FIELD_DISPLAY_COLOR);
String email = (String) object.get(CompetitorJsonConstants.FIELD_EMAIL);
String searchTag = (String) object.get(CompetitorJsonConstants.FIELD_SEARCHTAG);
URI flagImageURI = null;
String flagImageURIAsString = (String) object.get(CompetitorJsonConstants.FIELD_FLAG_IMAGE_URI);
if (flagImageURIAsString != null) {
try {
flagImageURI = URI.create(flagImageURIAsString);
} catch (IllegalArgumentException e) {
logger.warning("Illegal flag image URI " + e.getMessage());
}
}
final Color displayColor;
if (displayColorAsString == null || displayColorAsString.isEmpty()) {
displayColor = null;
} else {
displayColor = new RGBColor(displayColorAsString);
}
DynamicTeam team = null;
DynamicBoat boat = null;
if (teamJsonDeserializer != null && object.get(CompetitorJsonConstants.FIELD_TEAM) != null) {
team = teamJsonDeserializer.deserialize(Helpers.getNestedObjectSafe(object,
CompetitorJsonConstants.FIELD_TEAM));
}
if (boatJsonDeserializer != null && object.get(CompetitorJsonConstants.FIELD_BOAT) != null) {
boat = boatJsonDeserializer.deserialize(Helpers.getNestedObjectSafe(object,
CompetitorJsonConstants.FIELD_BOAT));
}
final Double timeOnTimeFactor = (Double) object.get(CompetitorJsonConstants.FIELD_TIME_ON_TIME_FACTOR);
final Double timeOnDistanceAllowanceInSecondsPerNauticalMile = (Double) object
.get(CompetitorJsonConstants.FIELD_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE);
Competitor competitor = competitorStore.getOrCreateCompetitor(competitorId, name, displayColor, email,
flagImageURI, team, boat, timeOnTimeFactor,
timeOnDistanceAllowanceInSecondsPerNauticalMile == null ? null :
new MillisecondsDurationImpl((long) (timeOnDistanceAllowanceInSecondsPerNauticalMile*1000)), searchTag);
return competitor;
} catch (Exception e) {
throw new JsonDeserializationException(e);
}
}
}
@@ -63,6 +63,11 @@ public class Helpers {
return result;
}
/**
* If the {@link Object#toString() string representation} of {@code serializableId} {@link UUID#fromString(String) parses}
* as a {@link UUID}, the resulting {@link UUID} is returned. Otherwise, the {@code serializableId} parameter's value
* is returned unchanged.
*/
public static Serializable tryUuidConversion(Serializable serializableId) {
try {
return UUID.fromString(serializableId.toString());
@@ -55,6 +55,7 @@ public class CompetitorJsonSerializer implements JsonSerializer<Competitor> {
result.put(CompetitorJsonConstants.FIELD_NAME, competitor.getName());
result.put(CompetitorJsonConstants.FIELD_DISPLAY_COLOR, competitor.getColor() == null ? null : competitor.getColor().getAsHtml());
result.put(CompetitorJsonConstants.FIELD_EMAIL, competitor.getEmail());
result.put(CompetitorJsonConstants.FIELD_SEARCHTAG, competitor.getSearchTag());
result.put(CompetitorJsonConstants.FIELD_SAIL_ID, competitor.getBoat() == null ? "" : competitor.getBoat().getSailID());
final Nationality nationality = competitor.getTeam() == null ? null : competitor.getTeam().getNationality();
result.put(CompetitorJsonConstants.FIELD_NATIONALITY, nationality == null ? "" : nationality.getThreeLetterIOCAcronym());
@@ -1,248 +1,248 @@
package com.sap.sailing.server.gateway.serialization.test.racelog;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseAreaChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningListChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPathfinderEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogWindFixEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEventSerializer;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RaceLogEventSerializerTest {
private RaceLogEventSerializer serializer;
private JsonSerializer<RaceLogEvent> flagEventSerializer;
private JsonSerializer<RaceLogEvent> startTimeSerializer;
private JsonSerializer<RaceLogEvent> raceStatusSerializer;
private JsonSerializer<RaceLogEvent> courseAreaChangedEventSerializer;
private JsonSerializer<RaceLogEvent> passChangedSerializer;
private JsonSerializer<RaceLogEvent> courseDesignChangedEventSerializer;
private JsonSerializer<RaceLogEvent> finishPositioningListChangedEventSerializer;
private JsonSerializer<RaceLogEvent> finishPositioningConfirmedEventSerializer;
private JsonSerializer<RaceLogEvent> pathfinderEventSerializer;
private JsonSerializer<RaceLogEvent> gateLineOpeningTimeEventSerializer;
private JsonSerializer<RaceLogEvent> startProcedureTypeChangedEventSerializer;
private JsonSerializer<RaceLogEvent> protestStartTimeEventSerializer;
private JsonSerializer<RaceLogEvent> windFixEventSerializer;
private JsonSerializer<RaceLogEvent> denoteForTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> startTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> revokeEventSerializer;
private JsonSerializer<RaceLogEvent> registerCompetitorEventSerializer;
private JsonSerializer<RaceLogEvent> additionalScoringInformationSerializer;
private JsonSerializer<RaceLogEvent> fixedMarkPassingEventSerializer;
private JsonSerializer<RaceLogEvent> suppressedMarkPassingsSerializer;
private JsonSerializer<RaceLogEvent> dependentStartTimeEventSerializer;
private JsonSerializer<RaceLogEvent> startOfTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> useCompetitorsFromRaceLogEventSerializer;
private JsonSerializer<RaceLogEvent> endOfTrackingEventSerializer;
private AbstractLogEventAuthor author = new LogEventAuthorImpl("Test Author", 1);
@SuppressWarnings("unchecked")
@Before
public void setUp() {
flagEventSerializer = mock(JsonSerializer.class);
startTimeSerializer = mock(JsonSerializer.class);
raceStatusSerializer = mock(JsonSerializer.class);
courseAreaChangedEventSerializer = mock(JsonSerializer.class);
passChangedSerializer = mock(JsonSerializer.class);
courseDesignChangedEventSerializer = mock(JsonSerializer.class);
finishPositioningListChangedEventSerializer = mock(JsonSerializer.class);
finishPositioningConfirmedEventSerializer = mock(JsonSerializer.class);
pathfinderEventSerializer = mock(JsonSerializer.class);
gateLineOpeningTimeEventSerializer = mock(JsonSerializer.class);
startProcedureTypeChangedEventSerializer = mock(JsonSerializer.class);
protestStartTimeEventSerializer = mock(JsonSerializer.class);
windFixEventSerializer = mock(JsonSerializer.class);
denoteForTrackingEventSerializer = mock(JsonSerializer.class);
startTrackingEventSerializer = mock(JsonSerializer.class);
revokeEventSerializer = mock(JsonSerializer.class);
registerCompetitorEventSerializer = mock(JsonSerializer.class);
additionalScoringInformationSerializer = mock(JsonSerializer.class);
fixedMarkPassingEventSerializer = mock(JsonSerializer.class);
suppressedMarkPassingsSerializer = mock(JsonSerializer.class);
dependentStartTimeEventSerializer = mock(JsonSerializer.class);
startOfTrackingEventSerializer = mock(JsonSerializer.class);
useCompetitorsFromRaceLogEventSerializer = mock(JsonSerializer.class);
endOfTrackingEventSerializer = mock(JsonSerializer.class);
serializer = new RaceLogEventSerializer(flagEventSerializer, startTimeSerializer, raceStatusSerializer,
courseAreaChangedEventSerializer, passChangedSerializer, courseDesignChangedEventSerializer,
finishPositioningListChangedEventSerializer, finishPositioningConfirmedEventSerializer,
pathfinderEventSerializer, gateLineOpeningTimeEventSerializer,
startProcedureTypeChangedEventSerializer, protestStartTimeEventSerializer, windFixEventSerializer,
denoteForTrackingEventSerializer, startTrackingEventSerializer, revokeEventSerializer,
registerCompetitorEventSerializer, fixedMarkPassingEventSerializer, suppressedMarkPassingsSerializer,
additionalScoringInformationSerializer, dependentStartTimeEventSerializer,
startOfTrackingEventSerializer, useCompetitorsFromRaceLogEventSerializer,
endOfTrackingEventSerializer);
}
@Test
public void testChoosesFlagEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFlagEventImpl(null, author, 0, null, null, false);
serializer.serialize(event);
verify(flagEventSerializer).serialize(event);
}
@Test
public void testChoosesStartTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartTimeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(startTimeSerializer).serialize(event);
}
@Test
public void testChoosesRaceStatusSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRaceStatusEventImpl(null, author, 0, RaceLogRaceStatus.SCHEDULED);
serializer.serialize(event);
verify(raceStatusSerializer).serialize(event);
}
@Test
public void testChoosesCourseAreaChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogCourseAreaChangeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(courseAreaChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesPassChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogPassChangeEventImpl(null, author, 0);
serializer.serialize(event);
verify(passChangedSerializer).serialize(event);
}
@Test
public void testChoosesCourseDesignChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(courseDesignChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesFinishPositioningListChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFinishPositioningListChangedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(finishPositioningListChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesFinishPositioningConfirmedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFinishPositioningConfirmedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(finishPositioningConfirmedEventSerializer).serialize(event);
}
@Test
public void testChoosesPathfinderSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogPathfinderEventImpl(null, author, 0, "GER 20");
serializer.serialize(event);
verify(pathfinderEventSerializer).serialize(event);
}
@Test
public void testChoosesGateLineOpeningTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogGateLineOpeningTimeEventImpl(null, author, 0, 2l, 1l);
serializer.serialize(event);
verify(gateLineOpeningTimeEventSerializer).serialize(event);
}
@Test
public void testStartProcedureTypeChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartProcedureChangedEventImpl(null, author, 0, RacingProcedureType.ESS);
serializer.serialize(event);
verify(startProcedureTypeChangedEventSerializer).serialize(event);
}
@Test
public void testProtestStartTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogProtestStartTimeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(protestStartTimeEventSerializer).serialize(event);
}
@Test
public void testWindFixSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogWindFixEventImpl(null, author, 0, null, /* isMagnetic */ false);
serializer.serialize(event);
verify(windFixEventSerializer).serialize(event);
}
@Test
public void testDenoteForTrackingSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogDenoteForTrackingEventImpl(null, author, 0, "", null, null);
serializer.serialize(event);
verify(denoteForTrackingEventSerializer).serialize(event);
}
@Test
public void testCreateRaceSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartTrackingEventImpl(null, author, 0);
serializer.serialize(event);
verify(startTrackingEventSerializer).serialize(event);
}
@Test
public void testRevokeEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRevokeEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(),
author, 0, 0, UUID.randomUUID(), "type", "short info", "reason");
serializer.serialize(event);
verify(revokeEventSerializer).serialize(event);
}
@Test
public void testRegisterCompetitorEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRegisterCompetitorEventImpl(null, author, 0,
DomainFactory.INSTANCE
.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */null, /* timeOnDistanceAllowancePerNauticalMile */
null));
serializer.serialize(event);
verify(registerCompetitorEventSerializer).serialize(event);
}
}
package com.sap.sailing.server.gateway.serialization.test.racelog;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseAreaChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningListChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPathfinderEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogWindFixEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEventSerializer;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RaceLogEventSerializerTest {
private RaceLogEventSerializer serializer;
private JsonSerializer<RaceLogEvent> flagEventSerializer;
private JsonSerializer<RaceLogEvent> startTimeSerializer;
private JsonSerializer<RaceLogEvent> raceStatusSerializer;
private JsonSerializer<RaceLogEvent> courseAreaChangedEventSerializer;
private JsonSerializer<RaceLogEvent> passChangedSerializer;
private JsonSerializer<RaceLogEvent> courseDesignChangedEventSerializer;
private JsonSerializer<RaceLogEvent> finishPositioningListChangedEventSerializer;
private JsonSerializer<RaceLogEvent> finishPositioningConfirmedEventSerializer;
private JsonSerializer<RaceLogEvent> pathfinderEventSerializer;
private JsonSerializer<RaceLogEvent> gateLineOpeningTimeEventSerializer;
private JsonSerializer<RaceLogEvent> startProcedureTypeChangedEventSerializer;
private JsonSerializer<RaceLogEvent> protestStartTimeEventSerializer;
private JsonSerializer<RaceLogEvent> windFixEventSerializer;
private JsonSerializer<RaceLogEvent> denoteForTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> startTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> revokeEventSerializer;
private JsonSerializer<RaceLogEvent> registerCompetitorEventSerializer;
private JsonSerializer<RaceLogEvent> additionalScoringInformationSerializer;
private JsonSerializer<RaceLogEvent> fixedMarkPassingEventSerializer;
private JsonSerializer<RaceLogEvent> suppressedMarkPassingsSerializer;
private JsonSerializer<RaceLogEvent> dependentStartTimeEventSerializer;
private JsonSerializer<RaceLogEvent> startOfTrackingEventSerializer;
private JsonSerializer<RaceLogEvent> useCompetitorsFromRaceLogEventSerializer;
private JsonSerializer<RaceLogEvent> endOfTrackingEventSerializer;
private AbstractLogEventAuthor author = new LogEventAuthorImpl("Test Author", 1);
@SuppressWarnings("unchecked")
@Before
public void setUp() {
flagEventSerializer = mock(JsonSerializer.class);
startTimeSerializer = mock(JsonSerializer.class);
raceStatusSerializer = mock(JsonSerializer.class);
courseAreaChangedEventSerializer = mock(JsonSerializer.class);
passChangedSerializer = mock(JsonSerializer.class);
courseDesignChangedEventSerializer = mock(JsonSerializer.class);
finishPositioningListChangedEventSerializer = mock(JsonSerializer.class);
finishPositioningConfirmedEventSerializer = mock(JsonSerializer.class);
pathfinderEventSerializer = mock(JsonSerializer.class);
gateLineOpeningTimeEventSerializer = mock(JsonSerializer.class);
startProcedureTypeChangedEventSerializer = mock(JsonSerializer.class);
protestStartTimeEventSerializer = mock(JsonSerializer.class);
windFixEventSerializer = mock(JsonSerializer.class);
denoteForTrackingEventSerializer = mock(JsonSerializer.class);
startTrackingEventSerializer = mock(JsonSerializer.class);
revokeEventSerializer = mock(JsonSerializer.class);
registerCompetitorEventSerializer = mock(JsonSerializer.class);
additionalScoringInformationSerializer = mock(JsonSerializer.class);
fixedMarkPassingEventSerializer = mock(JsonSerializer.class);
suppressedMarkPassingsSerializer = mock(JsonSerializer.class);
dependentStartTimeEventSerializer = mock(JsonSerializer.class);
startOfTrackingEventSerializer = mock(JsonSerializer.class);
useCompetitorsFromRaceLogEventSerializer = mock(JsonSerializer.class);
endOfTrackingEventSerializer = mock(JsonSerializer.class);
serializer = new RaceLogEventSerializer(flagEventSerializer, startTimeSerializer, raceStatusSerializer,
courseAreaChangedEventSerializer, passChangedSerializer, courseDesignChangedEventSerializer,
finishPositioningListChangedEventSerializer, finishPositioningConfirmedEventSerializer,
pathfinderEventSerializer, gateLineOpeningTimeEventSerializer,
startProcedureTypeChangedEventSerializer, protestStartTimeEventSerializer, windFixEventSerializer,
denoteForTrackingEventSerializer, startTrackingEventSerializer, revokeEventSerializer,
registerCompetitorEventSerializer, fixedMarkPassingEventSerializer, suppressedMarkPassingsSerializer,
additionalScoringInformationSerializer, dependentStartTimeEventSerializer,
startOfTrackingEventSerializer, useCompetitorsFromRaceLogEventSerializer,
endOfTrackingEventSerializer);
}
@Test
public void testChoosesFlagEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFlagEventImpl(null, author, 0, null, null, false);
serializer.serialize(event);
verify(flagEventSerializer).serialize(event);
}
@Test
public void testChoosesStartTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartTimeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(startTimeSerializer).serialize(event);
}
@Test
public void testChoosesRaceStatusSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRaceStatusEventImpl(null, author, 0, RaceLogRaceStatus.SCHEDULED);
serializer.serialize(event);
verify(raceStatusSerializer).serialize(event);
}
@Test
public void testChoosesCourseAreaChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogCourseAreaChangeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(courseAreaChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesPassChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogPassChangeEventImpl(null, author, 0);
serializer.serialize(event);
verify(passChangedSerializer).serialize(event);
}
@Test
public void testChoosesCourseDesignChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(courseDesignChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesFinishPositioningListChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFinishPositioningListChangedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(finishPositioningListChangedEventSerializer).serialize(event);
}
@Test
public void testChoosesFinishPositioningConfirmedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogFinishPositioningConfirmedEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(finishPositioningConfirmedEventSerializer).serialize(event);
}
@Test
public void testChoosesPathfinderSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogPathfinderEventImpl(null, author, 0, "GER 20");
serializer.serialize(event);
verify(pathfinderEventSerializer).serialize(event);
}
@Test
public void testChoosesGateLineOpeningTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogGateLineOpeningTimeEventImpl(null, author, 0, 2l, 1l);
serializer.serialize(event);
verify(gateLineOpeningTimeEventSerializer).serialize(event);
}
@Test
public void testStartProcedureTypeChangedSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartProcedureChangedEventImpl(null, author, 0, RacingProcedureType.ESS);
serializer.serialize(event);
verify(startProcedureTypeChangedEventSerializer).serialize(event);
}
@Test
public void testProtestStartTimeSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogProtestStartTimeEventImpl(null, author, 0, null);
serializer.serialize(event);
verify(protestStartTimeEventSerializer).serialize(event);
}
@Test
public void testWindFixSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogWindFixEventImpl(null, author, 0, null, /* isMagnetic */ false);
serializer.serialize(event);
verify(windFixEventSerializer).serialize(event);
}
@Test
public void testDenoteForTrackingSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogDenoteForTrackingEventImpl(null, author, 0, "", null, null);
serializer.serialize(event);
verify(denoteForTrackingEventSerializer).serialize(event);
}
@Test
public void testCreateRaceSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogStartTrackingEventImpl(null, author, 0);
serializer.serialize(event);
verify(startTrackingEventSerializer).serialize(event);
}
@Test
public void testRevokeEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRevokeEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(),
author, 0, 0, UUID.randomUUID(), "type", "short info", "reason");
serializer.serialize(event);
verify(revokeEventSerializer).serialize(event);
}
@Test
public void testRegisterCompetitorEventSerializer() {
// we use the real event type here because we do not want to re-implement the dispatching.
RaceLogEvent event = new RaceLogRegisterCompetitorEventImpl(null, author, 0,
DomainFactory.INSTANCE
.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */null, /* timeOnDistanceAllowancePerNauticalMile */
null, null));
serializer.serialize(event);
verify(registerCompetitorEventSerializer).serialize(event);
}
}
@@ -1,102 +1,102 @@
package com.sap.sailing.server.gateway.test;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.mongodb.MongoDBConfiguration;
import com.sap.sse.mongodb.MongoDBService;
public abstract class AbstractJsonExportTest {
protected RacingEventService racingEventService;
protected MongoDBService service;
protected static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
public void setUp() {
service = MongoDBConfiguration.getDefaultTestConfiguration().getService();
service.getDB().dropDatabase();
racingEventService = new RacingEventServiceImpl();
}
protected String callJsonHttpServlet(AbstractJsonHttpServlet jsonServlet, String GetOrPostMethod, Map<String, String> parameters) throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getMethod()).thenReturn(GetOrPostMethod);
if(parameters != null) {
for(Map.Entry<String, String> entry: parameters.entrySet()) {
when(request.getParameter(entry.getKey())).thenReturn(entry.getValue());
}
}
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
when(response.getWriter()).thenReturn(writer);
AbstractJsonHttpServlet spyJsonExportServlet = spy(jsonServlet);
doReturn(racingEventService).when(spyJsonExportServlet).getService();
spyJsonExportServlet.service(request, response);
// the writer may not have been flushed yet...
writer.flush();
return stringWriter.toString();
}
protected TimePoint parseTimepointFromJsonString(String timePointAsJsonString) throws ParseException {
TimePoint result = null;
if(timePointAsJsonString != null && !timePointAsJsonString.isEmpty()) {
Date date = TIMEPOINT_FORMATTER.parse(timePointAsJsonString);
result = new MillisecondsTimePoint(date);
}
return result;
}
protected List<Competitor> createCompetitors(int numberOfCompetitorsToCreate) {
List<Competitor> result = new ArrayList<Competitor>();
BoatClass boatClass = new BoatClassImpl("505", /* typicallyStartsUpwind */ true);
for (int i = 1; i <= numberOfCompetitorsToCreate; i++) {
String competitorName = "C" + i;
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), competitorName, Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
boatClass, null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
result.add(competitor);
}
return result;
}
}
package com.sap.sailing.server.gateway.test;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.mongodb.MongoDBConfiguration;
import com.sap.sse.mongodb.MongoDBService;
public abstract class AbstractJsonExportTest {
protected RacingEventService racingEventService;
protected MongoDBService service;
protected static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
public void setUp() {
service = MongoDBConfiguration.getDefaultTestConfiguration().getService();
service.getDB().dropDatabase();
racingEventService = new RacingEventServiceImpl();
}
protected String callJsonHttpServlet(AbstractJsonHttpServlet jsonServlet, String GetOrPostMethod, Map<String, String> parameters) throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getMethod()).thenReturn(GetOrPostMethod);
if(parameters != null) {
for(Map.Entry<String, String> entry: parameters.entrySet()) {
when(request.getParameter(entry.getKey())).thenReturn(entry.getValue());
}
}
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
when(response.getWriter()).thenReturn(writer);
AbstractJsonHttpServlet spyJsonExportServlet = spy(jsonServlet);
doReturn(racingEventService).when(spyJsonExportServlet).getService();
spyJsonExportServlet.service(request, response);
// the writer may not have been flushed yet...
writer.flush();
return stringWriter.toString();
}
protected TimePoint parseTimepointFromJsonString(String timePointAsJsonString) throws ParseException {
TimePoint result = null;
if(timePointAsJsonString != null && !timePointAsJsonString.isEmpty()) {
Date date = TIMEPOINT_FORMATTER.parse(timePointAsJsonString);
result = new MillisecondsTimePoint(date);
}
return result;
}
protected List<Competitor> createCompetitors(int numberOfCompetitorsToCreate) {
List<Competitor> result = new ArrayList<Competitor>();
BoatClass boatClass = new BoatClassImpl("505", /* typicallyStartsUpwind */ true);
for (int i = 1; i <= numberOfCompetitorsToCreate; i++) {
String competitorName = "C" + i;
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), competitorName, Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
boatClass, null), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
result.add(competitor);
}
return result;
}
}
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff. Show more