> result;
+ if (closestTwsTwa == null) {
+ result = new Pair<>(0.0, null);
+ } else {
+ double minDiffDeg = Math.abs(Math.abs(Math.abs(closestTwsTwa.getObject().getBearing().getDegrees() * 2)
+ - Math.abs(getManeuverAngleDeg())));
+ // TODO ask polar service how likely this is because the polar service knows how narrow or wide the
+ // maneuver angle range is
+ result = new Pair<>(1. / (1. + (minDiffDeg / 10.) * (minDiffDeg / 10.)), closestTwsTwa);
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return format(this, /* id */ null);
+ }
+
+ }
+
+ public String getManeuverClassificationColumnHeaders() {
+ return "datapoint\tcompetitor\ttimePoint\tangleDeg\tboatSpeedKn\tcogDeg\tmiddleManeuverCourse\tlossM";
+ }
+
+ public String getManeuverClassificationColumnTypes() {
+ return "infoitem\tstring\tdate\tfloat\tfloat\tfloat\tfloat\tfloat";
+ }
+
+ public String format(ManeuverClassification mc, String id) {
+ DateFormat df = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
+ final String prefix = mc.getCompetitor().getName() + "\t" + df.format(mc.getTimePoint().asDate()) + "\t" + mc.getManeuverAngleDeg()
+ + "\t" + mc.getSpeedAtManeuverStart().getKnots() + "\t"
+ + mc.getSpeedAtManeuverStart().getBearing().getDegrees();
+ final StringBuilder result = new StringBuilder();
+ if (id != null) {
+ result.append("ID");
+ result.append(id);
+ result.append('\t');
+ }
+ result.append(prefix);
+ result.append("\t");
+ result.append(mc.getMiddleManeuverCourse().getDegrees());
+ result.append("\t");
+ result.append(mc.getManeuverLoss() == null ? 0.0 : mc.getManeuverLoss().getMeters());
+ return result.toString();
+ }
+
+ /**
+ * Fetches all the race's maneuvers and tries to find the tacks and jibes. For each such maneuver identified, a wind
+ * fix will be created based on the average COG into and out of the maneuver.
+ *
+ *
+ * All maneuvers of all competitors between start and end time are considered (usually race start and end for that
+ * competitor, but may be the start of tracking, e.g., in case no course is set, and current time in case no finish
+ * line mark passing is found for that competitor yet). Clustering the candidates by average COG should give two
+ * clusters that are approximately 180deg apart from each other: one with the tacks and one with the jibes. A bunch
+ * of other clusters will emerge for head-up/bear-away maneuvers with small course changes (one for each actual
+ * tack/leg type combination), making them very unlikely candidates for maneuvers that have distinct wide expected
+ * maneuver angles. Two more clusters typically emerge that hold the mark rounding maneuvers that have maneuver
+ * angles similar to that of a typical tack and that would result in estimated wind directions offset by
+ * approximately 90deg from the correct wind direction. Altogether this makes for eight expected clusters, two of
+ * which are the interesting ones, four of which are expected to not contain likely candidates for the wide-angle
+ * maneuvers (head-up/bear-away clusters), and the mark rounding clusters which to each other also tend to have a
+ * 180deg offset.
+ *
+ *
+ * Now for each cluster we check if it's the tack cluster. The tack cluster shows some characteristic features that
+ * make it a little easier to identify: its maneuver angle is in most cases wider than that of the jibes, resulting
+ * in two well-defined maneuver angle clusters (one for port-to-starboard and one for starboard-to-port tacks).
+ * There are usually no other maneuvers with similar middle COG because boats can't sail straight against the wind.
+ *
+ *
+ * We evaluate each cluster's likelihood of being the tack cluster by for each of its maneuvers adding up the
+ * likelihood of that maneuver being a tack, solely based on its maneuver angle, as judged by the polar service. If
+ * a cluster exists that has approximately the opposite average middle COG (the jibe cluster candidate), the
+ * likelihoods for its maneuvers being a jibe are added. (TODO adding is statistically not adequate here; however,
+ * multiplying hundreds if not thousands of probability values would easily lead to a double value going to 0.0
+ * quickly. But is adding adequate to estimate the cluster having the maximum likelihood of being the tack cluster?
+ * We'd only need a monotonous function.) Finally, the resulting likelihood is multiplied by how likely the speed
+ * ratio between the tack and jibe cluster candidates is, based on the polar diagram. For this task, the cluster's
+ * maneuvers' average speed (weighted by each maneuver's likelihood of being a tack) is divided by that of the jibe
+ * cluster's maneuvers' average speed (weighted by each maneuver's likelihood of being a jibe) and assigned a
+ * likelihood by the polar service.
+ *
+ *
+ * The cluster that has the highest likelihood of being the tack cluster is selected. The confidence of the choice
+ * depends on how clearly this cluster was the favorite among all clusters. For each of its maneuvers a wind fix is
+ * generated with a confidence defined by the confidence of having picked the correct cluster as the tack cluster,
+ * multiplied with the likelihood of the maneuver being a tack (as judged by the polar service). Similarly, each
+ * maneuver from the jibe cluster is turned into a wind fix whose confidence results from the likelihood of the
+ * maneuver being a jibe (based on the polar service's judgement) and the general confidence of the correct jibe
+ * cluster having been selected.
+ *
+ *
+ * One benefit of looking primarily for the tacks is that boats cannot sail straight against the wind. Therefore,
+ * there usually are almost no maneuvers that have the same middle COG with a maneuver angle that resembles that of
+ * the other maneuvers in the cluster. This way, the tack cluster will show two cleanly separated clusters along the
+ * maneuver angle dimension that show low variance each, compared to all other clusters.
+ *
+ *
+ * TODO with enough candidates at hand, apply temporal and spatial segmentation to account for heterogeneous wind fields
+ */
+ private Triple>,
+ Cluster,
+ Cluster> analyzeRace(boolean waitForLatest) throws NotEnoughDataHasBeenAddedException {
+ final Map maneuvers = getAllManeuvers(waitForLatest);
+ // cluster into eight clusters by middle COG first, then aggregate tack likelihoods for each, and jibe likelihoods for opposite cluster
+ final int numberOfClusters = 8;
+ KMeansMappingClusterer clusterer =
+ new KMeansMappingClusterer<>(numberOfClusters,
+ getManeuverClassifications(maneuvers),
+ (mc)->new ScalableBearing(mc.getMiddleManeuverCourse()), // maps maneuver classification to cluster metric
+ // use an evenly distributed set of cluster seeds for clustering wind direction estimations
+ IntStream.range(0, numberOfClusters).mapToObj((i)->new DegreeBearingImpl(((double) i)*360./(double) numberOfClusters)));
+ final Set> clusters = clusterer.getClusters();
+ assert maneuvers.size() == clusters.stream().map((c)->c.size()).reduce((s1, s2)->s1+s2).get();
+ final Set, Double>> clustersAndLikelihoodOfBeingTackCluster =
+ clusters.stream().map((c)->new Pair<>(c, getLikelihoodIsTackCluster(c, clusters))).collect(Collectors.toSet());
+ // find most likely tack cluster, based on proximity of maneuver angles in cluster and opposite cluster as well as the speed ratio
+ // between the cluster and its opposite jibe cluster candidate
+ Pair, Double> dominantClusterAndLikelihoodOfBeingTackCluster =
+ clustersAndLikelihoodOfBeingTackCluster.stream().max(
+ (a, b)->(int) Math.signum(a.getB() - b.getB())).get();
+ addWindFixes(dominantClusterAndLikelihoodOfBeingTackCluster.getA(), ManeuverType.TACK);
+ Cluster jibeCluster = getOppositeCluster(dominantClusterAndLikelihoodOfBeingTackCluster.getA(), clusters);
+ if (jibeCluster != null) {
+ addWindFixes(jibeCluster, ManeuverType.JIBE);
+ }
+ return new Triple<>(clusters, dominantClusterAndLikelihoodOfBeingTackCluster.getA(), jibeCluster);
+ }
+
+ private void addWindFixes(
+ Cluster dominantClusterAndLikelihoodOfBeingTackCluster,
+ final ManeuverType maneuverType) {
+ // TODO see bug 1562 comment #8: use WindWithConfidenceImpl internally and implement WindTrack.getAveragedWindWithConfidence
+ for (ManeuverClassification mc : dominantClusterAndLikelihoodOfBeingTackCluster) {
+ final SpeedWithBearingWithConfidence estimatedWindSpeedAndBearing = mc.getEstimatedWindSpeedAndBearing(maneuverType);
+ if (estimatedWindSpeedAndBearing != null) {
+ Wind windFromTack = new WindImpl(mc.getPosition(), mc.getTimePoint(), estimatedWindSpeedAndBearing.getObject());
+ add(windFromTack);
+ }
}
}
+
+ /**
+ * For the tackClusterCandidate add up the likelihoods for each maneuver contained that it is a tack.
+ * If an opposite jibe cluster is found whose centroid middle COG is closer than
+ * {@link #THRESHOLD_OPPOSITE_CLUSTER_DIFFERENCE_DEGREES} degrees to the expected value, its maneuvers are assessed
+ * as jibes and their probabilities are added, making the tackClusterCandidate more likely as there are
+ * more likely jibe candidates in the jibe cluster candidate.
+ *
+ *
+ * If a jibe cluster candidate is found, the resulting number is scaled by the likelihood that the average speed
+ * difference (weighted by the likelihood of being the expected maneuver type) between tack and jibe cluster makes
+ * sense. Otherwise, the value is scaled down by a factor of .25 as a penalty for not having found a jibe cluster.
+ *
+ * @return not a 0..1 likelihood but some scaled value that can grow beyond 1 and represents the sum for all
+ * relevant tackClusterCandidate maneuvers' likelihood that they are a tack, added to the
+ * likelihood sum for an opposite cluster that its maneuvers are jibes, scaled by the probability that the
+ * speed ratio between tack and jibe cluster makes sense (or .25 in case there is no jibe cluster candidate
+ * found within the threshold).
+ */
+ private double getLikelihoodIsTackCluster(Cluster tackClusterCandidate,
+ Set> clusters) {
+ double tackClusterLikelihood = 0;
+ for (ManeuverClassification mc : tackClusterCandidate) {
+ tackClusterLikelihood += mc.getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType.TACK).getA();
+ }
+ // TODO the cluster is more likely a tack cluster if two maneuver angle clusters are found that have small variance (no "into-the-wind" maneuvers other than tacks)
+ Cluster jibeClusterCandidate = getOppositeCluster(tackClusterCandidate, clusters);
+ final double speedMatchFactor;
+ double jibeClusterLikelihood = 0;
+ if (jibeClusterCandidate != null) {
+ for (ManeuverClassification mc : jibeClusterCandidate) {
+ jibeClusterLikelihood += mc.getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType.JIBE).getA();
+ }
+ speedMatchFactor = getLikelihoodTackJibeSpeedRatio(tackClusterCandidate, jibeClusterCandidate);
+ } else {
+ speedMatchFactor = .25; // no jibe cluster found; penalize for not being able to compare average speeds between tacks and jibes
+ }
+ return speedMatchFactor * tackClusterLikelihood * jibeClusterLikelihood;
+ }
- private Map getAllManeuvers() {
- Map maneuvers = new HashMap<>();
+ private Cluster getOppositeCluster(
+ Cluster cluster,
+ Set> clusters) {
+ final Bearing clusterCentroid = cluster.getCentroid();
+ final Bearing opposite = clusterCentroid.reverse();
+ Cluster oppositeClusterCandidate =
+ clusters.stream().min((a, b)->
+ (int) Math.signum(Math.abs(opposite.getDifferenceTo(a.getCentroid()).getDegrees()) -
+ Math.abs(opposite.getDifferenceTo(b.getCentroid()).getDegrees()))).get();
+ final Cluster result;
+ if (Math.abs(opposite.getDifferenceTo(oppositeClusterCandidate.getCentroid()).getDegrees()) < THRESHOLD_OPPOSITE_CLUSTER_DIFFERENCE_DEGREES) {
+ result = oppositeClusterCandidate;
+ } else {
+ result = null;
+ }
+ return result;
+ }
+ /**
+ * By looking at the weighted speeds over ground averages, and based on the {@link #polarService} determines how
+ * likely it is that the tack cluster actually contains tacks and the jibe cluster jibes. This is based on the idea
+ * that if for the most likely wind speeds the jibes have a different (usually significantly higher) entry speed
+ * than the tacks then this difference show show in the cluster elements. If they don't, then this should give a
+ * penalty for the cluster likelihoods.
+ *
+ *
+ * The weight of a maneuver for computing the weighted speed average is determined to be the
+ * {@link ManeuverClassification#getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType) likelihood of the maneuver being
+ * what it is assumed to be}.
+ */
+ private double getLikelihoodTackJibeSpeedRatio(
+ Cluster tackClusterCandidate,
+ Cluster jibeClusterCandidate) {
+ Speed tackClusterWeightedAverageSpeed = getWeightedAverageSpeed(tackClusterCandidate, ManeuverType.TACK);
+ Speed jibeClusterWeightedAverageSpeed = getWeightedAverageSpeed(jibeClusterCandidate, ManeuverType.JIBE);
+ // TODO ask polarService how likely the ratio we found actually is
+ return Math.min(1., 0.5*jibeClusterWeightedAverageSpeed.getKnots()/tackClusterWeightedAverageSpeed.getKnots());
+ }
+
+ private Speed getWeightedAverageSpeed(Cluster cluster, ManeuverType maneuverType) {
+ double weightSum = 0;
+ ScalableSpeed scalableSpeed = new ScalableSpeed(Speed.NULL);
+ for (ManeuverClassification mc : cluster) {
+ final Double weight = mc.getLikelihoodAndTWSBasedOnSpeedAndAngle(maneuverType).getA();
+ weightSum += weight;
+ scalableSpeed = scalableSpeed.add(new ScalableSpeed(mc.getSpeedAtManeuverStart()).multiply(weight));
+ }
+ return scalableSpeed.divide(weightSum);
+ }
+
+ /**
+ * For each maneuver from maneuvers, a {@link ManeuverClassification object} is created.
+ */
+ private Stream getManeuverClassifications(final Map maneuvers) {
+ return maneuvers.entrySet().stream().map((maneuverAndCompetitor)->
+ new ManeuverClassification(maneuverAndCompetitor.getValue(), maneuverAndCompetitor.getKey()));
+ }
+
+ private Map getAllManeuvers(boolean waitForLatest) {
+ Map maneuvers = new HashMap<>();
+ final Waypoint firstWaypoint = trackedRace.getRace().getCourse().getFirstWaypoint();
+ final Waypoint lastWaypoint = trackedRace.getRace().getCourse().getLastWaypoint();
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
- final BoatClass boatClass = competitor.getBoat().getBoatClass();
- final TimePoint from = trackedRace.getStartOfRace() == null ? trackedRace.getStartOfTracking()
- : trackedRace.getStartOfRace();
- final TimePoint to = trackedRace.getEndOfRace() == null ? trackedRace.getEndOfTracking() == null ?
- MillisecondsTimePoint.now() : trackedRace.getEndOfTracking() : trackedRace.getEndOfRace();
- for (Maneuver maneuver : trackedRace.getManeuvers(competitor, from, to, /* waitForLatest */ false)) {
- maneuvers.put(maneuver, boatClass);
+ final TimePoint from = Util.getFirstNonNull(
+ firstWaypoint == null ? null : trackedRace.getMarkPassing(competitor, firstWaypoint) == null ? null : trackedRace.getMarkPassing(competitor, firstWaypoint).getTimePoint(),
+ trackedRace.getStartOfRace(), trackedRace.getStartOfTracking());
+ final TimePoint to = Util.getFirstNonNull(
+ lastWaypoint == null ? null : trackedRace.getMarkPassing(competitor, lastWaypoint) == null ? null : trackedRace.getMarkPassing(competitor, lastWaypoint).getTimePoint(),
+ trackedRace.getEndOfRace(), trackedRace.getEndOfTracking(),
+ MillisecondsTimePoint.now());
+ for (Maneuver maneuver : trackedRace.getManeuvers(competitor, from, to, waitForLatest)) {
+ maneuvers.put(maneuver, competitor);
}
}
return Collections.unmodifiableMap(maneuvers);
}
+
+ public Set> getClusters() {
+ return clusters;
+ }
+
+ public Cluster getTackCluster() {
+ return tackCluster;
+ }
+
+ public Cluster getJibeCluster() {
+ return jibeCluster;
+ }
+
+ public String getStringRepresentation(boolean waitForLatest) {
+ return getStringRepresentation(getClusters().stream(), waitForLatest);
+ }
+
+ public String getStringRepresentation(Stream> clusters, boolean waitForLatest) {
+ StringBuilder stringRepresentation = new StringBuilder();
+ stringRepresentation.delete(0, stringRepresentation.length());
+ stringRepresentation.append(getManeuverClassificationColumnHeaders());
+ stringRepresentation.append('\n');
+ stringRepresentation.append(getManeuverClassificationColumnTypes());
+ stringRepresentation.append('\n');
+ stringRepresentation.append(getManeuverClassificationColumnHeaders());
+ stringRepresentation.append('\n');
+ final int[] id = new int[1];
+ clusters.map((c)->c.stream()).reduce(Stream::concat).get().forEach((i)->{
+ stringRepresentation.append(format(i, ""+id[0]++));
+ stringRepresentation.append('\n');
+ });
+ return stringRepresentation.toString();
+ }
}
diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/ColorDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/ColorDeserializer.java
index b78f68f840a..9a5d79a3b36 100644
--- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/ColorDeserializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/ColorDeserializer.java
@@ -2,10 +2,10 @@ package com.sap.sailing.server.gateway.deserialization.impl;
import org.json.simple.JSONObject;
-import com.sap.sailing.domain.common.Color;
-import com.sap.sailing.domain.common.impl.RGBColor;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
+import com.sap.sse.common.Color;
+import com.sap.sse.common.impl.RGBColor;
public class ColorDeserializer implements JsonDeserializer {
diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/CompetitorJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/CompetitorJsonDeserializer.java
index ada83dcddf7..dcd7490de68 100644
--- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/CompetitorJsonDeserializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/CompetitorJsonDeserializer.java
@@ -12,11 +12,11 @@ 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.Color;
-import com.sap.sailing.domain.common.impl.RGBColor;
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.RGBColor;
public class CompetitorJsonDeserializer implements JsonDeserializer {
protected final CompetitorFactory competitorStore;
diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/FleetDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/FleetDeserializer.java
index fe384773d9a..453e3602118 100755
--- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/FleetDeserializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/FleetDeserializer.java
@@ -4,10 +4,10 @@ import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.impl.FleetImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.FleetJsonSerializer;
+import com.sap.sse.common.Color;
public class FleetDeserializer implements JsonDeserializer {
private JsonDeserializer colorDeserializer;
diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorJsonSerializer.java
index 68c01c8ce15..8a42dcb3b06 100644
--- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorJsonSerializer.java
@@ -10,8 +10,8 @@ import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.Team;
-import com.sap.sailing.domain.common.CountryCode;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
+import com.sap.sse.common.CountryCode;
public class CompetitorJsonSerializer implements JsonSerializer {
public static final String FIELD_ID = "id";
diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/FleetJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/FleetJsonSerializer.java
index a517cfa1e61..14f883e8ca8 100644
--- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/FleetJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/FleetJsonSerializer.java
@@ -3,8 +3,8 @@ package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Fleet;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
+import com.sap.sse.common.Color;
public class FleetJsonSerializer implements JsonSerializer {
public static final String FIELD_NAME = "name";
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ColorJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ColorJsonSerializer.java
index 6202db3c072..34b97dc2bac 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ColorJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ColorJsonSerializer.java
@@ -2,8 +2,8 @@ package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONObject;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
+import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
public class ColorJsonSerializer implements JsonSerializer {
diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/AbstractJsonExportTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/AbstractJsonExportTest.java
index 3622f14ea39..9cbc93bc25a 100644
--- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/AbstractJsonExportTest.java
+++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/AbstractJsonExportTest.java
@@ -27,10 +27,10 @@ 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.domain.common.Color;
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;
diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java
index 9104b802747..308954f2376 100644
--- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java
+++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java
@@ -21,10 +21,10 @@ 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.domain.common.Color;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
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;
diff --git a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF
index 69c688d9d13..efbd733e9ec 100644
--- a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF
@@ -46,7 +46,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.common,
com.sap.sse.replication,
com.sap.sse,
- com.sap.sailing.server.gateway.serialization.shared.android
+ com.sap.sailing.server.gateway.serialization.shared.android,
+ com.sap.sse.shared.android
Bundle-ClassPath: .
Web-ContextPath: /sailingserver
Export-Package: com.sap.sailing.server.gateway,
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/HttpMessageSenderServletRequestHandler.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/HttpMessageSenderServletRequestHandler.java
index ce47d02c8ff..697329316be 100755
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/HttpMessageSenderServletRequestHandler.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/HttpMessageSenderServletRequestHandler.java
@@ -11,9 +11,9 @@ import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.BundleContext;
-import com.sap.sailing.domain.common.Base64Utils;
import com.sap.sailing.domain.common.HttpMessageSenderServletConstants;
import com.sap.sailing.server.RacingEventService;
+import com.sap.sse.common.Base64Utils;
public abstract class HttpMessageSenderServletRequestHandler {
private static final Logger logger = Logger.getLogger(AbstractHttpPostServlet.class.getName());
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java
index 1d0799c9b52..d020065d275 100755
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java
@@ -9,8 +9,8 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.logging.Logger;
import javax.servlet.ServletException;
@@ -36,12 +36,12 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sailing.server.gateway.HttpRequestUtils;
import com.sap.sailing.server.gateway.ParseHttpParameterException;
-import com.sap.sailing.util.SmartFutureCache;
-import com.sap.sailing.util.SmartFutureCache.CacheUpdater;
-import com.sap.sailing.util.SmartFutureCache.UpdateInterval;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
+import com.sap.sse.util.SmartFutureCache;
+import com.sap.sse.util.SmartFutureCache.CacheUpdater;
+import com.sap.sse.util.SmartFutureCache.UpdateInterval;
/**
* Exports a leaderboard to the JSON format. Uses a {@link SmartFutureCache}.
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java
index ca80609670d..6b9ff74828d 100755
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java
@@ -20,7 +20,6 @@ import com.sap.sailing.domain.base.Person;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.common.CountryCode;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
@@ -36,6 +35,7 @@ import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sse.InvalidDateException;
+import com.sap.sse.common.CountryCode;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
index 97876cb43c5..8b758124930 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
@@ -1,5 +1,8 @@
package com.sap.sailing.server.gateway.jaxrs.api;
+import java.util.ArrayList;
+import java.util.stream.Stream;
+
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -17,19 +20,24 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
+import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.DoublePair;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
+import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl;
+import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
import com.sap.sailing.server.gateway.serialization.impl.PositionJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.WindJsonSerializer;
+import com.sap.sse.util.kmeans.Cluster;
/**
* Right now this service is only used for quick debugging and testing of the polar api. It used plain text responses.
@@ -95,7 +103,7 @@ public class PolarResource extends AbstractSailingServerResource {
}
@GET
- @Produces("text/plain;charset=UTF-8")
+ @Produces("application/json;charset=UTF-8")
@Path("windestimation/{regattaname}/races/{racename}")
public Response getCompetitorPositions(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) throws NotEnoughDataHasBeenAddedException {
Regatta regatta = findRegattaByName(regattaName);
@@ -112,7 +120,7 @@ public class PolarResource extends AbstractSailingServerResource {
WindJsonSerializer serializer = new WindJsonSerializer(new PositionJsonSerializer());
PolarDataService service = getService().getPolarDataService();
ManeuverBasedWindEstimationTrackImpl maneuverBasedWindEstimationTrackImpl = new ManeuverBasedWindEstimationTrackImpl(
- service, trackedRace, /* millisecondsOverWhichToAverage */ 30000);
+ service, trackedRace, /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ false);
maneuverBasedWindEstimationTrackImpl.lockForRead();
try {
for (Wind wind : maneuverBasedWindEstimationTrackImpl.getFixes()) {
@@ -121,8 +129,43 @@ public class PolarResource extends AbstractSailingServerResource {
} finally {
maneuverBasedWindEstimationTrackImpl.unlockAfterRead();
}
- ResponseBuilder responseBuilder = Response.ok(resultAsJson.toJSONString(), MediaType.TEXT_PLAIN);
- response = responseBuilder.build();
+ response = Response.ok(resultAsJson.toJSONString(), MediaType.APPLICATION_JSON).build();
+ }
+ }
+ return response;
+ }
+
+ @GET
+ @Produces("text/plain;charset=UTF-8")
+ @Path("maneuvers/{regattaname}/races/{racename}")
+ public Response getManeuvers(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName,
+ @QueryParam("cluster") String cluster)
+ throws NotEnoughDataHasBeenAddedException {
+ Regatta regatta = findRegattaByName(regattaName);
+ Response response;
+ if (regatta == null) {
+ response = getBadRegattaErrorResponse(regattaName);
+ } else {
+ RaceDefinition race = findRaceByName(regatta, raceName);
+ if (race == null) {
+ response = getBadRaceErrorResponse(regattaName, raceName);
+ } else {
+ TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
+ PolarDataService service = getService().getPolarDataService();
+ ManeuverBasedWindEstimationTrackImpl maneuverBasedWindEstimationTrackImpl = new ManeuverBasedWindEstimationTrackImpl(
+ service, trackedRace, /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ false);
+ final Stream> clusters;
+ if ("tack".equals(cluster)) {
+ clusters = Stream.of(maneuverBasedWindEstimationTrackImpl.getTackCluster());
+ } else if ("jibe".equals(cluster)) {
+ clusters = Stream.of(maneuverBasedWindEstimationTrackImpl.getJibeCluster());
+ } else if (cluster != null && cluster.matches("[0-9][0-9]*")) {
+ clusters = Stream.of(new ArrayList<>(maneuverBasedWindEstimationTrackImpl.getClusters()).get(Integer.valueOf(cluster)));
+ } else {
+ clusters = maneuverBasedWindEstimationTrackImpl.getClusters().stream();
+ }
+ response = Response.ok(maneuverBasedWindEstimationTrackImpl.getStringRepresentation(clusters, /* waitForLatest */ true),
+ MediaType.TEXT_PLAIN).build();
}
}
return response;
diff --git a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
index e62721228be..197b35bc5a2 100755
--- a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
@@ -25,4 +25,5 @@ Require-Bundle: com.sap.sailing.server,
com.sap.sse.common,
org.mockito.mockito-core;bundle-version="1.9.5",
com.sap.sailing.domain.shared.android,
- com.sap.sse.replication.testsupport
+ com.sap.sse.replication.testsupport,
+ com.sap.sse.shared.android
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java
index f913d8cd1e6..522b32f12a4 100644
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java
@@ -15,7 +15,6 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO;
@@ -28,6 +27,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard;
+import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
public abstract class AbstractLogReplicationTest, EventT extends AbstractLogEvent, VisitorT>
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/CompetitorReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/CompetitorReplicationTest.java
index 2c77345bf82..07553232562 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/CompetitorReplicationTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/CompetitorReplicationTest.java
@@ -25,7 +25,6 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.ScoringSchemeType;
@@ -41,6 +40,7 @@ import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
import com.sap.sailing.server.operationaltransformation.AllowCompetitorResetToDefaults;
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.UpdateCompetitor;
+import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaReplicationTest.java
index 450f4b9561a..9a5800a95ec 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaReplicationTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaReplicationTest.java
@@ -25,13 +25,13 @@ import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.server.operationaltransformation.UpdateSeries;
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackedRaceContentsReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackedRaceContentsReplicationTest.java
index 12762e73aca..047ecd2589c 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackedRaceContentsReplicationTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackedRaceContentsReplicationTest.java
@@ -28,7 +28,6 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.WindSource;
@@ -55,6 +54,7 @@ import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
+import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
index 44148bcbca3..24bdb4998e0 100755
--- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
+++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
@@ -71,7 +71,6 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
import com.sap.sailing.domain.common.MaxPointsReason;
@@ -111,6 +110,7 @@ import com.sap.sailing.server.gateway.jaxrs.spi.MasterDataResource;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.masterdata.DummyTrackedRace;
import com.sap.sailing.server.masterdata.MasterDataImporter;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java
index fe8a2866b87..a8c5a7a71e7 100755
--- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java
+++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java
@@ -34,7 +34,6 @@ import com.sap.sailing.domain.base.impl.CourseAreaImpl;
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.common.Color;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO;
@@ -69,6 +68,7 @@ import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.RemoveEvent;
import com.sap.sailing.server.operationaltransformation.RemoveLeaderboard;
import com.sap.sailing.server.operationaltransformation.RemoveRegatta;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/WindByRaceLogTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/WindByRaceLogTest.java
index 2865d2bda36..c400a3a1df3 100644
--- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/WindByRaceLogTest.java
+++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/WindByRaceLogTest.java
@@ -31,7 +31,6 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.WindSource;
@@ -57,6 +56,7 @@ import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboar
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.DisconnectLeaderboardColumnFromTrackedRace;
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF
index 33f058df7cb..1f88a62205c 100755
--- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF
@@ -29,7 +29,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.operationaltransformation,
com.sap.sse.replication,
com.sap.sse,
- com.sap.sailing.server.gateway.serialization.shared.android
+ com.sap.sailing.server.gateway.serialization.shared.android,
+ com.sap.sse.shared.android
Bundle-ClassPath: .
Export-Package: com.sap.sailing.server,
com.sap.sailing.server.impl;
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch
index 5be12174f71..2c4007d528e 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch
@@ -33,5 +33,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch
index 2a6259980f1..a67d08acad6 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch
@@ -32,5 +32,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
index 648f2821999..6ab6f8a17ab 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
@@ -26,6 +26,6 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
index 4f6187aa41b..31bfbb52380 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
@@ -27,6 +27,6 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch
index de11e6d6cb5..e1350cf0639 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch
@@ -26,5 +26,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch
index e0c271095ac..c52a1ceba8a 100755
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch
@@ -32,5 +32,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy).launch b/java/com.sap.sailing.server/SailingServer (Proxy).launch
index 27c8c29adc5..e9faedde69f 100755
--- a/java/com.sap.sailing.server/SailingServer (Proxy).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy).launch
@@ -33,6 +33,6 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
index d8cb087c747..4c9e5998b00 100755
--- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
@@ -26,6 +26,6 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch
index 258749ce4ba..d67a1da4bfd 100755
--- a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch
@@ -26,5 +26,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch
index 7ddb1c014fb..0b56116f9e4 100755
--- a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch
@@ -25,5 +25,5 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch b/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch
index 896bd1a0fac..a337c9bd920 100755
--- a/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch
@@ -26,6 +26,6 @@
-
+
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java
index 84182e335d3..48a8efafed8 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java
@@ -56,6 +56,7 @@ import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
+import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java
index fcd2e4f8a60..1186cc2384c 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java
@@ -16,9 +16,9 @@ import java.util.concurrent.ConcurrentMap;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.media.MediaTrack;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
class MediaLibrary {
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/PersistentCompetitorStore.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/PersistentCompetitorStore.java
index 143c4144c4c..c352f1637bc 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/PersistentCompetitorStore.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/PersistentCompetitorStore.java
@@ -10,11 +10,11 @@ import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.TransientCompetitorStoreImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinderFactory;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
+import com.sap.sse.common.Color;
import com.sap.sse.mongodb.MongoDBService;
/**
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
index ea70cf04535..22300c0aadb 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
@@ -191,8 +191,6 @@ import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived;
import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
import com.sap.sse.BuildVersion;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -200,6 +198,8 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.common.search.Result;
import com.sap.sse.common.search.ResultImpl;
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
import com.sap.sse.replication.OperationExecutionListener;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicationMasterDescriptor;
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DataImportLockWithProgress.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DataImportLockWithProgress.java
index 23675ba9466..e1df3fffe09 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DataImportLockWithProgress.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DataImportLockWithProgress.java
@@ -11,8 +11,8 @@ import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDataImport
import com.sap.sailing.server.operationaltransformation.DataImportFailed;
import com.sap.sailing.server.operationaltransformation.ImportMasterDataOperation;
import com.sap.sailing.server.operationaltransformation.SetDataImportDeleteProgressFromMapTimer;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
/**
* This lock is used to allow only one master data import operation be performed at once. It also keeps information
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java
index 840aa2b0380..39a1e449f9c 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java
@@ -50,8 +50,8 @@ import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
import com.sap.sailing.server.masterdata.DummyTrackedRace;
-import com.sap.sailing.util.impl.LockUtil;
import com.sap.sse.common.Util;
+import com.sap.sse.concurrent.LockUtil;
public class ImportMasterDataOperation extends
AbstractRacingEventServiceOperation {
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateCompetitor.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateCompetitor.java
index 749c6557e94..0b63f0c2c75 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateCompetitor.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateCompetitor.java
@@ -2,9 +2,9 @@ package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Nationality;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
+import com.sap.sse.common.Color;
public class UpdateCompetitor extends AbstractRacingEventServiceOperation {
private static final long serialVersionUID = 1172181354320184263L;
diff --git a/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/StructureImporter.java b/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/StructureImporter.java
index b5558943b64..c27ee51992d 100755
--- a/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/StructureImporter.java
+++ b/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/StructureImporter.java
@@ -29,10 +29,8 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.FleetColors;
import com.sap.sailing.domain.common.ScoringSchemeType;
-import com.sap.sailing.domain.common.impl.AbstractColor;
import com.sap.sailing.xrr.resultimport.ParserFactory;
import com.sap.sailing.xrr.schema.Boat;
import com.sap.sailing.xrr.schema.Crew;
@@ -49,7 +47,9 @@ import com.sap.sailing.xrr.structureimport.buildstructure.GuessFleetOrderingStra
import com.sap.sailing.xrr.structureimport.buildstructure.RegattaStructure;
import com.sap.sailing.xrr.structureimport.buildstructure.Series;
import com.sap.sailing.xrr.structureimport.buildstructure.SetRacenumberStrategy;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.impl.AbstractColor;
import com.sapsailing.xrr.structureimport.eventimport.EventImport;
import com.sapsailing.xrr.structureimport.eventimport.RegattaJSON;
diff --git a/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/buildstructure/Competitors.java b/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/buildstructure/Competitors.java
index 59e3d4a9255..8f6d9ea85c8 100755
--- a/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/buildstructure/Competitors.java
+++ b/java/com.sap.sailing.xrr.structureimport/src/com/sap/sailing/xrr/structureimport/buildstructure/Competitors.java
@@ -1,7 +1,7 @@
package com.sap.sailing.xrr.structureimport.buildstructure;
-import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
+import com.sap.sse.common.Color;
public class Competitors {
private String countryCode = "";
diff --git a/java/com.sap.sse.common/.classpath b/java/com.sap.sse.common/.classpath
index d0c701c89d6..dcc01746046 100644
--- a/java/com.sap.sse.common/.classpath
+++ b/java/com.sap.sse.common/.classpath
@@ -1,8 +1,8 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/java/com.sap.sse.common/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sse.common/.settings/org.eclipse.jdt.core.prefs
index c537b63063c..d17b6724d17 100644
--- a/java/com.sap.sse.common/.settings/org.eclipse.jdt.core.prefs
+++ b/java/com.sap.sse.common/.settings/org.eclipse.jdt.core.prefs
@@ -1,7 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF
index 50e1fe41905..56290d7ee65 100644
--- a/java/com.sap.sse.common/META-INF/MANIFEST.MF
+++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF
@@ -4,10 +4,11 @@ Bundle-Name: SSE Common
Bundle-SymbolicName: com.sap.sse.common
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
-Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: com.sap.sse.common,
com.sap.sse.common.filter,
com.sap.sse.common.impl,
+ com.sap.sse.common.scalablevalue,
com.sap.sse.common.search
Require-Bundle: com.sap.sse.datamining.shared;bundle-version="1.0.0"
Bundle-ActivationPolicy: lazy
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ArrayListNavigableSet.java b/java/com.sap.sse.common/src/com/sap/sse/common/ArrayListNavigableSet.java
similarity index 96%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ArrayListNavigableSet.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/ArrayListNavigableSet.java
index 481181beb5f..7945b1139e3 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ArrayListNavigableSet.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/ArrayListNavigableSet.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.common;
import java.io.Serializable;
import java.util.ArrayList;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Base64Utils.java b/java/com.sap.sse.common/src/com/sap/sse/common/Base64Utils.java
similarity index 96%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Base64Utils.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/Base64Utils.java
index c1efa411e14..0d2081737eb 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Base64Utils.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/Base64Utils.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common;
+package com.sap.sse.common;
/*
* Copyright 2009 Google Inc.
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Cloner.java b/java/com.sap.sse.common/src/com/sap/sse/common/Cloner.java
similarity index 63%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Cloner.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/Cloner.java
index f1bc4002919..3265c2a544b 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Cloner.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/Cloner.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common;
+package com.sap.sse.common;
public interface Cloner {
void clone(Object from, Object to);
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Color.java b/java/com.sap.sse.common/src/com/sap/sse/common/Color.java
similarity index 87%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Color.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/Color.java
index da4f7ab2555..5eb74f763f5 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Color.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/Color.java
@@ -1,8 +1,8 @@
-package com.sap.sailing.domain.common;
+package com.sap.sse.common;
import java.io.Serializable;
-import com.sap.sailing.domain.common.impl.RGBColor;
+import com.sap.sse.common.impl.RGBColor;
public interface Color extends Serializable {
final Color WHITE = new RGBColor(255, 255, 255);
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCode.java b/java/com.sap.sse.common/src/com/sap/sse/common/CountryCode.java
similarity index 82%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCode.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/CountryCode.java
index 57ca803b4cf..6bb75ffeedf 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCode.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/CountryCode.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common;
+package com.sap.sse.common;
public interface CountryCode {
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCodeFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/CountryCodeFactory.java
similarity index 84%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCodeFactory.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/CountryCodeFactory.java
index 29d7cdbc4fb..eff4a2589c5 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CountryCodeFactory.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/CountryCodeFactory.java
@@ -1,6 +1,6 @@
-package com.sap.sailing.domain.common;
+package com.sap.sse.common;
-import com.sap.sailing.domain.common.impl.CountryCodeFactoryImpl;
+import com.sap.sse.common.impl.CountryCodeFactoryImpl;
public interface CountryCodeFactory {
CountryCodeFactory INSTANCE = new CountryCodeFactoryImpl();
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ReverseRandomAccessList.java b/java/com.sap.sse.common/src/com/sap/sse/common/ReverseRandomAccessList.java
similarity index 89%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ReverseRandomAccessList.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/ReverseRandomAccessList.java
index 9dc280dc06d..562aa477b66 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ReverseRandomAccessList.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/ReverseRandomAccessList.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.common;
import java.util.AbstractList;
import java.util.List;
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
index d27ffffbff5..75230764cee 100755
--- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
@@ -348,4 +348,18 @@ public class Util {
}
return join(separator, strings);
}
+
+ /**
+ * Returns the first non-null object in objects or null
+ * if no such object exists.
+ */
+ @SafeVarargs
+ public static T getFirstNonNull(T... objects) {
+ for (T t : objects) {
+ if (t != null) {
+ return t;
+ }
+ }
+ return null;
+ }
}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractColor.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractColor.java
similarity index 95%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractColor.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractColor.java
index 218eed21d46..e421ddea801 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractColor.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractColor.java
@@ -1,6 +1,6 @@
-package com.sap.sailing.domain.common.impl;
+package com.sap.sse.common.impl;
-import com.sap.sailing.domain.common.Color;
+import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
public abstract class AbstractColor implements Color {
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeFactoryImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeFactoryImpl.java
similarity index 98%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeFactoryImpl.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeFactoryImpl.java
index fc3a111d2e6..acf7452f781 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeFactoryImpl.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeFactoryImpl.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.impl;
+package com.sap.sse.common.impl;
import java.util.Collections;
import java.util.HashMap;
@@ -6,8 +6,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import com.sap.sailing.domain.common.CountryCode;
-import com.sap.sailing.domain.common.CountryCodeFactory;
+import com.sap.sse.common.CountryCode;
+import com.sap.sse.common.CountryCodeFactory;
public class CountryCodeFactoryImpl implements CountryCodeFactory {
private final Map byThreeLetterIOCName;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeImpl.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeImpl.java
similarity index 91%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeImpl.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeImpl.java
index c9330618272..807145e63a2 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/CountryCodeImpl.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/CountryCodeImpl.java
@@ -1,6 +1,6 @@
-package com.sap.sailing.domain.common.impl;
+package com.sap.sse.common.impl;
-import com.sap.sailing.domain.common.CountryCode;
+import com.sap.sse.common.CountryCode;
public class CountryCodeImpl implements CountryCode {
private final String name;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/HSVColor.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/HSVColor.java
similarity index 95%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/HSVColor.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/impl/HSVColor.java
index 5d6e45ceb0c..d831b89af52 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/HSVColor.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/HSVColor.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.impl;
+package com.sap.sse.common.impl;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/RGBColor.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/RGBColor.java
similarity index 95%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/RGBColor.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/impl/RGBColor.java
index 4944b479304..ddd26f55ee4 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/RGBColor.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/RGBColor.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.impl;
+package com.sap.sse.common.impl;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/AbstractScalarValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/AbstractScalarValue.java
similarity index 59%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/AbstractScalarValue.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/AbstractScalarValue.java
index c14cc01883c..33fc7a9c721 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/AbstractScalarValue.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/AbstractScalarValue.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.scalablevalue;
+package com.sap.sse.common.scalablevalue;
/**
@@ -8,5 +8,6 @@ package com.sap.sailing.domain.common.scalablevalue;
* @author Axel Uhl (d043530)
*
*/
-public interface AbstractScalarValue extends ScalableValue {
+public interface AbstractScalarValue> extends ComparableScalableValueWithDistance {
+
}
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ComparableScalableValueWithDistance.java b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ComparableScalableValueWithDistance.java
new file mode 100755
index 00000000000..cb773c07cd4
--- /dev/null
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ComparableScalableValueWithDistance.java
@@ -0,0 +1,5 @@
+package com.sap.sse.common.scalablevalue;
+
+public interface ComparableScalableValueWithDistance>
+ extends ScalableValueWithDistance, Comparable {
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/IsScalable.java b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/IsScalable.java
similarity index 73%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/IsScalable.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/IsScalable.java
index 4789e8a2a3d..2372c51620f 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/IsScalable.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/IsScalable.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.scalablevalue;
+package com.sap.sse.common.scalablevalue;
import java.io.Serializable;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/ScalableValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValue.java
similarity index 81%
rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/ScalableValue.java
rename to java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValue.java
index 61ae9bbf7ca..be59a56d8bb 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/ScalableValue.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValue.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.common.scalablevalue;
+package com.sap.sse.common.scalablevalue;
public interface ScalableValue {
ScalableValue multiply(double factor);
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValueWithDistance.java b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValueWithDistance.java
new file mode 100755
index 00000000000..ceaf9e752d6
--- /dev/null
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableValueWithDistance.java
@@ -0,0 +1,22 @@
+package com.sap.sse.common.scalablevalue;
+
+/**
+ * In addition to being a {@link ScalableValue}, specifies the {@link #getDistance} method which determines
+ * a non-negative double value as a measure for the distances between two values of this type.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ * @param
+ */
+public interface ScalableValueWithDistance extends ScalableValue {
+ /**
+ * @return a non-negative distance measure; 0.0 in case this and other are
+ * equal.
+ */
+ double getDistance(AveragesTo other);
+
+ ScalableValueWithDistance add(ScalableValue t);
+
+ ScalableValueWithDistance multiply(double factor);
+}
diff --git a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTest.java b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTest.java
index 17cc684c58d..001315e97a8 100755
--- a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTest.java
+++ b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTest.java
@@ -18,6 +18,8 @@ import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;
import org.junit.After;
@@ -36,11 +38,13 @@ import com.sap.sse.replication.impl.RabbitOutputStream;
import com.sap.sse.replication.impl.ReplicaDescriptor;
import com.sap.sse.replication.impl.ReplicationInstancesManager;
import com.sap.sse.replication.impl.ReplicationMasterDescriptorImpl;
-import com.sap.sse.replication.impl.ReplicationServiceImpl;
import com.sap.sse.replication.impl.ReplicationReceiver;
+import com.sap.sse.replication.impl.ReplicationServiceImpl;
import com.sap.sse.replication.impl.SingletonReplicablesProvider;
public abstract class AbstractServerReplicationTest, ReplicableImpl extends ReplicableInterface> {
+ private static final Logger logger = Logger.getLogger(AbstractServerReplicationTest.class.getName());
+
protected static final int SERVLET_PORT = 9990;
protected ReplicableImpl replica;
protected ReplicableImpl master;
@@ -92,6 +96,7 @@ public abstract class AbstractServerReplicationTest, ReplicationMasterDescriptor> basicSetUp(boolean dropDB,
ReplicableImpl master, ReplicableImpl replica) throws Exception {
+ logger.info("basicSetUp for test class "+getClass().getName());
persistenceSetUp(dropDB);
String exchangeName = "test-sapsailinganalytics-exchange";
String exchangeHost = "localhost";
@@ -119,8 +124,10 @@ public abstract class AbstractServerReplicationTest replicaReplicator = new ReplicationServiceTestImpl(exchangeName, exchangeHost, rim, replicaDescriptor,
this.replica, this.master, masterReplicator, masterDescriptor);
Pair, ReplicationMasterDescriptor> result = new Pair<>(replicaReplicator, masterDescriptor);
+ logger.info("starting initial load transmission servlet for "+getClass().getName());
initialLoadTestServerThread = replicaReplicator.startInitialLoadTransmissionServlet();
this.replicaReplicator = replicaReplicator;
+ logger.info("basicSetUp for test class "+getClass().getName()+" finished");
return result;
}
@@ -140,25 +147,31 @@ public abstract class AbstractServerReplicationTest
+
+
+
+
+
+
diff --git a/java/com.sap.sse.shared.android/.project b/java/com.sap.sse.shared.android/.project
new file mode 100755
index 00000000000..dd31c4112a7
--- /dev/null
+++ b/java/com.sap.sse.shared.android/.project
@@ -0,0 +1,28 @@
+
+
+ com.sap.sse.shared.android
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/com.sap.sse.shared.android/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sse.shared.android/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 00000000000..11f6e462df7
--- /dev/null
+++ b/java/com.sap.sse.shared.android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/java/com.sap.sse.shared.android/.settings/org.eclipse.pde.core.prefs b/java/com.sap.sse.shared.android/.settings/org.eclipse.pde.core.prefs
new file mode 100755
index 00000000000..b7e72d019c2
--- /dev/null
+++ b/java/com.sap.sse.shared.android/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF
new file mode 100755
index 00000000000..e7ad05c7f81
--- /dev/null
+++ b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Android
+Bundle-SymbolicName: com.sap.sse.shared.android
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: SAP
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Require-Bundle: com.sap.sse.common
+Export-Package: com.sap.sse.concurrent,
+ com.sap.sse.util.impl
diff --git a/java/com.sap.sse.shared.android/build.properties b/java/com.sap.sse.shared.android/build.properties
new file mode 100755
index 00000000000..41eb6ade2b4
--- /dev/null
+++ b/java/com.sap.sse.shared.android/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/java/com.sap.sse.shared.android/pom.xml b/java/com.sap.sse.shared.android/pom.xml
new file mode 100644
index 00000000000..379df04767b
--- /dev/null
+++ b/java/com.sap.sse.shared.android/pom.xml
@@ -0,0 +1,12 @@
+
+
+ 4.0.0
+
+ root
+ com.sap.sailing
+ 1.0.0-SNAPSHOT
+
+ com.sap.sse.shared.android
+ eclipse-plugin
+
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentHashBag.java b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentHashBag.java
similarity index 98%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentHashBag.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentHashBag.java
index dc3c045e655..aedd9a45784 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentHashBag.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentHashBag.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.concurrent;
import java.util.AbstractCollection;
import java.util.Map.Entry;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentWeakHashMap.java b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentWeakHashMap.java
similarity index 99%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentWeakHashMap.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentWeakHashMap.java
index 1e71a2f8cca..609a3ba4dbc 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/ConcurrentWeakHashMap.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/ConcurrentWeakHashMap.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.concurrent;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/LockUtil.java b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/LockUtil.java
similarity index 97%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/LockUtil.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/LockUtil.java
index c3c5061fa4a..be927203809 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/LockUtil.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/LockUtil.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.concurrent;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/NamedReentrantReadWriteLock.java
similarity index 96%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/NamedReentrantReadWriteLock.java
index 4f2e2efc65d..3e6c39dad6d 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/concurrent/NamedReentrantReadWriteLock.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.concurrent;
import java.io.IOException;
import java.io.ObjectInputStream;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/AbstractUnmodifiableNavigableSet.java b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/AbstractUnmodifiableNavigableSet.java
similarity index 93%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/AbstractUnmodifiableNavigableSet.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/AbstractUnmodifiableNavigableSet.java
index b1bfda134df..353807d8dc7 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/AbstractUnmodifiableNavigableSet.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/AbstractUnmodifiableNavigableSet.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.util.impl;
import java.io.Serializable;
import java.util.Collection;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/DescendingNavigableSet.java b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/DescendingNavigableSet.java
similarity index 94%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/DescendingNavigableSet.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/DescendingNavigableSet.java
index d7cb7eeee7a..c0f802a4575 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/DescendingNavigableSet.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/DescendingNavigableSet.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.util.impl;
import java.util.Collection;
import java.util.Collections;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/UnmodifiableNavigableSet.java b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/UnmodifiableNavigableSet.java
similarity index 95%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/UnmodifiableNavigableSet.java
rename to java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/UnmodifiableNavigableSet.java
index bdd5de00f65..d3867e2d655 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/UnmodifiableNavigableSet.java
+++ b/java/com.sap.sse.shared.android/src/com/sap/sse/util/impl/UnmodifiableNavigableSet.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util.impl;
+package com.sap.sse.util.impl;
import java.util.Collection;
import java.util.Collections;
diff --git a/java/com.sap.sse/META-INF/MANIFEST.MF b/java/com.sap.sse/META-INF/MANIFEST.MF
index a8e8f94cf1e..cc68d229206 100755
--- a/java/com.sap.sse/META-INF/MANIFEST.MF
+++ b/java/com.sap.sse/META-INF/MANIFEST.MF
@@ -7,6 +7,8 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: com.sap.sse,
com.sap.sse.util,
- com.sap.sse.util.impl
+ com.sap.sse.util.impl,
+ com.sap.sse.util.kmeans
Bundle-ActivationPolicy: lazy
-Require-Bundle: com.sap.sse.common
+Require-Bundle: com.sap.sse.common,
+ com.sap.sse.shared.android
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableReadLock.java b/java/com.sap.sse/src/com/sap/sse/util/AutoCloseableReadLock.java
similarity index 72%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableReadLock.java
rename to java/com.sap.sse/src/com/sap/sse/util/AutoCloseableReadLock.java
index cdce95659e1..92e5f66c578 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableReadLock.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/AutoCloseableReadLock.java
@@ -1,7 +1,8 @@
-package com.sap.sailing.util;
+package com.sap.sse.util;
+
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
public class AutoCloseableReadLock implements AutoCloseable {
private final NamedReentrantReadWriteLock lock;
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableWriteLock.java b/java/com.sap.sse/src/com/sap/sse/util/AutoCloseableWriteLock.java
similarity index 72%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableWriteLock.java
rename to java/com.sap.sse/src/com/sap/sse/util/AutoCloseableWriteLock.java
index 3b9570f16c4..558dc41a706 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/AutoCloseableWriteLock.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/AutoCloseableWriteLock.java
@@ -1,7 +1,8 @@
-package com.sap.sailing.util;
+package com.sap.sse.util;
+
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
public class AutoCloseableWriteLock implements AutoCloseable {
private final NamedReentrantReadWriteLock lock;
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/ByteArrayOutputStreamWithVisibleBuffer.java b/java/com.sap.sse/src/com/sap/sse/util/ByteArrayOutputStreamWithVisibleBuffer.java
similarity index 85%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/ByteArrayOutputStreamWithVisibleBuffer.java
rename to java/com.sap.sse/src/com/sap/sse/util/ByteArrayOutputStreamWithVisibleBuffer.java
index d6f60ca7bfb..63f2101fc36 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/ByteArrayOutputStreamWithVisibleBuffer.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/ByteArrayOutputStreamWithVisibleBuffer.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util;
+package com.sap.sse.util;
import java.io.ByteArrayOutputStream;
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/ClonerImpl.java b/java/com.sap.sse/src/com/sap/sse/util/ClonerImpl.java
similarity index 91%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/ClonerImpl.java
rename to java/com.sap.sse/src/com/sap/sse/util/ClonerImpl.java
index ac5b1bc3080..95882b3f0eb 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/ClonerImpl.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/ClonerImpl.java
@@ -1,9 +1,9 @@
-package com.sap.sailing.util;
+package com.sap.sse.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import com.sap.sailing.domain.common.Cloner;
+import com.sap.sse.common.Cloner;
public class ClonerImpl implements Cloner {
public void clone(Object from, Object to) {
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/SmartFutureCache.java b/java/com.sap.sse/src/com/sap/sse/util/SmartFutureCache.java
similarity index 97%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/SmartFutureCache.java
rename to java/com.sap.sse/src/com/sap/sse/util/SmartFutureCache.java
index b800ca87e9a..c0792b23c3f 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/SmartFutureCache.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/SmartFutureCache.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.util;
+package com.sap.sse.util;
import java.util.HashMap;
import java.util.HashSet;
@@ -19,9 +19,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
-import com.sap.sailing.util.SmartFutureCache.UpdateInterval;
-import com.sap.sailing.util.impl.LockUtil;
-import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
+import com.sap.sse.util.SmartFutureCache.UpdateInterval;
import com.sap.sse.util.impl.ThreadFactoryWithPriority;
/**
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/WeakIdentityHashMap.java b/java/com.sap.sse/src/com/sap/sse/util/WeakIdentityHashMap.java
similarity index 96%
rename from java/com.sap.sailing.domain/src/com/sap/sailing/util/WeakIdentityHashMap.java
rename to java/com.sap.sse/src/com/sap/sse/util/WeakIdentityHashMap.java
index efaf06a3cba..9ec3ba5f898 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/WeakIdentityHashMap.java
+++ b/java/com.sap.sse/src/com/sap/sse/util/WeakIdentityHashMap.java
@@ -2,7 +2,7 @@
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
-package com.sap.sailing.util;
+package com.sap.sse.util;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
diff --git a/java/com.sap.sse/src/com/sap/sse/util/kmeans/Cluster.java b/java/com.sap.sse/src/com/sap/sse/util/kmeans/Cluster.java
new file mode 100755
index 00000000000..a2d280f62c8
--- /dev/null
+++ b/java/com.sap.sse/src/com/sap/sse/util/kmeans/Cluster.java
@@ -0,0 +1,124 @@
+package com.sap.sse.util.kmeans;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import com.sap.sse.common.scalablevalue.ScalableValueWithDistance;
+
+/**
+ * A k-means cluster that can determine its centroid (arithmetic mean of all its values) and for each element the
+ * distance to that centroid.
+ *
+ *
+ * Two clusters are equal and therefore in particular have equal hash codes if their element set is equal. This equality
+ * definition explicitly ignores the {@link #mean} to which this cluster was initialized.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ */
+public class Cluster> implements Iterable {
+ private final Set elements;
+ private final Function mapper;
+ private final AveragesTo mean;
+ private ScalableValueWithDistance sum;
+
+ public Cluster(final AveragesTo mean, Function mapper) {
+ this.mapper = mapper;
+ elements = new HashSet<>();
+ this.mean = mean;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((elements == null) ? 0 : elements.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Cluster, ?, ?, ?> other = (Cluster, ?, ?, ?>) obj;
+ if (elements == null) {
+ if (other.elements != null)
+ return false;
+ } else if (!elements.equals(other.elements))
+ return false;
+ return true;
+ }
+
+ public void add(final E e) {
+ elements.add(e);
+ final T t = mapper.apply(e);
+ if (sum == null) {
+ sum = t;
+ } else {
+ sum = sum.add(t);
+ }
+ }
+
+ /**
+ * Determines the {@link ScalableValueWithDistance#getDistance(Object) distance} of the element e to
+ * this cluster's {@link #mean} value.
+ */
+ public double getDistanceFromMean(final E e) {
+ return mapper.apply(e).getDistance(mean);
+ }
+
+ /**
+ * @return null for an empty cluster; otherwise the average obtained by dividing the element
+ * {@link ScalableValueWithDistance#add(com.sap.sse.common.scalablevalue.ScalableValue) sum} by
+ * the number of elements that have been added to this cluster so far
+ */
+ public AveragesTo getCentroid() {
+ return sum == null ? null : sum.divide(elements.size());
+ }
+
+ public AveragesTo getMean() {
+ return mean;
+ }
+
+ public int size() {
+ return elements.size();
+ }
+
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ @Override
+ public Iterator iterator() {
+ return elements.iterator();
+ }
+
+ @Override
+ public Spliterator spliterator() {
+ return elements.spliterator();
+ }
+
+ @Override
+ public void forEach(Consumer super E> action) {
+ elements.forEach(action);
+ }
+
+ @Override
+ public String toString() {
+ return "{mean: "+getMean()+", centroid: "+getCentroid()+", elements: "+elements+"}";
+ }
+
+ public Stream stream() {
+ return elements.stream();
+ }
+}
diff --git a/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClusterer.java b/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClusterer.java
new file mode 100755
index 00000000000..a5c4fb7244a
--- /dev/null
+++ b/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClusterer.java
@@ -0,0 +1,26 @@
+package com.sap.sse.util.kmeans;
+
+import java.util.Iterator;
+
+import com.sap.sse.common.scalablevalue.ScalableValueWithDistance;
+
+/**
+ * Clusters elements of type T into a pre-defined number of clusters such that after clustering the sum of
+ * square distances of each element to its cluster mean is minimized. See also http://en.wikipedia.org/wiki/K-means_clustering.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ */
+public class KMeansClusterer> extends
+ KMeansMappingClusterer {
+
+ protected KMeansClusterer(int numberOfClusters, Iterable elements, Iterator seeds) {
+ super(numberOfClusters, elements, (e) -> e, seeds);
+ }
+
+ public KMeansClusterer(int numberOfClusters, Iterable elements) {
+ super(numberOfClusters, elements, (e) -> e);
+ }
+}
\ No newline at end of file
diff --git a/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClustererWithEquidistantInitialization.java b/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClustererWithEquidistantInitialization.java
new file mode 100755
index 00000000000..4483b8586aa
--- /dev/null
+++ b/java/com.sap.sse/src/com/sap/sse/util/kmeans/KMeansClustererWithEquidistantInitialization.java
@@ -0,0 +1,58 @@
+package com.sap.sse.util.kmeans;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.sap.sse.common.scalablevalue.ComparableScalableValueWithDistance;
+import com.sap.sse.common.scalablevalue.ScalableValueWithDistance;
+
+/**
+ * Requires {@link ComparableScalableValueWithDistance comparable scalable values} as elements for which then
+ * the minimum and maximum elements are calculated. The given number of clusters is then initialized with mean values
+ * that are equidistantly distributed between the minimum and maximum value.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ * @param
+ * @param
+ */
+public class KMeansClustererWithEquidistantInitialization, T extends ComparableScalableValueWithDistance>
+ extends KMeansClusterer {
+
+ public KMeansClustererWithEquidistantInitialization(int numberOfClusters, Iterable elements) {
+ super(numberOfClusters, elements, getEquiDistantSeeds(numberOfClusters, elements));
+ }
+
+ /**
+ * Based on the elements being mutually comparable, min and max are determined and elements in between are calculated
+ * so that numberOfClusters-1 equal distances are created.
+ */
+ private static , T extends ComparableScalableValueWithDistance> Iterator getEquiDistantSeeds(
+ int numberOfClusters, Iterable elements) {
+ AveragesTo min = null;
+ T minElement = null;
+ AveragesTo max = null;
+ T maxElement = null;
+ for (T t : elements) {
+ final AveragesTo tVal = t.divide(1);
+ if (min == null || min.compareTo(tVal) > 0) {
+ minElement = t;
+ min = tVal;
+ }
+ if (max == null || max.compareTo(tVal) < 0) {
+ maxElement = t;
+ max = tVal;
+ }
+ }
+ ScalableValueWithDistance step = maxElement.add(minElement.multiply(-1)).multiply(1./(double) (numberOfClusters-1));
+ List seeds = new ArrayList<>();
+ ScalableValueWithDistance a = minElement;
+ for (int i = 0; i E into a pre-defined number of clusters such that after clustering the sum of
+ * square distances of each element to its cluster mean is minimized. See also http://en.wikipedia.org/wiki/K-means_clustering.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ * the element type that can be mapped using a mapping {@link Function} to a
+ * @param
+ * auxiliary type required for the scalable value type T
+ * @param
+ * auxiliary type required for the scalable value type T
+ * @param
+ * elements of this type can be obtained through a mapping from elements of type E and can hence
+ * be scaled and a distance between them can be computed which enables the clustering process
+ */
+public class KMeansMappingClusterer> {
+ private List> clusters;
+ private final Function mapper;
+
+ /**
+ * Clusters the elements into numberOfClusters clusters such that the sum of squared
+ * distances to the elements' assigned cluster centroid is minimized. After the constructor has returned, clients
+ * can query the clusters and their centroids.
+ *
+ *
+ * To determine the seeds for the clusters, all elements will be distributed randomly across the
+ * numberOfClusters clusters, and the resulting cluster centroids are used as seeds.
+ *
+ * @param numberOfClusters
+ * this is the "k" in the k-means algorithm, defining how many clusters are expected.
+ * @param elements
+ * the elements to cluster
+ * @param mapper
+ * maps elements to type T
+ */
+ public KMeansMappingClusterer(int numberOfClusters, Iterable elements, Function mapper) {
+ this(numberOfClusters, elements, mapper, randomizedSeeds(numberOfClusters, elements, mapper));
+ }
+
+ /**
+ * Same as {@link #KMeansMappingClusterer(int, Iterable, Function)}, only that a stream instead of an iterable
+ * is used to provide the elements.
+ *
+ * @param elements the stream must not be {@link Stream#isParallel() a parallel stream}
+ */
+ public KMeansMappingClusterer(int numberOfClusters, Stream elements, Function mapper) {
+ this(numberOfClusters, streamToList(elements), mapper);
+ }
+
+ private static Iterable streamToList(Stream elements) {
+ assert !elements.isParallel();
+ final List result = new ArrayList<>();
+ elements.forEach((e)->result.add(e));
+ return result;
+ }
+
+ /**
+ * Constructs numberOfClusters (or as many as elements are provided if those are fewer
+ * than numberOfClusters) clusters and randomly assigns the elements to them. The
+ * {@link Cluster#getCentroid() centroids} of those clusters are returned as initial means.
+ */
+ private static > Iterator randomizedSeeds(
+ int numberOfClusters, Iterable elements, Function mapper) {
+ ArrayList> clusters = new ArrayList<>(numberOfClusters);
+ Random random = new Random();
+ int i=0;
+ for (E e : elements) {
+ if (i < numberOfClusters) {
+ Cluster cluster = new Cluster<>(null, mapper);
+ clusters.add(cluster);
+ cluster.add(e);
+ } else {
+ clusters.get(random.nextInt(numberOfClusters)).add(e);
+ }
+ i++;
+ };
+ return clusters.stream().map((c)->c.getCentroid()).iterator();
+ }
+
+ /**
+ * Same as {@link #KMeansMappingClusterer(int, Iterable, Function, Iterator)}, only that the elements and the seeds are
+ * provided by streams instead of iterables and iterators.
+ */
+ public KMeansMappingClusterer(int numberOfClusters, Stream elements, Function mapper, Stream extends AveragesTo> seeds) {
+ this(numberOfClusters, streamToList(elements), mapper, seeds.iterator());
+ }
+
+ /**
+ * Like {@link #KMeansMappingClusterer(int, Iterable)}, additionally providing the seeds to use for the cluster centroids
+ * during the first iteration.
+ *
+ * @param seeds
+ * elements to use as the seeds; if fewer than numberOfClusters seeds are provided, the
+ * number of clusters is reduced to the number of seeds provided.
+ */
+ public KMeansMappingClusterer(int numberOfClusters, Iterable elements, Function mapper, Iterator extends AveragesTo> seeds) {
+ this.mapper = mapper;
+ clusters = new ArrayList<>();
+ initClusters(elements, seeds);
+ if (!clusters.isEmpty()) {
+ addElementsToNearestCluster(elements);
+ iterate(elements);
+ }
+ }
+
+ /**
+ * Creates the clusters using the seeds as their initial mean. Won't create more clusters than
+ * elements provided; in case fewer elements are provided, only a prefix of the seeds
+ * iterator will be used.
+ */
+ private void initClusters(Iterable elements, Iterator extends AveragesTo> seeds) {
+ Iterator elementsIter = elements.iterator();
+ while (elementsIter.hasNext() && seeds.hasNext()) {
+ elementsIter.next();
+ clusters.add(new Cluster(seeds.next(), mapper));
+ }
+ }
+
+ /**
+ * Computes the next iteration by creating new clusters that use as their mean the centroids of the
+ * current clusters; then, assigns all elements to these clusters and repeats this process until
+ * the latest iteration produces the same clustering that the previous iteration produced.
+ */
+ private void iterate(Iterable elements) {
+ List> oldClusters;
+ do {
+ List> newClusters = new ArrayList<>(clusters.size());
+ for (Cluster c : clusters) {
+ AveragesTo newMean = c.getCentroid();
+ if (newMean == null) {
+ newMean = c.getMean(); // use old mean instead
+ }
+ newClusters.add(new Cluster(newMean, mapper));
+ }
+ oldClusters = clusters;
+ clusters = newClusters;
+ addElementsToNearestCluster(elements);
+ } while (!clusters.equals(oldClusters));
+ }
+
+ /**
+ * adds all elements to their nearest cluster
+ */
+ private void addElementsToNearestCluster(Iterable elements) {
+ assert !clusters.isEmpty();
+ for (E e : elements) {
+ Iterator> clusterIter = clusters.iterator();
+ Cluster nearestCluster = clusterIter.next();
+ double leastDistance = nearestCluster.getDistanceFromMean(e);
+ while (clusterIter.hasNext()) {
+ Cluster nextCluster = clusterIter.next();
+ double distance = nextCluster.getDistanceFromMean(e);
+ if (distance < leastDistance) {
+ leastDistance = distance;
+ nearestCluster = nextCluster;
+ }
+ }
+ nearestCluster.add(e);
+ }
+ }
+
+ public Set