mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-01 09:53:58 +00:00
Merge branch 'master' into bug2707
This commit is contained in:
commit
f1a52dc719
82 files changed
+1860
-888
No files matched your search
@@ -20,7 +20,7 @@ start_tmux() {
|
||||
|
||||
start_servers() {
|
||||
NUMBER_OF_INSTANCES=`echo "$JAVA_START_INSTANCES" | wc -w`
|
||||
MEMORY_PER_INSTANCE_IN_MB=`cat /proc/meminfo | grep MemTotal | awk '{printf("%i\n", ($2 / 1024 - 1500) / '$NUMBER_OF_INSTANCES' );}'`
|
||||
MEMORY_PER_INSTANCE_IN_MB=`cat /proc/meminfo | grep MemTotal | awk '{printf("%i\n", ($2 / 1024 * 0.75 - 1500) / '$NUMBER_OF_INSTANCES' );}'`
|
||||
echo "Using ${MEMORY_PER_INSTANCE_IN_MB}MB as default heap size per instance."
|
||||
for conf in $JAVA_START_INSTANCES; do
|
||||
echo "Checking for amazon update..."
|
||||
|
||||
+1
-8
@@ -11,19 +11,12 @@ import com.sap.sse.datamining.components.Processor;
|
||||
public class ConcurrencyTestsUtil {
|
||||
|
||||
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
private static ThreadPoolExecutor executor = createExecutor();
|
||||
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
public static ThreadPoolExecutor getExecutor() {
|
||||
if (executor.isShutdown()) {
|
||||
executor = createExecutor();
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
private static ThreadPoolExecutor createExecutor() {
|
||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
public static void sleepFor(long milliseconds) {
|
||||
try {
|
||||
Thread.sleep(milliseconds);
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class NullProcessor<InputType, ResultType> extends AbstractProcessor<Inpu
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
|
||||
throw new RuntimeException("An error occured during the processing", failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public enum DetailType implements Serializable {
|
||||
RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(1, ASCENDING), RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START(1, ASCENDING),
|
||||
RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START(2, DESCENDING),
|
||||
RACE_TIME_TRAVELED(0, ASCENDING), RACE_TIME_TRAVELED_UPWIND(0, ASCENDING), RACE_TIME_TRAVELED_DOWNWIND(0, ASCENDING), RACE_TIME_TRAVELED_REACHING(0, ASCENDING),
|
||||
DISTANCE_TO_START_LINE(0, ASCENDING), BEAT_ANGLE(0, ASCENDING);
|
||||
DISTANCE_TO_START_LINE(0, ASCENDING), BEAT_ANGLE(0, ASCENDING), COURSE_OVER_GROUND_TRUE_DEGREES(0, ASCENDING);
|
||||
|
||||
private int precision;
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public class DoubleTriple {
|
||||
private final double a;
|
||||
private final double b;
|
||||
private final double c;
|
||||
|
||||
public DoubleTriple(double a, double b, double c) {
|
||||
super();
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public double getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public double getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public double getC() {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
+19
-14
@@ -1,12 +1,12 @@
|
||||
package com.sap.sailing.domain.common.scalablevalue.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.DoubleTriple;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
@@ -14,42 +14,47 @@ import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
* bearing is scaled separately, and the speed is scaled as a scalar value independently of the bearing. This is
|
||||
* particularly useful for {@link Wind} scaling where it makes more sense to average the wind speed independently of the
|
||||
* wind direction / bearing than adding up the "wind vectors" and averaging, which would reduce the resulting wind speed
|
||||
* for constant wind speeds across all fixes with different directions.
|
||||
* for constant wind speeds across all fixes with different directions.<p>
|
||||
*
|
||||
* The triple used for scaling uses the speed in knots as the first component, the sine as the second and the
|
||||
* cosine as the third value.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ScalableSpeedWithBearing implements ScalableValue<Util.Triple<Speed, Double, Double>, SpeedWithBearing> {
|
||||
private final Speed speed;
|
||||
public class ScalableSpeedWithBearing implements ScalableValue<DoubleTriple, SpeedWithBearing> {
|
||||
private final double speedInKnots;
|
||||
private final double sin;
|
||||
private final double cos;
|
||||
|
||||
public ScalableSpeedWithBearing(SpeedWithBearing speedWithBearing) {
|
||||
this(new KnotSpeedImpl(speedWithBearing.getKnots()), Math.sin(speedWithBearing.getBearing()
|
||||
this(speedWithBearing.getKnots(), Math.sin(speedWithBearing.getBearing()
|
||||
.getRadians()), Math.cos(speedWithBearing.getBearing().getRadians()));
|
||||
}
|
||||
|
||||
public ScalableSpeedWithBearing(Speed speed, double sin, double cos) {
|
||||
this.speed = speed;
|
||||
this(speed.getKnots(), sin, cos);
|
||||
}
|
||||
|
||||
private ScalableSpeedWithBearing(double speedInKnots, double sin, double cos) {
|
||||
this.speedInKnots = speedInKnots;
|
||||
this.sin = sin;
|
||||
this.cos = cos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableSpeedWithBearing multiply(double factor) {
|
||||
Speed newSpeed = new KnotSpeedImpl(factor*speed.getKnots());
|
||||
return new ScalableSpeedWithBearing(newSpeed, factor*sin, factor*cos);
|
||||
return new ScalableSpeedWithBearing(factor*speedInKnots, factor*sin, factor*cos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableSpeedWithBearing add(ScalableValue<Util.Triple<Speed, Double, Double>, SpeedWithBearing> t) {
|
||||
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() + t.getValue().getA().getKnots());
|
||||
return new ScalableSpeedWithBearing(newSpeed, sin+t.getValue().getB(), cos+t.getValue().getC());
|
||||
public ScalableSpeedWithBearing add(ScalableValue<DoubleTriple, SpeedWithBearing> t) {
|
||||
return new ScalableSpeedWithBearing(speedInKnots + t.getValue().getA(), sin+t.getValue().getB(), cos+t.getValue().getC());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing divide(double divisor) {
|
||||
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() / divisor);
|
||||
Speed newSpeed = new KnotSpeedImpl(speedInKnots / divisor);
|
||||
double angle;
|
||||
if (cos == 0) {
|
||||
angle = sin >= 0 ? Math.PI / 2 : -Math.PI / 2;
|
||||
@@ -61,8 +66,8 @@ public class ScalableSpeedWithBearing implements ScalableValue<Util.Triple<Speed
|
||||
}
|
||||
|
||||
@Override
|
||||
public Util.Triple<Speed, Double, Double> getValue() {
|
||||
return new Util.Triple<Speed, Double, Double>(speed, sin, cos);
|
||||
public DoubleTriple getValue() {
|
||||
return new DoubleTriple(speedInKnots, sin, cos);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-3
@@ -1,11 +1,10 @@
|
||||
package com.sap.sailing.domain.base;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.DoubleTriple;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.confidence.HasConfidence;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public interface SpeedWithBearingWithConfidence<RelativeTo> extends
|
||||
HasConfidence<Util.Triple<Speed, Double, Double>, SpeedWithBearing, RelativeTo> {
|
||||
HasConfidence<DoubleTriple, SpeedWithBearing, RelativeTo> {
|
||||
SpeedWithBearing getObject();
|
||||
}
|
||||
+4
-5
@@ -1,17 +1,16 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.DoubleTriple;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.confidence.impl.HasConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeedWithBearing;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.scalablevalue.IsScalable;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
public class SpeedWithBearingWithConfidenceImpl<RelativeTo> extends
|
||||
HasConfidenceImpl<Util.Triple<Speed, Double, Double>, SpeedWithBearing, RelativeTo> implements
|
||||
SpeedWithBearingWithConfidence<RelativeTo>, IsScalable<Util.Triple<Speed, Double, Double>, SpeedWithBearing> {
|
||||
HasConfidenceImpl<DoubleTriple, SpeedWithBearing, RelativeTo> implements
|
||||
SpeedWithBearingWithConfidence<RelativeTo>, IsScalable<DoubleTriple, SpeedWithBearing> {
|
||||
private static final long serialVersionUID = -4811576094614673625L;
|
||||
|
||||
public SpeedWithBearingWithConfidenceImpl(SpeedWithBearing speedWithBearing, double confidence, RelativeTo relativeTo) {
|
||||
@@ -24,7 +23,7 @@ public class SpeedWithBearingWithConfidenceImpl<RelativeTo> extends
|
||||
* angle.
|
||||
*/
|
||||
@Override
|
||||
public ScalableValue<Util.Triple<Speed, Double, Double>, SpeedWithBearing> getScalableValue() {
|
||||
public ScalableValue<DoubleTriple, SpeedWithBearing> getScalableValue() {
|
||||
return new ScalableSpeedWithBearing(getObject());
|
||||
}
|
||||
}
|
||||
@@ -1,447 +1,454 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feature
|
||||
id="com.sap.sailing.feature"
|
||||
label="SAP Sailing Server"
|
||||
version="1.0.0.qualifier"
|
||||
provider-name="SAP">
|
||||
|
||||
<description url="http://www.sap.com">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feature
|
||||
id="com.sap.sailing.feature"
|
||||
label="SAP Sailing Server"
|
||||
version="1.0.0.qualifier"
|
||||
provider-name="SAP">
|
||||
|
||||
<description url="http://www.sap.com">
|
||||
The SAP Sailing Server.
|
||||
|
||||
Provides connectivity to a TracTrac live GPS feed as well as a live feed from an Expedition system.
|
||||
Computes leaderboard information for sailing races and offers RESTful APIs to all of this.
|
||||
</description>
|
||||
|
||||
<copyright url="http://www.example.com/copyright">
|
||||
[Enter Copyright Description here.]
|
||||
</copyright>
|
||||
|
||||
<license url="http://www.example.com/license">
|
||||
[Enter License Description here.]
|
||||
</license>
|
||||
|
||||
<requires>
|
||||
<import plugin="com.googlecode.java-diff-utils" version="1.3.0" match="greaterOrEqual"/>
|
||||
<import plugin="org.eclipse.osgi" version="3.10.1" match="greaterOrEqual"/>
|
||||
<import plugin="javax.servlet" version="3.1.0" match="greaterOrEqual"/>
|
||||
<import plugin="com.mongodb.driver" version="2.6.2" match="greaterOrEqual"/>
|
||||
<import plugin="com.google.gwt.osgi" version="2.6.1" match="greaterOrEqual"/>
|
||||
<import plugin="org.json.simple" version="1.1.0" match="greaterOrEqual"/>
|
||||
<import plugin="org.moxieapps.gwt.highcharts" version="1.1.4" match="greaterOrEqual"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-jms_1.1_spec"/>
|
||||
<import plugin="com.rabbitmq.client"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec"/>
|
||||
</requires>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.geocoding"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.common"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.tractracadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.expeditionconnector"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.ess40"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.tractrac.clientmodule"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.declination"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingreplayadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.tractracadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security.ui"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security.userstore.mongodb"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.gwt.ui"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.udpconnector"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xmlexport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.simulator"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.www"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.www.events"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.kiworesultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.ess40.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.freg.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.barbados.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.sailwave.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.manage2sail.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.velum.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.monitoring"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xrr.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.igtimiadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.igtimiadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.racelogtrackingadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.deckmanadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.autoload"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.common"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.datamining"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.datamining.shared"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gateway"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gwt.adminconsole"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.mongodb"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.operationaltransformation"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.replication"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xrr.structureimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.serialization.shared.android"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.serialization"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.filestorage"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.shared.android"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.dashboards.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.mail"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.dashboards.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.datamining"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.datamining.shared"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
Computes leaderboard information for sailing races and offers RESTful APIs to all of this.
|
||||
</description>
|
||||
|
||||
<copyright url="http://www.example.com/copyright">
|
||||
[Enter Copyright Description here.]
|
||||
</copyright>
|
||||
|
||||
<license url="http://www.example.com/license">
|
||||
[Enter License Description here.]
|
||||
</license>
|
||||
|
||||
<requires>
|
||||
<import plugin="com.googlecode.java-diff-utils" version="1.3.0" match="greaterOrEqual"/>
|
||||
<import plugin="org.eclipse.osgi" version="3.10.1" match="greaterOrEqual"/>
|
||||
<import plugin="javax.servlet" version="3.1.0" match="greaterOrEqual"/>
|
||||
<import plugin="com.mongodb.driver" version="2.6.2" match="greaterOrEqual"/>
|
||||
<import plugin="com.google.gwt.osgi" version="2.6.1" match="greaterOrEqual"/>
|
||||
<import plugin="org.json.simple" version="1.1.0" match="greaterOrEqual"/>
|
||||
<import plugin="org.moxieapps.gwt.highcharts" version="1.1.4" match="greaterOrEqual"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-jms_1.1_spec"/>
|
||||
<import plugin="com.rabbitmq.client"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec"/>
|
||||
</requires>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.geocoding"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.common"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.tractracadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.expeditionconnector"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.ess40"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.tractrac.clientmodule"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.declination"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.swisstimingreplayadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.tractracadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security.ui"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.security.userstore.mongodb"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.gwt.ui"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.udpconnector"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xmlexport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.simulator"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.www"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.www.events"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.kiworesultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.ess40.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.freg.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.barbados.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.sailwave.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.manage2sail.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.velum.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.monitoring"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xrr.resultimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.igtimiadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.igtimiadapter.persistence"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.racelogtrackingadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.deckmanadapter"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.autoload"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.common"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.datamining"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.datamining.shared"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gateway"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.gwt.adminconsole"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.mongodb"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.operationaltransformation"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.replication"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.xrr.structureimport"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.serialization.shared.android"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.server.gateway.serialization"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.filestorage"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.shared.android"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.dashboards.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.mail"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.dashboards.gwt"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.datamining"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.datamining.shared"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sse.threadmanager"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
@@ -567,13 +567,17 @@ img.openColumn {
|
||||
background-color: white;
|
||||
background-image: url(images/viewicons/@1x/img/SAP_RV_AudioVideo_INACTIVE.png);
|
||||
background-repeat: no-repeat, no-repeat;
|
||||
background-position: 4% 50%, 96% 50%
|
||||
background-position: 10% 50%, 90% 50%
|
||||
}
|
||||
|
||||
.gwt-SplitLayoutPanel-NorthSouthToggleButton-mediaplaying {
|
||||
background-image: url(images/viewicons/@1x/img/SAP_RV_AudioVideo_GHOSTED.png);
|
||||
}
|
||||
|
||||
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Small-media {
|
||||
background-position: 50% 50%, 100% 50% !important;
|
||||
background-position: 5% 50%, 100% 50% !important;
|
||||
margin-left: 0px !important;
|
||||
padding: 2px 20px !important;
|
||||
padding: 2px 35px !important;
|
||||
}
|
||||
|
||||
@external gwt-ToggleButton-up, gwt-ToggleButton-down, gwt-ToggleButton-up-hovering, gwt-ToggleButton-down-hovering;
|
||||
|
||||
+7
@@ -128,6 +128,8 @@ public class DetailTypeFormatter {
|
||||
return stringMessages.distanceToLine();
|
||||
case BEAT_ANGLE:
|
||||
return stringMessages.beatAngle();
|
||||
case COURSE_OVER_GROUND_TRUE_DEGREES:
|
||||
return stringMessages.courseOverGroundTrueDegrees();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -172,6 +174,9 @@ public class DetailTypeFormatter {
|
||||
case RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START:
|
||||
case DISTANCE_TO_START_LINE:
|
||||
return stringMessages.metersUnit();
|
||||
|
||||
case COURSE_OVER_GROUND_TRUE_DEGREES:
|
||||
return stringMessages.degreesShort();
|
||||
|
||||
case GAP_TO_LEADER_IN_SECONDS:
|
||||
case GAP_CHANGE_SINCE_LEG_START_IN_SECONDS:
|
||||
@@ -342,6 +347,8 @@ public class DetailTypeFormatter {
|
||||
return stringMessages.beatAngleTooltip();
|
||||
case DISTANCE_TO_START_LINE:
|
||||
return "";
|
||||
case COURSE_OVER_GROUND_TRUE_DEGREES:
|
||||
return stringMessages.courseOverGroundTrueDegreesTooltip();
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
+8
@@ -1091,6 +1091,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String raceIsInLiveTimePanelMode();
|
||||
String backToLiveTimePanelMode();
|
||||
String windChart();
|
||||
String mediaNoVideosCaption();
|
||||
String mediaShowVideoCaption();
|
||||
String mediaShowVideoTooltip(String title);
|
||||
String mediaHideVideoCaption();
|
||||
@@ -1160,4 +1161,11 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String showCompetitorFullNameColumn();
|
||||
String loadingDimensionValues();
|
||||
String runningQuery();
|
||||
String courseOverGroundTrueDegreesTooltip();
|
||||
String courseOverGroundTrueDegrees();
|
||||
String results();
|
||||
String group();
|
||||
String valueAscending();
|
||||
String valueDescending();
|
||||
String sortBy();
|
||||
}
|
||||
+10
-2
@@ -1071,12 +1071,13 @@ leaderboardGroupNotContainedInEvent=The leaderboard group {0} is not contained i
|
||||
raceIsInLiveTimePanelMode=Race is Live
|
||||
backToLiveTimePanelMode=Back to Live
|
||||
windChart=Wind Chart
|
||||
mediaNoVideosCaption=No Videos
|
||||
mediaShowVideoCaption=Show Video
|
||||
mediaShowVideoTooltip=Click to show video: {0}
|
||||
mediaHideVideoCaption=Hide Video
|
||||
mediaHideVideoTooltip=Click to hide video
|
||||
mediaSelectVideoCaption={0} Videos
|
||||
mediaSelectVideoTooltip=Click to select video
|
||||
mediaSelectVideoTooltip=Click to select video
|
||||
mediaManageMediaCaption=Manage Media
|
||||
mediaManageMediaTooltip=Configure audio and video clips, synchronize times
|
||||
showAll=Show all
|
||||
@@ -1139,4 +1140,11 @@ fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your
|
||||
showCompetitorSailIdColumn=Show Competitor Sail Id
|
||||
showCompetitorFullNameColumn=Show Competitor Full Name
|
||||
loadingDimensionValues=Loading dimension values
|
||||
runningQuery=Running Query
|
||||
runningQuery=Running Query
|
||||
courseOverGroundTrueDegreesTooltip=True course over ground in degrees
|
||||
courseOverGroundTrueDegrees=COG
|
||||
results=Results
|
||||
group=Group
|
||||
valueAscending=Value (Ascending)
|
||||
valueDescending=Value (Descending)
|
||||
sortBy=Sort by
|
||||
+9
-1
@@ -1066,6 +1066,7 @@ leaderboardGroupNotContainedInEvent=Die Wettfahrtgruppe {0} gehört nicht zur Ve
|
||||
raceIsInLiveTimePanelMode=Rennen ist live
|
||||
backToLiveTimePanelMode=Zurück zu live
|
||||
windChart=Wind Chart
|
||||
mediaNoVideosCaption=Keine Videos
|
||||
mediaShowVideoCaption=Video ein
|
||||
mediaShowVideoTooltip=Video abspielen: {0}
|
||||
mediaHideVideoCaption=Video aus
|
||||
@@ -1129,4 +1130,11 @@ fileUploadResult=Ergebnis des Hochladens: {0} {1}\nIm Fehlerfall bitte die Konfi
|
||||
showCompetitorSailIdColumn=Sail Id anzeigen
|
||||
showCompetitorFullNameColumn=Vollen Namen anzeigen
|
||||
loadingDimensionValues=Lade Dimensionswerte
|
||||
runningQuery=Datenabfrage läuft
|
||||
runningQuery=Datenabfrage läuft
|
||||
courseOverGroundTrueDegreesTooltip=Rechtweisender Kurs über Grund in Grad
|
||||
courseOverGroundTrueDegrees=KüG
|
||||
results=Ergebnisse
|
||||
group=Gruppe
|
||||
valueAscending=Wert (Aufsteigend)
|
||||
valueDescending=Wert (Absteigend)
|
||||
sortBy=Sortiert nach
|
||||
+9
-1
@@ -1019,6 +1019,7 @@ leaderboardGroupNotContainedInEvent=The leaderboard group {0} is not contained i
|
||||
raceIsInLiveTimePanelMode=Race is Live
|
||||
backToLiveTimePanelMode=Back to Live
|
||||
windChart=Wind Chart
|
||||
mediaNoVideosCaption=No Videos
|
||||
mediaShowVideoCaption=Show Video
|
||||
mediaShowVideoTooltip=Click to show video: {0}
|
||||
mediaHideVideoCaption=Hide Video
|
||||
@@ -1078,4 +1079,11 @@ fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your
|
||||
showCompetitorSailIdColumn=Show Competitor Sail Id
|
||||
showCompetitorFullNameColumn=Show Competitor Full Name
|
||||
loadingDimensionValues=Loading dimension values
|
||||
runningQuery=Running Query
|
||||
runningQuery=Running Query
|
||||
courseOverGroundTrueDegreesTooltip=True course over ground in degrees
|
||||
courseOverGroundTrueDegrees=COG
|
||||
results=Results
|
||||
group=Group
|
||||
valueAscending=Value (Ascending)
|
||||
valueDescending=Value (Descending)
|
||||
sortBy=Sort by
|
||||
+2
-1
@@ -61,8 +61,9 @@ public class VideoFloatingContainer extends AbstractVideoContainer implements Vi
|
||||
dialogBox.show();
|
||||
|
||||
int absoluteTop = popupPositionProvider.getYPositionUiObject().getAbsoluteTop();
|
||||
int posY = absoluteTop -300;
|
||||
int posY = absoluteTop - 300;
|
||||
dialogBox.setPopupPosition(5, posY);
|
||||
dialogBox.setPixelSize(videoPlayer.getDefaultWidth(), videoPlayer.getDefaultHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
@@ -86,5 +86,15 @@ public class VideoHtmlPlayer extends AbstractHtmlMediaPlayer implements VideoSyn
|
||||
public void setEditFlag(EditFlag editFlag) {
|
||||
this.editFlag = editFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultWidth() {
|
||||
return 400;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultHeight() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -259,4 +259,14 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements VideoSync
|
||||
return editFlag != null && editFlag.isEditing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultWidth() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultHeight() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -6,4 +6,8 @@ public interface VideoSynchPlayer extends VideoPlayerWithWidget, MediaSynchAdapt
|
||||
|
||||
void setEditFlag(EditFlag editFlag);
|
||||
|
||||
int getDefaultWidth();
|
||||
|
||||
int getDefaultHeight();
|
||||
|
||||
}
|
||||
+1
@@ -34,6 +34,7 @@ public class MultiCompetitorRaceChartSettingsComponent extends AbstractChartSett
|
||||
availableDetailsTypes.add(DetailType.REGATTA_RANK);
|
||||
availableDetailsTypes.add(DetailType.DISTANCE_TO_START_LINE);
|
||||
availableDetailsTypes.add(DetailType.BEAT_ANGLE);
|
||||
availableDetailsTypes.add(DetailType.COURSE_OVER_GROUND_TRUE_DEGREES);
|
||||
|
||||
if (hasOverallLeaderboard) {
|
||||
availableDetailsTypes.add(DetailType.OVERALL_RANK);
|
||||
|
||||
+11
-4
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.gwt.ui.datamining;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
@@ -24,6 +26,8 @@ import com.sap.sailing.gwt.ui.datamining.presentation.BenchmarkResultsPanel;
|
||||
import com.sap.sailing.gwt.ui.datamining.presentation.ResultsChart;
|
||||
import com.sap.sailing.gwt.ui.datamining.selection.BufferingQueryDefinitionProviderWithControls;
|
||||
import com.sap.sailing.gwt.ui.datamining.settings.QueryRunnerSettings;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.impl.UUIDDataMiningSession;
|
||||
import com.sap.sse.gwt.client.EntryPointHelper;
|
||||
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
|
||||
|
||||
@@ -31,11 +35,14 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
|
||||
private static DataMiningResources resources = GWT.create(DataMiningResources.class);
|
||||
|
||||
private final DataMiningServiceAsync dataMiningService = GWT.create(DataMiningService.class);
|
||||
|
||||
private DataMiningSession session;
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
super.doOnModuleLoad();
|
||||
|
||||
session = new UUIDDataMiningSession(UUID.randomUUID());
|
||||
|
||||
EntryPointHelper.registerASyncService((ServiceDefTarget) dataMiningService, RemoteServiceMappingConstants.dataMiningServiceRemotePath);
|
||||
|
||||
RootLayoutPanel rootPanel = RootLayoutPanel.get();
|
||||
@@ -44,13 +51,13 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
|
||||
|
||||
DockLayoutPanel dockPanel = new DockLayoutPanel(Unit.PX);
|
||||
dockPanel.addNorth(createLogoAndTitlePanel(), 68);
|
||||
BufferingQueryDefinitionProviderWithControls queryDefinitionProviderWithControls = new BufferingQueryDefinitionProviderWithControls(getStringMessages(), sailingService, dataMiningService, this);
|
||||
BufferingQueryDefinitionProviderWithControls queryDefinitionProviderWithControls = new BufferingQueryDefinitionProviderWithControls(session, getStringMessages(), sailingService, dataMiningService, this);
|
||||
queryDefinitionProviderWithControls.getEntryWidget().addStyleName("dataMiningPanel");
|
||||
dockPanel.add(queryDefinitionProviderWithControls.getEntryWidget());
|
||||
|
||||
ResultsPresenter<Number> resultsPresenter = new ResultsChart(getStringMessages());
|
||||
if (GwtHttpRequestUtils.getBooleanParameter("benchmark", false)) {
|
||||
BenchmarkResultsPanel benchmarkResultsPanel = new BenchmarkResultsPanel(getStringMessages(), dataMiningService, this, queryDefinitionProviderWithControls);
|
||||
BenchmarkResultsPanel benchmarkResultsPanel = new BenchmarkResultsPanel(session, getStringMessages(), dataMiningService, this, queryDefinitionProviderWithControls);
|
||||
splitPanel.addSouth(benchmarkResultsPanel, 500);
|
||||
} else {
|
||||
splitPanel.addSouth(resultsPresenter.getWidget(), 400);
|
||||
@@ -58,7 +65,7 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
|
||||
|
||||
splitPanel.add(dockPanel);
|
||||
|
||||
QueryRunner queryRunner = new SimpleQueryRunner(getStringMessages(), dataMiningService, this, queryDefinitionProviderWithControls, resultsPresenter);
|
||||
QueryRunner queryRunner = new SimpleQueryRunner(session, getStringMessages(), dataMiningService, this, queryDefinitionProviderWithControls, resultsPresenter);
|
||||
queryDefinitionProviderWithControls.addControl(queryRunner.getEntryWidget());
|
||||
queryDefinitionProviderWithControls.addControl(createSettingsControlWidget(queryRunner, queryDefinitionProviderWithControls));
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.sap.sailing.datamining.shared.SailingDataMiningSerializationDummy;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.SSEDataMiningSerializationDummy;
|
||||
@@ -19,9 +20,9 @@ public interface DataMiningService extends RemoteService {
|
||||
|
||||
Iterable<DataRetrieverChainDefinitionDTO> getDataRetrieverChainDefinitionsFor(FunctionDTO statisticToCalculate, String localeInfoName);
|
||||
|
||||
QueryResult<Set<Object>> getDimensionValuesFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName) throws Exception;
|
||||
QueryResult<Set<Object>> getDimensionValuesFor(DataMiningSession session, DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName);
|
||||
|
||||
<ResultType extends Number> QueryResult<ResultType> runQuery(QueryDefinitionDTO queryDefinition) throws Exception;
|
||||
<ResultType extends Number> QueryResult<ResultType> runQuery(DataMiningSession session, QueryDefinitionDTO queryDefinition);
|
||||
|
||||
SSEDataMiningSerializationDummy pseudoMethodSoThatSomeSSEDataMiningClassesAreAddedToTheGWTSerializationPolicy();
|
||||
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.datamining.shared.SailingDataMiningSerializationDummy;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.SSEDataMiningSerializationDummy;
|
||||
@@ -22,9 +23,9 @@ public interface DataMiningServiceAsync {
|
||||
void getDataRetrieverChainDefinitionsFor(FunctionDTO statisticToCalculate, String localeInfoName,
|
||||
AsyncCallback<Iterable<DataRetrieverChainDefinitionDTO>> callback);
|
||||
|
||||
void getDimensionValuesFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName, AsyncCallback<QueryResult<Set<Object>>> callback);
|
||||
void getDimensionValuesFor(DataMiningSession session, DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName, AsyncCallback<QueryResult<Set<Object>>> callback);
|
||||
|
||||
<ResultType extends Number> void runQuery(QueryDefinitionDTO queryDefinition, AsyncCallback<QueryResult<ResultType>> callback);
|
||||
<ResultType extends Number> void runQuery(DataMiningSession session, QueryDefinitionDTO queryDefinition, AsyncCallback<QueryResult<ResultType>> callback);
|
||||
|
||||
/**
|
||||
* This method does nothing, but is needed to ensure, that some classes for the data mining
|
||||
|
||||
+16
-4
@@ -13,25 +13,30 @@ import com.sap.sailing.gwt.ui.datamining.QueryRunner;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sailing.gwt.ui.datamining.settings.QueryRunnerSettings;
|
||||
import com.sap.sailing.gwt.ui.datamining.settings.QueryRunnerSettingsDialogComponent;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
public class SimpleQueryRunner implements QueryRunner {
|
||||
|
||||
private final DataMiningSession session;
|
||||
private final StringMessages stringMessages;
|
||||
private final DataMiningServiceAsync dataMiningService;
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
private final Button runButton;
|
||||
|
||||
private QueryRunnerSettings settings;
|
||||
private final QueryDefinitionProvider queryDefinitionProvider;
|
||||
private final ResultsPresenter<Number> resultsPresenter;
|
||||
|
||||
private final Button runButton;
|
||||
private int sentQueriesNumber;
|
||||
|
||||
public SimpleQueryRunner(StringMessages stringMessages, DataMiningServiceAsync dataMiningService,
|
||||
public SimpleQueryRunner(DataMiningSession session, StringMessages stringMessages, DataMiningServiceAsync dataMiningService,
|
||||
ErrorReporter errorReporter, QueryDefinitionProvider queryDefinitionProvider,
|
||||
ResultsPresenter<Number> resultsPresenter) {
|
||||
this.session = session;
|
||||
this.stringMessages = stringMessages;
|
||||
this.dataMiningService = dataMiningService;
|
||||
this.errorReporter = errorReporter;
|
||||
@@ -51,14 +56,17 @@ public class SimpleQueryRunner implements QueryRunner {
|
||||
if (this.settings.isRunAutomatically()) {
|
||||
queryDefinitionProvider.addQueryDefinitionChangedListener(this);
|
||||
}
|
||||
|
||||
sentQueriesNumber = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(QueryDefinitionDTO queryDefinition) {
|
||||
Iterable<String> errorMessages = queryDefinitionProvider.validateQueryDefinition(queryDefinition);
|
||||
if (errorMessages == null || !errorMessages.iterator().hasNext()) {
|
||||
sentQueriesNumber++;
|
||||
resultsPresenter.showBusyIndicator();
|
||||
dataMiningService.runQuery(queryDefinition, new AsyncCallback<QueryResult<Number>>() {
|
||||
dataMiningService.runQuery(session, queryDefinition, new AsyncCallback<QueryResult<Number>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error running the query: " + caught.getMessage());
|
||||
@@ -67,7 +75,11 @@ public class SimpleQueryRunner implements QueryRunner {
|
||||
|
||||
@Override
|
||||
public void onSuccess(QueryResult<Number> result) {
|
||||
resultsPresenter.showResult(result);
|
||||
sentQueriesNumber--;
|
||||
//Don't show the empty result, if more Queries have been sent
|
||||
if (!result.isEmpty() || sentQueriesNumber == 0) {
|
||||
resultsPresenter.showResult(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
+6
-3
@@ -11,11 +11,13 @@ import com.google.gwt.user.client.ui.Label;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.datamining.QueryDefinitionProvider;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
public class BenchmarkResultsPanel extends FlowPanel {
|
||||
|
||||
|
||||
private final DataMiningSession session;
|
||||
private DataMiningServiceAsync dataMiningService;
|
||||
private ErrorReporter errorReporter;
|
||||
private StringMessages stringMessages;
|
||||
@@ -25,9 +27,10 @@ public class BenchmarkResultsPanel extends FlowPanel {
|
||||
private Label benchmarkStatusLabel;
|
||||
private BenchmarkResultsChart resultsChart;
|
||||
|
||||
public BenchmarkResultsPanel(StringMessages stringMessages, DataMiningServiceAsync dataMiningService,
|
||||
public BenchmarkResultsPanel(DataMiningSession session, StringMessages stringMessages, DataMiningServiceAsync dataMiningService,
|
||||
ErrorReporter errorReporter, QueryDefinitionProvider queryDefinitionProvider) {
|
||||
super();
|
||||
this.session = session;
|
||||
this.dataMiningService = dataMiningService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringMessages = stringMessages;
|
||||
@@ -48,7 +51,7 @@ public class BenchmarkResultsPanel extends FlowPanel {
|
||||
|
||||
private void runQuery(final ClientBenchmarkData benchmarkData) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
dataMiningService.runQuery(queryDefinitionProvider.getQueryDefinition(), new AsyncCallback<QueryResult<Number>>() {
|
||||
dataMiningService.runQuery(session, queryDefinitionProvider.getQueryDefinition(), new AsyncCallback<QueryResult<Number>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error running a query: " + caught.getMessage());
|
||||
|
||||
+182
-96
@@ -3,9 +3,12 @@ package com.sap.sailing.gwt.ui.datamining.presentation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.ChartSubtitle;
|
||||
@@ -17,45 +20,120 @@ import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.ToolTip;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsData;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsFormatter;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.XAxisLabels;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.YAxisLabels;
|
||||
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.text.shared.AbstractRenderer;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ValueListBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.panels.ResizingFlowPanel;
|
||||
import com.sap.sailing.gwt.ui.client.shared.panels.ResizingSimplePanel;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
|
||||
public class ResultsChart implements ResultsPresenter<Number> {
|
||||
|
||||
|
||||
private final Comparator<GroupKey> standardKeyComparator = new Comparator<GroupKey>() {
|
||||
@Override
|
||||
public int compare(GroupKey key1, GroupKey key2) {
|
||||
return key1.compareTo(key2);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.group();
|
||||
};
|
||||
};
|
||||
private final Comparator<GroupKey> ascendingByValueKeyComparator = new Comparator<GroupKey>() {
|
||||
@Override
|
||||
public int compare(GroupKey key1, GroupKey key2) {
|
||||
Map<GroupKey, ? extends Number> resultData = currentResult.getResults();
|
||||
double doubleValue1 = resultData.get(key1).doubleValue();
|
||||
double doubleValue2 = resultData.get(key2).doubleValue();
|
||||
return Double.compare(doubleValue1, doubleValue2);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.valueAscending();
|
||||
};
|
||||
};
|
||||
private final Comparator<GroupKey> descendingByValueKeyComparator = new Comparator<GroupKey>() {
|
||||
@Override
|
||||
public int compare(GroupKey key1, GroupKey key2) {
|
||||
return -1 * ascendingByValueKeyComparator.compare(key1, key2);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.valueDescending();
|
||||
};
|
||||
};
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private final SimplePanel mainPanel;
|
||||
private final FlowPanel mainPanel;
|
||||
|
||||
private final HorizontalPanel sortByPanel;
|
||||
private final ValueListBox<Comparator<GroupKey>> keyComparatorListBox;
|
||||
|
||||
private final ResizingSimplePanel presentationPanel;
|
||||
private final Chart chart;
|
||||
private Map<GroupKey, Series> series;
|
||||
|
||||
private Map<GroupKey, Integer> mainKeyToValueMap;
|
||||
private Map<Integer, GroupKey> valueToGroupKeyMap;
|
||||
|
||||
private final HTML errorLabel;
|
||||
|
||||
private final HTML labeledBusyIndicator;
|
||||
|
||||
private Map<GroupKey, Series> seriesMappedByGroupKey;
|
||||
private final GroupKey simpleResultSeriesKey;
|
||||
private QueryResult<? extends Number> currentResult;
|
||||
private Map<GroupKey, Integer> mainKeyToXValueMap;
|
||||
|
||||
public ResultsChart(StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
mainPanel = new ResizingSimplePanel() {
|
||||
|
||||
mainPanel = new ResizingFlowPanel() {
|
||||
@Override
|
||||
public void onResize() {
|
||||
presentationPanel.onResize();
|
||||
}
|
||||
};
|
||||
|
||||
sortByPanel = new HorizontalPanel();
|
||||
sortByPanel.setSpacing(5);
|
||||
sortByPanel.setVisible(false);
|
||||
mainPanel.add(sortByPanel);
|
||||
sortByPanel.add(new Label(stringMessages.sortBy()));
|
||||
keyComparatorListBox = new ValueListBox<>(new AbstractRenderer<Comparator<?>>() {
|
||||
@Override
|
||||
public String render(Comparator<?> object) {
|
||||
return object.toString();
|
||||
}
|
||||
});
|
||||
keyComparatorListBox.addValueChangeHandler(new ValueChangeHandler<Comparator<GroupKey>>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Comparator<GroupKey>> event) {
|
||||
resetChartSeries();
|
||||
showResultData();
|
||||
}
|
||||
});
|
||||
sortByPanel.add(keyComparatorListBox);
|
||||
|
||||
presentationPanel = new ResizingSimplePanel() {
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
chart.redraw();
|
||||
}
|
||||
};
|
||||
mainPanel.add(presentationPanel);
|
||||
|
||||
chart = createChart();
|
||||
series = new HashMap<GroupKey, Series>();
|
||||
seriesMappedByGroupKey = new HashMap<GroupKey, Series>();
|
||||
simpleResultSeriesKey = new GenericGroupKey<String>(stringMessages.results());
|
||||
|
||||
errorLabel = new HTML();
|
||||
errorLabel.setStyleName("chart-importantMessage");
|
||||
@@ -68,8 +146,9 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
currentResult = null;
|
||||
errorLabel.setHTML(error);
|
||||
mainPanel.setWidget(errorLabel);
|
||||
presentationPanel.setWidget(errorLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,108 +163,125 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
|
||||
@Override
|
||||
public void showBusyIndicator() {
|
||||
mainPanel.setWidget(labeledBusyIndicator);
|
||||
currentResult = null;
|
||||
presentationPanel.setWidget(labeledBusyIndicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<Number> result) {
|
||||
if (!result.isEmpty()) {
|
||||
resetChart();
|
||||
|
||||
updateYAxisLabels(result);
|
||||
updateChartSubtitleAndSetChartAsWidget(result);
|
||||
|
||||
List<GroupKey> sortedKeys = getSortedKeysFrom(result);
|
||||
buildGroupKeyValueMaps(sortedKeys);
|
||||
if (resultHasComplexKeys(result)) {
|
||||
displayComplexResult(result, sortedKeys);
|
||||
} else {
|
||||
displaySimpleResult(result, sortedKeys);
|
||||
}
|
||||
|
||||
chart.redraw();
|
||||
if (result != null && !result.isEmpty()) {
|
||||
currentResult = result;
|
||||
updateKeyComparatorListBox();
|
||||
resetChartSeries();
|
||||
updateYAxisLabels();
|
||||
updateChartSubtitleAndSetChartAsWidget();
|
||||
showResultData();
|
||||
} else {
|
||||
showError(stringMessages.noDataFound() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateYAxisLabels(QueryResult<? extends Number> result) {
|
||||
chart.getYAxis().setAxisTitleText(result.getResultSignifier());
|
||||
chart.setToolTip(new ToolTip().setValueDecimals(result.getValueDecimals()).setValueSuffix(
|
||||
result.getUnitSignifier()));
|
||||
private void updateKeyComparatorListBox() {
|
||||
boolean visible = false;
|
||||
Comparator<GroupKey> valueToBeSelected = standardKeyComparator;
|
||||
Collection<Comparator<GroupKey>> acceptableValues = new ArrayList<>();
|
||||
acceptableValues.add(valueToBeSelected);
|
||||
if (currentResult != null && isCurrentResultSimple()) {
|
||||
valueToBeSelected = getKeyComparator() != null ? getKeyComparator() : valueToBeSelected;
|
||||
acceptableValues.add(ascendingByValueKeyComparator);
|
||||
acceptableValues.add(descendingByValueKeyComparator);
|
||||
visible = true;
|
||||
}
|
||||
keyComparatorListBox.setValue(valueToBeSelected);
|
||||
keyComparatorListBox.setAcceptableValues(acceptableValues);
|
||||
sortByPanel.setVisible(visible);
|
||||
}
|
||||
|
||||
private boolean resultHasComplexKeys(QueryResult<? extends Number> result) {
|
||||
for (GroupKey key : result.getResults().keySet()) {
|
||||
if (key.hasSubKey()) {
|
||||
return true;
|
||||
private boolean isCurrentResultSimple() {
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
if (groupKey.hasSubKey()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void displayComplexResult(QueryResult<? extends Number> result, List<GroupKey> sortedKeys) {
|
||||
Map<Series, Boolean> isInChart = new HashMap<Series, Boolean>();
|
||||
for (GroupKey key : sortedKeys) {
|
||||
Point point = new Point(mainKeyToValueMap.get(key.getMainKey()), result.getResults().get(key));
|
||||
point.setName(key.getMainKey().asString());
|
||||
Series series = getOrCreateSeries(key).addPoint(point, false, false, false);
|
||||
if (isInChart.get(series) == null || !isInChart.get(series)) {
|
||||
chart.addSeries(series, false, false);
|
||||
isInChart.put(series, true);
|
||||
}
|
||||
}
|
||||
private void resetChartSeries() {
|
||||
chart.removeAllSeries(false);
|
||||
seriesMappedByGroupKey = new HashMap<GroupKey, Series>();
|
||||
}
|
||||
|
||||
private void displaySimpleResult(QueryResult<? extends Number> result, List<GroupKey> sortedKeys) {
|
||||
Series series = chart.createSeries().setName("Results");
|
||||
for (GroupKey key : sortedKeys) {
|
||||
Point point = new Point(mainKeyToValueMap.get(key.getMainKey()), result.getResults().get(key));
|
||||
point.setName(key.getMainKey().asString());
|
||||
series.addPoint(point, false, false, false);
|
||||
}
|
||||
chart.addSeries(series, false, false);
|
||||
private void updateYAxisLabels() {
|
||||
chart.getYAxis().setAxisTitleText(currentResult.getResultSignifier());
|
||||
chart.setToolTip(new ToolTip().setValueDecimals(currentResult.getValueDecimals()).setValueSuffix(
|
||||
currentResult.getUnitSignifier()));
|
||||
}
|
||||
|
||||
private void updateChartSubtitleAndSetChartAsWidget(QueryResult<? extends Number> result) {
|
||||
private void updateChartSubtitleAndSetChartAsWidget() {
|
||||
chart.setChartSubtitle(new ChartSubtitle().setText(stringMessages.queryResultsChartSubtitle(
|
||||
result.getRetrievedDataAmount(), result.getCalculationTimeInSeconds())));
|
||||
currentResult.getRetrievedDataAmount(), currentResult.getCalculationTimeInSeconds())));
|
||||
// This is needed, so that the subtitle is updated. Otherwise the text would stay empty
|
||||
mainPanel.setWidget(null);
|
||||
mainPanel.setWidget(chart);
|
||||
presentationPanel.setWidget(null);
|
||||
presentationPanel.setWidget(chart);
|
||||
}
|
||||
|
||||
public List<GroupKey> getSortedKeysFrom(QueryResult<? extends Number> result) {
|
||||
List<GroupKey> sortedKeys = new ArrayList<GroupKey>(result.getResults().keySet());
|
||||
Collections.sort(sortedKeys);
|
||||
private void showResultData() {
|
||||
buildMainKeyMapAndSetXAxisCategories();
|
||||
createAndAddSeriesToChart();
|
||||
|
||||
for (Entry<GroupKey, ? extends Number> resultEntry : currentResult.getResults().entrySet()) {
|
||||
GroupKey mainKey = resultEntry.getKey().getMainKey();
|
||||
Point point = new Point(mainKeyToXValueMap.get(mainKey), resultEntry.getValue());
|
||||
point.setName(mainKey.asString());
|
||||
seriesMappedByGroupKey.get(groupKeyToSeriesKey(resultEntry.getKey()))
|
||||
.addPoint(point, false, false, false);
|
||||
}
|
||||
|
||||
chart.redraw();
|
||||
}
|
||||
|
||||
private void buildMainKeyMapAndSetXAxisCategories() {
|
||||
List<GroupKey> sortedMainKeys = getSortedMainKeys();
|
||||
String[] categories = new String[sortedMainKeys.size()];
|
||||
mainKeyToXValueMap = new HashMap<>();
|
||||
for (int i = 0; i < sortedMainKeys.size(); i++) {
|
||||
GroupKey mainKey = sortedMainKeys.get(i);
|
||||
categories[i] = mainKey.asString();
|
||||
mainKeyToXValueMap.put(mainKey, i);
|
||||
}
|
||||
chart.getXAxis().setCategories(false, categories);
|
||||
}
|
||||
|
||||
public List<GroupKey> getSortedMainKeys() {
|
||||
Collection<GroupKey> mainKeySet = new HashSet<>();
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
mainKeySet.add(groupKey.getMainKey());
|
||||
}
|
||||
List<GroupKey> sortedKeys = new ArrayList<>(mainKeySet);
|
||||
Collections.sort(sortedKeys, getKeyComparator());
|
||||
return sortedKeys;
|
||||
}
|
||||
|
||||
private void buildGroupKeyValueMaps(Collection<GroupKey> keys) {
|
||||
mainKeyToValueMap = new HashMap<GroupKey, Integer>();
|
||||
valueToGroupKeyMap = new HashMap<Integer, GroupKey>();
|
||||
int index = 0;
|
||||
for (GroupKey groupKey : keys) {
|
||||
if (!mainKeyToValueMap.containsKey(groupKey.getMainKey())) {
|
||||
mainKeyToValueMap.put(groupKey.getMainKey(), index);
|
||||
valueToGroupKeyMap.put(index, groupKey.getMainKey());
|
||||
index++;
|
||||
private Comparator<GroupKey> getKeyComparator() {
|
||||
return keyComparatorListBox.getValue();
|
||||
}
|
||||
|
||||
private void createAndAddSeriesToChart() {
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
GroupKey seriesKey = groupKeyToSeriesKey(groupKey);
|
||||
if (!seriesMappedByGroupKey.containsKey(seriesKey)) {
|
||||
seriesMappedByGroupKey.put(seriesKey, chart.createSeries().setName(seriesKey.asString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Series getOrCreateSeries(GroupKey groupKey) {
|
||||
GroupKey key = groupKey.hasSubKey() ? groupKey.getSubKey() : groupKey;
|
||||
|
||||
if (!series.containsKey(key)) {
|
||||
series.put(key, chart.createSeries().setName(key.asString()));
|
||||
List<GroupKey> sortedSeriesKeys = new ArrayList<>(seriesMappedByGroupKey.keySet());
|
||||
Collections.sort(sortedSeriesKeys);
|
||||
for (GroupKey seriesKey : sortedSeriesKeys) {
|
||||
chart.addSeries(seriesMappedByGroupKey.get(seriesKey), false, false);
|
||||
}
|
||||
return series.get(key);
|
||||
}
|
||||
|
||||
private void resetChart() {
|
||||
chart.removeAllSeries(false);
|
||||
series = new HashMap<GroupKey, Series>();
|
||||
|
||||
private GroupKey groupKeyToSeriesKey(GroupKey groupKey) {
|
||||
return groupKey.hasSubKey() ? groupKey.getSubKey() : simpleResultSeriesKey;
|
||||
}
|
||||
|
||||
private Chart createChart() {
|
||||
@@ -200,17 +296,7 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
.setCredits(new Credits().setEnabled(false))
|
||||
.setChartTitle(new ChartTitle().setText(stringMessages.dataMiningResult()));
|
||||
|
||||
chart.getXAxis().setAllowDecimals(false).setLabels(new XAxisLabels().setFormatter(new AxisLabelsFormatter() {
|
||||
@Override
|
||||
public String format(AxisLabelsData axisLabelsData) {
|
||||
try {
|
||||
Integer value = (int) axisLabelsData.getValueAsDouble();
|
||||
return valueToGroupKeyMap.get(value).asString();
|
||||
} catch (Exception e) {
|
||||
return "error formatting label";
|
||||
}
|
||||
}
|
||||
}));
|
||||
chart.getXAxis().setAllowDecimals(false);
|
||||
|
||||
chart.getYAxis().setAxisTitleText("Result").setLabels(new YAxisLabels().setFormatter(new AxisLabelsFormatter() {
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -27,6 +27,7 @@ import com.sap.sailing.gwt.ui.datamining.SelectionChangedListener;
|
||||
import com.sap.sailing.gwt.ui.datamining.SelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.datamining.StatisticChangedListener;
|
||||
import com.sap.sailing.gwt.ui.datamining.StatisticProvider;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.components.AggregatorType;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
@@ -56,7 +57,7 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
|
||||
|
||||
private SelectionProvider<?> selectionProvider;
|
||||
|
||||
public BufferingQueryDefinitionProviderWithControls(StringMessages stringMessages, SailingServiceAsync sailingService, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter) {
|
||||
public BufferingQueryDefinitionProviderWithControls(DataMiningSession session, StringMessages stringMessages, SailingServiceAsync sailingService, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter) {
|
||||
super(stringMessages, sailingService, dataMiningService, errorReporter);
|
||||
|
||||
mainPanel = new ResizingFlowPanel() {
|
||||
@@ -71,7 +72,7 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
|
||||
|
||||
mainPanel.add(createFunctionsPanel());
|
||||
|
||||
selectionProvider = new RetrieverLevelSpecificSelectionProvider(stringMessages, dataMiningService, errorReporter, retrieverChainProvider);
|
||||
selectionProvider = new RetrieverLevelSpecificSelectionProvider(session, stringMessages, dataMiningService, errorReporter, retrieverChainProvider);
|
||||
selectionProvider.addSelectionChangedListener(new SelectionChangedListener() {
|
||||
@Override
|
||||
public void selectionChanged() {
|
||||
|
||||
+5
-2
@@ -22,6 +22,7 @@ import com.sap.sailing.gwt.ui.datamining.DataRetrieverChainDefinitionChangedList
|
||||
import com.sap.sailing.gwt.ui.datamining.DataRetrieverChainDefinitionProvider;
|
||||
import com.sap.sailing.gwt.ui.datamining.SelectionChangedListener;
|
||||
import com.sap.sailing.gwt.ui.datamining.SelectionProvider;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
|
||||
@@ -30,6 +31,7 @@ import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
public class RetrieverLevelSpecificSelectionProvider implements SelectionProvider<Object>, DataRetrieverChainDefinitionChangedListener {
|
||||
|
||||
private final DataMiningSession session;
|
||||
private final StringMessages stringMessages;
|
||||
private final DataMiningServiceAsync dataMiningService;
|
||||
private final ErrorReporter errorReporter;
|
||||
@@ -42,8 +44,9 @@ public class RetrieverLevelSpecificSelectionProvider implements SelectionProvide
|
||||
private final VerticalPanel contentPanel;
|
||||
private final Collection<SingleRetrieverLevelSelectionProviderPrototype> singleRetrieverLevelSelectionProviders;
|
||||
|
||||
public RetrieverLevelSpecificSelectionProvider(StringMessages stringMessages, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
|
||||
public RetrieverLevelSpecificSelectionProvider(DataMiningSession session, StringMessages stringMessages, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
|
||||
DataRetrieverChainDefinitionProvider dataRetrieverChainDefinitionProvider) {
|
||||
this.session = session;
|
||||
this.stringMessages = stringMessages;
|
||||
this.dataMiningService = dataMiningService;
|
||||
this.errorReporter = errorReporter;
|
||||
@@ -90,7 +93,7 @@ public class RetrieverLevelSpecificSelectionProvider implements SelectionProvide
|
||||
}
|
||||
first = false;
|
||||
|
||||
SingleRetrieverLevelSelectionProviderPrototype singleRetrieverLevelSelectionProvider = new SingleRetrieverLevelSelectionProviderPrototype(stringMessages, dataMiningService, errorReporter,
|
||||
SingleRetrieverLevelSelectionProviderPrototype singleRetrieverLevelSelectionProvider = new SingleRetrieverLevelSelectionProviderPrototype(session, stringMessages, dataMiningService, errorReporter,
|
||||
retrieverChain, retrievedDataType, retrieverLevel );
|
||||
singleRetrieverLevelSelectionProvider.addSelectionChangedListener(singleRetrieverLevelSelectionProvidersListener);
|
||||
|
||||
|
||||
+6
-3
@@ -24,6 +24,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.components.AbstractObjectRenderer;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.datamining.SelectionChangedListener;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
@@ -39,7 +40,8 @@ public class SingleRetrieverLevelSelectionProviderPrototype extends HorizontalPa
|
||||
/* This implementation is a prototype and mustn't be used to develop a productive UI component.
|
||||
* Instead start from scratch and use this prototype as orientation to get a cleaner result.
|
||||
* */
|
||||
|
||||
|
||||
private final DataMiningSession session;
|
||||
private final DataMiningServiceAsync dataMiningService;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final Set<SelectionChangedListener> listeners;
|
||||
@@ -61,8 +63,9 @@ public class SingleRetrieverLevelSelectionProviderPrototype extends HorizontalPa
|
||||
private final Map<ValueListBox<?>, VerticalPanel> singleDimensionFilterSelectionPanelsMappedBySelectionBox;
|
||||
private final Map<ValueListBox<?>, SelectionTable<?>> selectionTablesMappedBySelectionBox;
|
||||
|
||||
public SingleRetrieverLevelSelectionProviderPrototype(StringMessages stringMessages, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
|
||||
public SingleRetrieverLevelSelectionProviderPrototype(DataMiningSession session, StringMessages stringMessages, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
|
||||
DataRetrieverChainDefinitionDTO retrieverChain, LocalizedTypeDTO retrievedDataType, int retrieverLevel) {
|
||||
this.session = session;
|
||||
this.dataMiningService = dataMiningService;
|
||||
this.errorReporter = errorReporter;
|
||||
listeners = new HashSet<>();
|
||||
@@ -123,7 +126,7 @@ public class SingleRetrieverLevelSelectionProviderPrototype extends HorizontalPa
|
||||
if (isFiltrationPossible) {
|
||||
Collections.sort(availableDimensions);
|
||||
labeledBusyIndicator.setVisible(true);
|
||||
dataMiningService.getDimensionValuesFor(retrieverChain, retrieverLevel, dimensions, LocaleInfo.getCurrentLocale().getLocaleName(), new AsyncCallback<QueryResult<Set<Object>>>() {
|
||||
dataMiningService.getDimensionValuesFor(session, retrieverChain, retrieverLevel, dimensions, LocaleInfo.getCurrentLocale().getLocaleName(), new AsyncCallback<QueryResult<Set<Object>>>() {
|
||||
@Override
|
||||
public void onSuccess(QueryResult<Set<Object>> result) {
|
||||
dimensionValuesMappedByDimension.clear();
|
||||
|
||||
+2
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
@@ -48,6 +49,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
GWT.debugger();
|
||||
super.doOnModuleLoad();
|
||||
final boolean showRaceDetails = GwtHttpRequestUtils.getBooleanParameter(LeaderboardUrlSettings.PARAM_SHOW_RACE_DETAILS, false /* default*/);
|
||||
final boolean embedded = GwtHttpRequestUtils.getBooleanParameter(LeaderboardUrlSettings.PARAM_EMBEDDED, false /* default*/);
|
||||
|
||||
+30
-35
@@ -2065,7 +2065,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
* adds the <code>column</code> to the right end of the {@link #getLeaderboardTable() leaderboard table} and sets
|
||||
* the column style according to the {@link LeaderboardSortableColumnWithMinMax#getColumnStyle() column's style definition}.
|
||||
*/
|
||||
protected void addColumn(LeaderboardSortableColumnWithMinMax<LeaderboardRowDTO, ?> column) {
|
||||
protected void addColumn(AbstractSortableColumnWithMinMax<LeaderboardRowDTO, ?> column) {
|
||||
leaderboardTable.addColumn(column, column.getHeader(), column.getComparator(), column
|
||||
.getPreferredSortingOrder().isAscending());
|
||||
String columnStyle = column.getColumnStyle();
|
||||
@@ -2496,7 +2496,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
int columnIndex = 0;
|
||||
columnIndex = ensureSelectionCheckboxColumn(columnIndex);
|
||||
columnIndex = ensureRankColumn(columnIndex);
|
||||
columnIndex = ensureSailIDAndCompetitorColumn();
|
||||
columnIndex = ensureSailIDAndCompetitorColumn(columnIndex);
|
||||
columnIndex = updateCarryColumn(leaderboard, columnIndex);
|
||||
adjustOverallDetailColumns(leaderboard, columnIndex);
|
||||
// first remove race columns no longer needed:
|
||||
@@ -2809,42 +2809,37 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
/**
|
||||
* @return the 0-based index for the next column
|
||||
*/
|
||||
private int ensureSailIDAndCompetitorColumn() {
|
||||
SailIDColumn<LeaderboardRowDTO> sailIdColumn = new SailIDColumn<LeaderboardRowDTO>(new CompetitorFetcher<LeaderboardRowDTO>() {
|
||||
@Override
|
||||
public CompetitorDTO getCompetitor(LeaderboardRowDTO t) {
|
||||
return t.competitor;
|
||||
private int ensureSailIDAndCompetitorColumn(int columnIndexWhereToInsertTheNextColumn) {
|
||||
if (isShowCompetitorSailId()) {
|
||||
if (getLeaderboardTable().getColumnCount() <= columnIndexWhereToInsertTheNextColumn
|
||||
|| !(getLeaderboardTable().getColumn(columnIndexWhereToInsertTheNextColumn) instanceof SailIDColumn<?>)) {
|
||||
insertColumn(columnIndexWhereToInsertTheNextColumn, new SailIDColumn<LeaderboardRowDTO>(new CompetitorFetcher<LeaderboardRowDTO>() {
|
||||
@Override
|
||||
public CompetitorDTO getCompetitor(LeaderboardRowDTO t) {
|
||||
return t.competitor;
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
if (getLeaderboardTable().getColumnCount() >= 3) { // table already filled with columns
|
||||
if (isShowCompetitorSailId()) {
|
||||
if (!(getLeaderboardTable().getColumn(2) instanceof SailIDColumn<?>)) {
|
||||
insertColumn(2, sailIdColumn);
|
||||
}
|
||||
} else {
|
||||
if (getLeaderboardTable().getColumn(2) instanceof SailIDColumn<?>) {
|
||||
removeColumn(2);
|
||||
}
|
||||
}
|
||||
final int competitorFullNameColumnIndex = 2 + (isShowCompetitorSailId() ? 1 : 0);
|
||||
if (isShowCompetitorFullName()) {
|
||||
if (!(getLeaderboardTable().getColumn(competitorFullNameColumnIndex) instanceof CompetitorColumn)) {
|
||||
insertColumn(competitorFullNameColumnIndex, createCompetitorColumn());
|
||||
}
|
||||
} else {
|
||||
if (getLeaderboardTable().getColumn(competitorFullNameColumnIndex) instanceof CompetitorColumn) {
|
||||
removeColumn(competitorFullNameColumnIndex);
|
||||
}
|
||||
}
|
||||
} else { // table just being initialized
|
||||
if (isShowCompetitorSailId()) {
|
||||
addColumn(sailIdColumn);
|
||||
}
|
||||
if (isShowCompetitorFullName()) {
|
||||
addColumn(createCompetitorColumn());
|
||||
columnIndexWhereToInsertTheNextColumn++;
|
||||
} else {
|
||||
if (getLeaderboardTable().getColumnCount() > columnIndexWhereToInsertTheNextColumn
|
||||
&& getLeaderboardTable().getColumn(columnIndexWhereToInsertTheNextColumn) instanceof SailIDColumn<?>) {
|
||||
removeColumn(columnIndexWhereToInsertTheNextColumn);
|
||||
}
|
||||
}
|
||||
return (isShowRegattaRankColumn() ? 2 : 1) + (isShowCompetitorSailId() ? 1 : 0) + (isShowCompetitorFullName() ? 1 : 0);
|
||||
if (isShowCompetitorFullName()) {
|
||||
if (getLeaderboardTable().getColumnCount() <= columnIndexWhereToInsertTheNextColumn
|
||||
|| !(getLeaderboardTable().getColumn(columnIndexWhereToInsertTheNextColumn) instanceof CompetitorColumn)) {
|
||||
insertColumn(columnIndexWhereToInsertTheNextColumn, createCompetitorColumn());
|
||||
}
|
||||
columnIndexWhereToInsertTheNextColumn++;
|
||||
} else {
|
||||
if (getLeaderboardTable().getColumnCount() > columnIndexWhereToInsertTheNextColumn
|
||||
&& getLeaderboardTable().getColumn(columnIndexWhereToInsertTheNextColumn) instanceof CompetitorColumn) {
|
||||
removeColumn(columnIndexWhereToInsertTheNextColumn);
|
||||
}
|
||||
}
|
||||
return columnIndexWhereToInsertTheNextColumn;
|
||||
}
|
||||
|
||||
protected CompetitorColumn createCompetitorColumn() {
|
||||
|
||||
+8
@@ -4,6 +4,14 @@ import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
|
||||
/**
|
||||
* Settings for the {@link LeaderboardPanel} component. If you change here, please also visit
|
||||
* {@link LeaderboardSettingsDialogComponent} to make the setting editable, and edit {@link LeaderboardUrlSettings}
|
||||
* for URL generation and parsing.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class LeaderboardSettings {
|
||||
public static final String PARAM_LEADERBOARD_GROUP_NAME = "leaderboardGroupName";
|
||||
public static final String PARAM_EMBEDDED = "embedded";
|
||||
|
||||
+16
-6
@@ -151,11 +151,21 @@ public class LeaderboardUrlSettings {
|
||||
maneuverDetails.append('=');
|
||||
maneuverDetails.append(maneuverDetail.name());
|
||||
}
|
||||
StringBuilder showAddedScores = new StringBuilder();
|
||||
showAddedScores.append('&');
|
||||
showAddedScores.append(LeaderboardUrlSettings.PARAM_SHOW_ADDED_SCORES);
|
||||
showAddedScores.append('=');
|
||||
showAddedScores.append(settings.getLeaderboardSettings().isShowAddedScores());
|
||||
StringBuilder additionalOverallParams = new StringBuilder();
|
||||
additionalOverallParams.append('&');
|
||||
additionalOverallParams.append(LeaderboardUrlSettings.PARAM_SHOW_ADDED_SCORES);
|
||||
additionalOverallParams.append('=');
|
||||
additionalOverallParams.append(settings.getLeaderboardSettings().isShowAddedScores());
|
||||
if (!settings.getLeaderboardSettings().isShowCompetitorSailIdColumn() || !settings.getLeaderboardSettings().isShowCompetitorFullNameColumn()) {
|
||||
additionalOverallParams.append('&');
|
||||
additionalOverallParams.append(LeaderboardUrlSettings.PARAM_SHOW_COMPETITOR_NAME_COLUMNS);
|
||||
additionalOverallParams.append('=');
|
||||
if (settings.getLeaderboardSettings().isShowCompetitorSailIdColumn()) {
|
||||
additionalOverallParams.append(LeaderboardUrlSettings.COMPETITOR_NAME_COLUMN_SAIL_ID);
|
||||
} else if (settings.getLeaderboardSettings().isShowCompetitorFullNameColumn()) {
|
||||
additionalOverallParams.append(LeaderboardUrlSettings.COMPETITOR_NAME_COLUMN_FULL_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
String debugParam = Window.Location.getParameter("gwt.codesvr");
|
||||
String link = URLEncoder.encode("/gwt/Leaderboard.html?name=" + leaderboardName
|
||||
@@ -177,7 +187,7 @@ public class LeaderboardUrlSettings {
|
||||
+ (settings.isAutoExpandLastRaceColumn() ? "&"+LeaderboardUrlSettings.PARAM_AUTO_EXPAND_LAST_RACE_COLUMN+"=true" : "")
|
||||
+ (settings.getLeaderboardSettings().getNumberOfLastRacesToShow() == null ? "" :
|
||||
"&"+LeaderboardUrlSettings.PARAM_NAME_LAST_N+"="+settings.getLeaderboardSettings().getNumberOfLastRacesToShow())
|
||||
+ showAddedScores.toString()
|
||||
+ additionalOverallParams.toString()
|
||||
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : ""));
|
||||
return link;
|
||||
}
|
||||
|
||||
+5
-5
@@ -3,7 +3,6 @@ package com.sap.sailing.gwt.ui.raceboard;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
@@ -84,7 +83,7 @@ public class SideBySideComponentViewer implements ComponentViewer {
|
||||
String tooltip;
|
||||
switch (mediaPlayerManagerComponent.getAssignedMediaTracks().size()) {
|
||||
case 0:
|
||||
caption = "No Videos";
|
||||
caption = stringMessages.mediaNoVideosCaption();
|
||||
tooltip = caption;
|
||||
mediaSelectionButton.setVisible(false);
|
||||
break;
|
||||
@@ -105,11 +104,12 @@ public class SideBySideComponentViewer implements ComponentViewer {
|
||||
tooltip = stringMessages.mediaSelectVideoTooltip();
|
||||
break;
|
||||
}
|
||||
if (Document.get().getClientWidth() <= 1024) {
|
||||
mediaSelectionButton.setHTML(" ");
|
||||
if (mediaPlayerManagerComponent.isPlaying()) {
|
||||
mediaSelectionButton.addStyleDependentName("mediaplaying");
|
||||
} else {
|
||||
mediaSelectionButton.setText(caption);
|
||||
mediaSelectionButton.removeStyleDependentName("mediaplaying");
|
||||
}
|
||||
mediaSelectionButton.setText(caption);
|
||||
mediaSelectionButton.setTitle(tooltip);
|
||||
mediaManagementButton.setVisible(mediaPlayerManagerComponent.allowsEditing());
|
||||
}
|
||||
|
||||
+5
-4
@@ -20,6 +20,7 @@ import com.sap.sse.datamining.QueryDefinition;
|
||||
import com.sap.sse.datamining.factories.FunctionDTOFactory;
|
||||
import com.sap.sse.datamining.functions.Function;
|
||||
import com.sap.sse.datamining.impl.DataRetrieverTypeWithInformation;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.SSEDataMiningSerializationDummy;
|
||||
@@ -122,8 +123,8 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Set<Object>> getDimensionValuesFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO,
|
||||
int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName) throws Exception {
|
||||
public QueryResult<Set<Object>> getDimensionValuesFor(DataMiningSession session, DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO,
|
||||
int retrieverLevel, Iterable<FunctionDTO> dimensionDTOs, String localeInfoName) {
|
||||
DataRetrieverChainDefinition<RacingEventService, ?> retrieverChainDefinition = getDataMiningServer().getDataRetrieverChainDefinition(dataRetrieverChainDefinitionDTO.getId());
|
||||
Iterable<Function<?>> dimensions = functionDTOsAsFunctions(dimensionDTOs);
|
||||
Locale locale = ResourceBundleStringMessages.Util.getLocaleFor(localeInfoName);
|
||||
@@ -142,10 +143,10 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ResultType extends Number> QueryResult<ResultType> runQuery(QueryDefinitionDTO queryDefinitionDTO) throws Exception {
|
||||
public <ResultType extends Number> QueryResult<ResultType> runQuery(DataMiningSession session, QueryDefinitionDTO queryDefinitionDTO) {
|
||||
QueryDefinition<RacingEventService, ?, ResultType> queryDefinition = getDataMiningServer().getQueryDefinitionForDTO(queryDefinitionDTO);
|
||||
Query<ResultType> query = getDataMiningServer().createQuery(queryDefinition);
|
||||
QueryResult<ResultType> result = query.run();
|
||||
QueryResult<ResultType> result = getDataMiningServer().runNewQueryAndAbortPreviousQueries(session, query);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -2721,12 +2721,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
TrackedLegOfCompetitor trackedLeg = trackedRace.getTrackedLeg(competitor, timePoint);
|
||||
switch (dataType) {
|
||||
case RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
if (track != null) {
|
||||
SpeedWithBearing speedOverGround = track.getEstimatedSpeed(timePoint);
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> sogTrack = trackedRace.getTrack(competitor);
|
||||
if (sogTrack != null) {
|
||||
SpeedWithBearing speedOverGround = sogTrack.getEstimatedSpeed(timePoint);
|
||||
result = (speedOverGround == null) ? null : speedOverGround.getKnots();
|
||||
}
|
||||
break;
|
||||
case COURSE_OVER_GROUND_TRUE_DEGREES:
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> cogTrack = trackedRace.getTrack(competitor);
|
||||
if (cogTrack != null) {
|
||||
SpeedWithBearing speedOverGround = cogTrack.getEstimatedSpeed(timePoint);
|
||||
result = (speedOverGround == null) ? null : speedOverGround.getBearing().getDegrees();
|
||||
}
|
||||
break;
|
||||
case VELOCITY_MADE_GOOD_IN_KNOTS:
|
||||
if (trackedLeg != null) {
|
||||
Speed velocityMadeGood = trackedLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache);
|
||||
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor;
|
||||
import com.sap.sse.datamining.impl.components.ProcessorInstruction;
|
||||
|
||||
public abstract class AbstractEnrichingProcessor<InputType, ResultType> extends
|
||||
AbstractSimpleParallelProcessor<InputType, ResultType> {
|
||||
@@ -17,11 +17,11 @@ public abstract class AbstractEnrichingProcessor<InputType, ResultType> extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<ResultType> createInstruction(final InputType element) {
|
||||
return new Callable<ResultType>() {
|
||||
protected ProcessorInstruction<ResultType> createInstruction(final InputType element) {
|
||||
return new ProcessorInstruction<ResultType>(this) {
|
||||
|
||||
@Override
|
||||
public ResultType call() throws Exception {
|
||||
public ResultType computeResult() {
|
||||
return enrich(element);
|
||||
}
|
||||
};
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.sap.sse.datamining.shared;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface DataMiningSession extends Serializable {
|
||||
|
||||
}
|
||||
+3
-1
@@ -5,7 +5,9 @@ import java.util.Map;
|
||||
|
||||
public interface QueryResult<AggregatedType> extends Serializable {
|
||||
|
||||
int getRetrievedDataAmount();
|
||||
public QueryResultState getState();
|
||||
|
||||
public int getRetrievedDataAmount();
|
||||
public double getCalculationTimeInSeconds();
|
||||
|
||||
/**
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.sap.sse.datamining.shared;
|
||||
|
||||
public enum QueryResultState {
|
||||
|
||||
/**
|
||||
* The query finished normally and the result is reliable.
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
/**
|
||||
* The Query timed out.<br />
|
||||
* The result can be empty or incomplete.
|
||||
*/
|
||||
TIMED_OUT,
|
||||
|
||||
/**
|
||||
* The query was aborted.<br />
|
||||
* The result can be empty or incomplete.
|
||||
*/
|
||||
ABORTED,
|
||||
|
||||
/**
|
||||
* Failures occurred during the query processing.<br />
|
||||
* The result can be empty, incomplete or incorrect.
|
||||
*/
|
||||
FAILURE,
|
||||
|
||||
/**
|
||||
* A severe error occurred during the query processing, that caused the query to stop.<br />
|
||||
* The result can be empty, incomplete or incorrect.
|
||||
*/
|
||||
ERROR
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.sap.sse.datamining.shared.impl;
|
||||
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
|
||||
public abstract class AbstractDataMiningSession implements DataMiningSession {
|
||||
private static final long serialVersionUID = 4420076115971081397L;
|
||||
|
||||
//Enforce hash code and equals in all subclasses
|
||||
@Override
|
||||
public abstract boolean equals(Object other);
|
||||
@Override
|
||||
public abstract int hashCode();
|
||||
|
||||
}
|
||||
+11
-3
@@ -6,11 +6,13 @@ import java.util.Map;
|
||||
import com.sap.sse.datamining.shared.AdditionalResultData;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.QueryResultState;
|
||||
import com.sap.sse.datamining.shared.Unit;
|
||||
|
||||
public class QueryResultImpl<AggregatedType> implements QueryResult<AggregatedType> {
|
||||
private static final long serialVersionUID = 5173796619174827696L;
|
||||
|
||||
private QueryResultState state;
|
||||
private Map<GroupKey, AggregatedType> results;
|
||||
private AdditionalResultData additionalData;
|
||||
|
||||
@@ -20,14 +22,20 @@ public class QueryResultImpl<AggregatedType> implements QueryResult<AggregatedTy
|
||||
@Deprecated
|
||||
QueryResultImpl() { }
|
||||
|
||||
public QueryResultImpl(Map<GroupKey, AggregatedType> results) {
|
||||
this(results, new NullAdditionalResultData());
|
||||
public QueryResultImpl(QueryResultState state, Map<GroupKey, AggregatedType> results) {
|
||||
this(state, results, new NullAdditionalResultData());
|
||||
}
|
||||
|
||||
public QueryResultImpl(Map<GroupKey, AggregatedType> results, AdditionalResultData additionalData) {
|
||||
public QueryResultImpl(QueryResultState state, Map<GroupKey, AggregatedType> results, AdditionalResultData additionalData) {
|
||||
this.state = state;
|
||||
this.results = new HashMap<GroupKey, AggregatedType>(results);
|
||||
this.additionalData = additionalData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRetrievedDataAmount() {
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.sap.sse.datamining.shared.impl;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDDataMiningSession extends AbstractDataMiningSession {
|
||||
|
||||
private static final long serialVersionUID = 7794343618067812057L;
|
||||
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* Constructor for the GWT-Serialization. Don't use this!
|
||||
*/
|
||||
@Deprecated
|
||||
public UUIDDataMiningSession() { }
|
||||
|
||||
public UUIDDataMiningSession(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.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;
|
||||
UUIDDataMiningSession other = (UUIDDataMiningSession) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -23,6 +23,7 @@ import com.sap.sse.datamining.functions.Function;
|
||||
import com.sap.sse.datamining.functions.ParameterProvider;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
import com.sap.sse.datamining.test.functions.registry.test_classes.Test_Boat;
|
||||
@@ -64,7 +65,8 @@ public class TestDimensionsValuesQuery {
|
||||
public void testDimensionsValuesQuery() throws InterruptedException, ExecutionException {
|
||||
Query<Set<Object>> dimensionsValueQuery = createDimensionsValuesQuery();
|
||||
Map<GroupKey, Set<Object>> expectedResultData = buildExpectedResultData();
|
||||
ConcurrencyTestsUtil.verifyResultData(dimensionsValueQuery.run().getResults(), (Map<GroupKey, Set<Object>>) expectedResultData);
|
||||
QueryResult<Set<Object>> result = dimensionsValueQuery.run();
|
||||
ConcurrencyTestsUtil.verifyResultData(result.getResults(), (Map<GroupKey, Set<Object>>) expectedResultData);
|
||||
}
|
||||
|
||||
private Query<Set<Object>> createDimensionsValuesQuery() {
|
||||
|
||||
+117
-62
@@ -11,13 +11,11 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -32,9 +30,11 @@ import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleRetrievalProcessor;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.impl.components.ParallelFilteringProcessor;
|
||||
import com.sap.sse.datamining.impl.components.ProcessorInstruction;
|
||||
import com.sap.sse.datamining.impl.criterias.AbstractFilterCriterion;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.QueryResultState;
|
||||
import com.sap.sse.datamining.shared.Unit;
|
||||
import com.sap.sse.datamining.shared.components.AggregatorType;
|
||||
import com.sap.sse.datamining.shared.impl.AdditionalResultDataImpl;
|
||||
@@ -52,16 +52,13 @@ public class TestProcessorQuery {
|
||||
|
||||
private final static ResourceBundleStringMessages stringMessages = TestsUtil.getTestStringMessagesWithProductiveMessages();
|
||||
|
||||
private ProcessorFactory processorFactory;
|
||||
private final static ProcessorFactory processorFactory = new ProcessorFactory(ConcurrencyTestsUtil.getExecutor());
|
||||
|
||||
private boolean receivedElementOrFinished;
|
||||
private boolean receivedAbort;
|
||||
|
||||
@Before
|
||||
public void initializeProcessorFactory() {
|
||||
processorFactory = new ProcessorFactory(ConcurrencyTestsUtil.getExecutor());
|
||||
}
|
||||
|
||||
private QueryResult<?> resultAfterAbortion;
|
||||
|
||||
@Test
|
||||
public void testStandardWorkflow() throws InterruptedException, ExecutionException {
|
||||
Collection<Number> dataSource = createDataSource();
|
||||
@@ -157,11 +154,12 @@ public class TestProcessorQuery {
|
||||
results.put(new GenericGroupKey<Integer>(3), 3.0);
|
||||
results.put(new GenericGroupKey<Integer>(4), 10.0);
|
||||
|
||||
QueryResultImpl<Double> result = new QueryResultImpl<>(results, new AdditionalResultDataImpl(dataSource.size() - 2, "Cross Sum (Sum)", Unit.None, "", 0, 0));
|
||||
QueryResultImpl<Double> result = new QueryResultImpl<>(QueryResultState.NORMAL, results, new AdditionalResultDataImpl(dataSource.size() - 2, "Cross Sum (Sum)", Unit.None, "", 0, 0));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void verifyResult(QueryResult<Double> result, QueryResult<Double> expectedResult) {
|
||||
assertThat("The result State isn't correct.", result.getState(), is(expectedResult.getState()));
|
||||
assertThat("Result values aren't correct.", result.getResults(), is(expectedResult.getResults()));
|
||||
assertThat("Retrieved data amount isn't correct.", result.getRetrievedDataAmount(), is(expectedResult.getRetrievedDataAmount()));
|
||||
assertThat("Result signifier isn't correct.", result.getResultSignifier(), is(expectedResult.getResultSignifier()));
|
||||
@@ -169,33 +167,27 @@ public class TestProcessorQuery {
|
||||
assertThat("Value decimals aren't correct.", result.getValueDecimals(), is(expectedResult.getValueDecimals()));
|
||||
}
|
||||
|
||||
@Test//(timeout=2000)
|
||||
public void testQueryTimeouting() throws TimeoutException {
|
||||
@Test(timeout=2000)
|
||||
public void testQueryTimeouting() {
|
||||
receivedElementOrFinished = false;
|
||||
receivedAbort = false;
|
||||
|
||||
Collection<Number> dataSource = new ArrayList<>();
|
||||
dataSource.add(new Number(10));
|
||||
ProcessorQuery<Double, Iterable<Number>> query = new ProcessorQuery<Double, Iterable<Number>>(
|
||||
createDataSource(), stringMessages, Locale.ENGLISH) {
|
||||
dataSource, stringMessages, Locale.ENGLISH) {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Processor<Iterable<Number>, ?> createFirstProcessor() {
|
||||
Processor<Double, Void> resultReceiver = new NullProcessor<Double, Void>(Double.class, Void.class) {
|
||||
@Override
|
||||
public void processElement(Double element) {
|
||||
receivedElementOrFinished = true;
|
||||
}
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
receivedElementOrFinished = true;
|
||||
}
|
||||
@Override
|
||||
public void abort() {
|
||||
receivedAbort = true;
|
||||
}
|
||||
};
|
||||
Collection<Processor<Double, ?>> resultReceivers = new ArrayList<>();
|
||||
resultReceivers.add(resultReceiver);
|
||||
return new BlockingProcessor<Iterable<Number>, Double>((Class<Iterable<Number>>)(Class<?>) Iterable.class, Double.class, ConcurrencyTestsUtil.getExecutor(), resultReceivers, 2000);
|
||||
resultReceivers.add(new AbortResultReceiver(this.getResultReceiver()));
|
||||
return new BlockingProcessor<Iterable<Number>, Double>((Class<Iterable<Number>>)(Class<?>) Iterable.class, Double.class,
|
||||
ConcurrencyTestsUtil.getExecutor(), resultReceivers, 1000) {
|
||||
@Override
|
||||
protected Double createResult(Iterable<Number> element) {
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -207,8 +199,76 @@ public class TestProcessorQuery {
|
||||
}
|
||||
|
||||
ConcurrencyTestsUtil.sleepFor(1000); // Wait if a result is received
|
||||
assertThat("The processing should be aborted", receivedElementOrFinished, is(false));
|
||||
assertThat("The processing should be aborted", receivedAbort, is(true));
|
||||
assertThat("The processing should be aborted, but received elements", receivedElementOrFinished, is(false));
|
||||
assertThat("The processing should be aborted, but didn't receive abort", receivedAbort, is(true));
|
||||
}
|
||||
|
||||
@Test(timeout=2000)
|
||||
public void testQueryAbortion() throws InterruptedException {
|
||||
receivedElementOrFinished = false;
|
||||
receivedAbort = false;
|
||||
|
||||
Collection<Number> dataSource = new ArrayList<>();
|
||||
dataSource.add(new Number(10));
|
||||
ProcessorQuery<Double, Iterable<Number>> query = new ProcessorQuery<Double, Iterable<Number>>(
|
||||
dataSource, stringMessages, Locale.ENGLISH) {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Processor<Iterable<Number>, ?> createFirstProcessor() {
|
||||
Collection<Processor<Double, ?>> resultReceivers = new ArrayList<>();
|
||||
resultReceivers.add(new AbortResultReceiver(this.getResultReceiver()));
|
||||
return new BlockingProcessor<Iterable<Number>, Double>((Class<Iterable<Number>>)(Class<?>) Iterable.class, Double.class,
|
||||
ConcurrencyTestsUtil.getExecutor(), resultReceivers, 1000) {
|
||||
@Override
|
||||
protected Double createResult(Iterable<Number> element) {
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Thread queryRunner = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultAfterAbortion = query.run();
|
||||
}
|
||||
});
|
||||
queryRunner.start();
|
||||
ConcurrencyTestsUtil.sleepFor(500);
|
||||
query.abort();
|
||||
|
||||
ConcurrencyTestsUtil.sleepFor(1000); // Wait if a result is received
|
||||
queryRunner.join();
|
||||
assertThat(resultAfterAbortion.getState(), is(QueryResultState.ABORTED));
|
||||
assertThat("The processing should be aborted, but received elements", receivedElementOrFinished, is(false));
|
||||
assertThat("The processing should be aborted, but didn't receive abort", receivedAbort, is(true));
|
||||
}
|
||||
|
||||
private class AbortResultReceiver extends NullProcessor<Double, Void> {
|
||||
|
||||
private final Processor<Map<GroupKey, Double>, Void> queryResultReceiver;
|
||||
|
||||
public AbortResultReceiver(Processor<Map<GroupKey, Double>, Void> queryResultReceiver) {
|
||||
super(Double.class, Void.class);
|
||||
this.queryResultReceiver = queryResultReceiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processElement(Double element) {
|
||||
receivedElementOrFinished = true;
|
||||
queryResultReceiver.processElement(null);
|
||||
}
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
receivedElementOrFinished = true;
|
||||
queryResultReceiver.finish();
|
||||
}
|
||||
@Override
|
||||
public void abort() {
|
||||
receivedAbort = true;
|
||||
queryResultReceiver.abort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -216,9 +276,35 @@ public class TestProcessorQuery {
|
||||
final String keyValue = "Sum";
|
||||
ProcessorQuery<Double, Iterable<Number>> query = new ProcessorQuery<Double, Iterable<Number>>(
|
||||
createDataSource(), stringMessages, Locale.ENGLISH) {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Processor<Iterable<Number>, ?> createFirstProcessor() {
|
||||
return createSumBuildingProcessor(/*query*/ this, keyValue);
|
||||
Collection<Processor<Map<GroupKey, Double>, ?>> resultReceivers = new ArrayList<>();
|
||||
resultReceivers.add(this.getResultReceiver());
|
||||
return new AbstractSimpleParallelProcessor<Iterable<Number>, Map<GroupKey, Double>>((Class<Iterable<Number>>)(Class<?>) Iterable.class,
|
||||
(Class<Map<GroupKey, Double>>)(Class<?>) Map.class,
|
||||
ConcurrencyTestsUtil.getExecutor(),
|
||||
resultReceivers) {
|
||||
@Override
|
||||
protected ProcessorInstruction<Map<GroupKey, Double>> createInstruction(final Iterable<Number> element) {
|
||||
return new ProcessorInstruction<Map<GroupKey,Double>>(this) {
|
||||
@Override
|
||||
public Map<GroupKey, Double> computeResult() {
|
||||
Map<GroupKey, Double> result = new HashMap<>();
|
||||
double sum = 0;
|
||||
for (Number number : element) {
|
||||
sum += number.getValue();
|
||||
}
|
||||
result.put(new GenericGroupKey<String>(keyValue), sum);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -227,35 +313,4 @@ public class TestProcessorQuery {
|
||||
assertThat(query.run(500, TimeUnit.MILLISECONDS).getResults(), is(expectedResult));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private AbstractSimpleParallelProcessor<Iterable<Number>, Map<GroupKey, Double>> createSumBuildingProcessor(
|
||||
ProcessorQuery<Double, Iterable<Number>> query, final String keyValue) {
|
||||
Collection<Processor<Map<GroupKey, Double>, ?>> resultReceivers = new ArrayList<>();
|
||||
resultReceivers.add(query.getResultReceiver());
|
||||
return new AbstractSimpleParallelProcessor<Iterable<Number>, Map<GroupKey, Double>>((Class<Iterable<Number>>)(Class<?>) Iterable.class,
|
||||
(Class<Map<GroupKey, Double>>)(Class<?>) Map.class,
|
||||
ConcurrencyTestsUtil.getExecutor(),
|
||||
resultReceivers) {
|
||||
@Override
|
||||
protected Callable<Map<GroupKey, Double>> createInstruction(final Iterable<Number> element) {
|
||||
return new Callable<Map<GroupKey,Double>>() {
|
||||
@Override
|
||||
public Map<GroupKey, Double> call() throws Exception {
|
||||
Map<GroupKey, Double> result = new HashMap<>();
|
||||
double sum = 0;
|
||||
for (Number number : element) {
|
||||
sum += number.getValue();
|
||||
}
|
||||
result.put(new GenericGroupKey<String>(keyValue), sum);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+15
-10
@@ -6,7 +6,6 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -38,8 +37,18 @@ public class TestAbstractParallelProcessorFinishing {
|
||||
|
||||
@Test
|
||||
public void testProcessFinishing() {
|
||||
processor.processElement(1);
|
||||
ConcurrencyTestsUtil.tryToFinishTheProcessorInAnotherThread(processor);
|
||||
Thread worker = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
processor.processElement(1);
|
||||
try {
|
||||
processor.finish();
|
||||
} catch (InterruptedException e) {
|
||||
fail("The test was interrupted: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
worker.start();
|
||||
ConcurrencyTestsUtil.sleepFor(100); //Wait till the processor tries to finish
|
||||
assertThat(receiverWasToldToFinish, is(false));
|
||||
instructionIsWorking = false; //The processer should be able to finish after the instruction is done
|
||||
@@ -54,20 +63,16 @@ public class TestAbstractParallelProcessorFinishing {
|
||||
public void finish() throws InterruptedException {
|
||||
receiverWasToldToFinish = true;
|
||||
}
|
||||
@Override
|
||||
public AdditionalResultDataBuilder getAdditionalResultData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
return additionalDataBuilder;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private AbstractSimpleParallelProcessor<Integer, Integer> createProcessor(Collection<Processor<Integer, ?>> receivers) {
|
||||
return new AbstractSimpleParallelProcessor<Integer, Integer>(Integer.class, Integer.class, ConcurrencyTestsUtil.getExecutor(), receivers) {
|
||||
@Override
|
||||
protected Callable<Integer> createInstruction(Integer partialElement) {
|
||||
return new Callable<Integer>() {
|
||||
protected ProcessorInstruction<Integer> createInstruction(Integer partialElement) {
|
||||
return new ProcessorInstruction<Integer>(this) {
|
||||
@Override
|
||||
public Integer call() {
|
||||
public Integer computeResult() {
|
||||
while (instructionIsWorking) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
|
||||
+3
-4
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -39,10 +38,10 @@ public class TestAbstractParallelProcessorWithManySimpleInstructions {
|
||||
receivers.add(receiver);
|
||||
processor = new AbstractSimpleParallelProcessor<Integer, Integer>(Integer.class, Integer.class, ConcurrencyTestsUtil.getExecutor(), receivers) {
|
||||
@Override
|
||||
protected Callable<Integer> createInstruction(final Integer element) {
|
||||
return new Callable<Integer>() {
|
||||
protected ProcessorInstruction<Integer> createInstruction(final Integer element) {
|
||||
return new ProcessorInstruction<Integer>(this) {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
public Integer computeResult() {
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
+3
-4
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -28,10 +27,10 @@ public class TestPartitioningOfAbstractSimpleParallelProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<Integer> createInstruction(Integer partialElement) {
|
||||
return new Callable<Integer>() {
|
||||
protected ProcessorInstruction<Integer> createInstruction(Integer partialElement) {
|
||||
return new ProcessorInstruction<Integer>(this) {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
public Integer computeResult() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
+19
@@ -73,6 +73,25 @@ public class TestAbstractStoringParallelAggregationProcessor {
|
||||
|
||||
@Test(timeout=5000)
|
||||
public void testThatTheLockIsReleasedAfterStoringFailed() throws InterruptedException {
|
||||
Collection<Processor<Integer, ?>> receivers = new HashSet<>();
|
||||
receivers.add(new NullProcessor<Integer, Void>(Integer.class, Void.class) {
|
||||
@Override
|
||||
public void processElement(Integer element) {
|
||||
receivedElement = element;
|
||||
}
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
receiverWasToldToFinish = true;
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
if (failure instanceof IllegalArgumentException) {
|
||||
// Do nothing, since a IllegalArgumentException is expected
|
||||
} else {
|
||||
super.onFailure(failure);
|
||||
}
|
||||
}
|
||||
});
|
||||
Processor<Integer, Integer> processor = new AbstractParallelStoringAggregationProcessor<Integer, Integer>(Integer.class, Integer.class, ConcurrencyTestsUtil.getExecutor(), receivers, "Sum") {
|
||||
@Override
|
||||
protected void storeElement(Integer element) {
|
||||
|
||||
+4
-11
@@ -18,19 +18,12 @@ import com.sap.sse.datamining.shared.GroupKey;
|
||||
public class ConcurrencyTestsUtil extends TestsUtil {
|
||||
|
||||
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
private static ThreadPoolExecutor executor = createExecutor();
|
||||
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
public static ThreadPoolExecutor getExecutor() {
|
||||
if (executor.isShutdown()) {
|
||||
executor = createExecutor();
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
private static ThreadPoolExecutor createExecutor() {
|
||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
public static void sleepFor(long milliseconds) {
|
||||
try {
|
||||
Thread.sleep(milliseconds);
|
||||
@@ -57,7 +50,7 @@ public class ConcurrencyTestsUtil extends TestsUtil {
|
||||
}
|
||||
|
||||
public static void tryToFinishTheProcessorInAnotherThread(final Processor<?, ?> processor) {
|
||||
Runnable finishingRunnable = new Runnable() {
|
||||
Thread finishingThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@@ -66,8 +59,8 @@ public class ConcurrencyTestsUtil extends TestsUtil {
|
||||
fail("The test was interrupted: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
getExecutor().execute(finishingRunnable);
|
||||
});
|
||||
finishingThread.start();
|
||||
}
|
||||
|
||||
protected ConcurrencyTestsUtil() {
|
||||
|
||||
+8
-6
@@ -1,14 +1,14 @@
|
||||
package com.sap.sse.datamining.test.util.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor;
|
||||
import com.sap.sse.datamining.impl.components.ProcessorInstruction;
|
||||
|
||||
public class BlockingProcessor<InputType, ResultType> extends AbstractSimpleParallelProcessor<InputType, ResultType> {
|
||||
public abstract class BlockingProcessor<InputType, ResultType> extends AbstractSimpleParallelProcessor<InputType, ResultType> {
|
||||
private final long timeToBlockInMillis;
|
||||
|
||||
public BlockingProcessor(Class<InputType> inputType, Class<ResultType> resultType,
|
||||
@@ -19,15 +19,17 @@ public class BlockingProcessor<InputType, ResultType> extends AbstractSimplePara
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<ResultType> createInstruction(InputType element) {
|
||||
return new Callable<ResultType>() {
|
||||
protected ProcessorInstruction<ResultType> createInstruction(InputType element) {
|
||||
return new ProcessorInstruction<ResultType>(this) {
|
||||
@Override
|
||||
public ResultType call() throws Exception {
|
||||
public ResultType computeResult() throws Exception {
|
||||
Thread.sleep(timeToBlockInMillis);
|
||||
return null;
|
||||
return createResult(element);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract ResultType createResult(InputType element);
|
||||
|
||||
@Override
|
||||
protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class NullProcessor<InputType, ResultType> extends AbstractProcessor<Inpu
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
|
||||
throw new RuntimeException("An error occured during the processing", failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.sap.sse.datamining;
|
||||
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
public interface DataMiningQueryManager {
|
||||
|
||||
public <ResultType> QueryResult<ResultType> runNewAndAbortPrevious(DataMiningSession session, Query<ResultType> query);
|
||||
|
||||
}
|
||||
@@ -7,7 +7,9 @@ import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.functions.Function;
|
||||
import com.sap.sse.datamining.functions.FunctionProvider;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
|
||||
@@ -55,4 +57,6 @@ public interface DataMiningServer {
|
||||
|
||||
public <DataSourceType, ResultType> Query<ResultType> createQuery(QueryDefinition<DataSourceType, ?, ResultType> queryDefinition);
|
||||
|
||||
public <ResultType> QueryResult<ResultType> runNewQueryAndAbortPreviousQueries(DataMiningSession session, Query<ResultType> query);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sap.sse.datamining;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@@ -8,8 +7,12 @@ import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
public interface Query<AggregatedType> {
|
||||
|
||||
public QueryResult<AggregatedType> run() throws InterruptedException, ExecutionException;
|
||||
public QueryState getState();
|
||||
|
||||
public QueryResult<AggregatedType> run();
|
||||
|
||||
public QueryResult<AggregatedType> run(long timeout, TimeUnit unit) throws TimeoutException;
|
||||
|
||||
public void abort();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.sap.sse.datamining;
|
||||
|
||||
import com.sap.sse.datamining.shared.QueryResultState;
|
||||
|
||||
public enum QueryState {
|
||||
|
||||
/**
|
||||
* The Query hasn't been started yet.
|
||||
*/
|
||||
NOT_STARTED,
|
||||
|
||||
/**
|
||||
* The Query is currently running.
|
||||
*/
|
||||
RUNNING,
|
||||
|
||||
/**
|
||||
* The Query finished normally and the result is reliable.
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
/**
|
||||
* The Query timed out.<br />
|
||||
* The result can be empty or incomplete.
|
||||
*/
|
||||
TIMED_OUT,
|
||||
|
||||
/**
|
||||
* The Query was aborted.<br />
|
||||
* The result can be empty or incomplete.
|
||||
*/
|
||||
ABORTED,
|
||||
|
||||
/**
|
||||
* Failures occurred during the query processing.<br />
|
||||
* The result can be empty, incomplete or incorrect.
|
||||
*/
|
||||
FAILURE,
|
||||
|
||||
/**
|
||||
* A severe error occurred during the query processing, that caused the query to stop.<br />
|
||||
* The result can be empty, incomplete or incorrect.
|
||||
*/
|
||||
ERROR;
|
||||
|
||||
public QueryResultState asResultState() {
|
||||
switch (this) {
|
||||
case ABORTED:
|
||||
return QueryResultState.ABORTED;
|
||||
case ERROR:
|
||||
return QueryResultState.ERROR;
|
||||
case FAILURE:
|
||||
return QueryResultState.FAILURE;
|
||||
case NORMAL:
|
||||
return QueryResultState.NORMAL;
|
||||
case TIMED_OUT:
|
||||
return QueryResultState.TIMED_OUT;
|
||||
default:
|
||||
throw new UnsupportedOperationException("There's no equivalent " + QueryResultState.class.getSimpleName() + " for '" + this + "'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.sap.sse.datamining.impl;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.sap.sse.datamining.DataMiningQueryManager;
|
||||
import com.sap.sse.datamining.Query;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
public class ConcurrentDataMiningQueryManager implements DataMiningQueryManager {
|
||||
|
||||
private final ConcurrentMap<DataMiningSession, Query<?>> queryMappedBySession;
|
||||
|
||||
public ConcurrentDataMiningQueryManager() {
|
||||
queryMappedBySession = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ResultType> QueryResult<ResultType> runNewAndAbortPrevious(DataMiningSession session, Query<ResultType> query) {
|
||||
if (session == null || query == null) {
|
||||
//Forbidding null Queries ensures the functionality of registerNewQuery
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
abortPreviousQueries(session, query);
|
||||
registerNewQuery(session, query);
|
||||
QueryResult<ResultType> result = query.run();
|
||||
unregisterQuery(session, query);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void abortPreviousQueries(DataMiningSession session, Query<?> query) {
|
||||
// TODO handle different types of queries (a statistics query doesn't have to be aborted, if a new dimension values query wants to run)
|
||||
if (queryMappedBySession.containsKey(session)) {
|
||||
Query<?> previousQuery = queryMappedBySession.get(session);
|
||||
previousQuery.abort();
|
||||
queryMappedBySession.remove(session, previousQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private <ResultType> void registerNewQuery(DataMiningSession session, Query<ResultType> query) {
|
||||
Query<?> previousValue = queryMappedBySession.putIfAbsent(session, query);
|
||||
if (previousValue != null) {
|
||||
throw new UnsupportedOperationException("There's allready a Query for the session: " + session);
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterQuery(DataMiningSession session, Query<?> query) {
|
||||
queryMappedBySession.remove(session, query);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.DataMiningQueryManager;
|
||||
import com.sap.sse.datamining.DataRetrieverChainDefinition;
|
||||
import com.sap.sse.datamining.DataRetrieverChainDefinitionProvider;
|
||||
import com.sap.sse.datamining.DataRetrieverChainDefinitionRegistry;
|
||||
@@ -21,7 +22,9 @@ import com.sap.sse.datamining.factories.QueryFactory;
|
||||
import com.sap.sse.datamining.functions.Function;
|
||||
import com.sap.sse.datamining.functions.FunctionProvider;
|
||||
import com.sap.sse.datamining.functions.FunctionRegistry;
|
||||
import com.sap.sse.datamining.shared.DataMiningSession;
|
||||
import com.sap.sse.datamining.shared.QueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.dto.FunctionDTO;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.i18n.impl.CompoundResourceBundleStringMessages;
|
||||
@@ -32,6 +35,7 @@ public class DataMiningServerImpl implements ModifiableDataMiningServer {
|
||||
private final ExecutorService executorService;
|
||||
|
||||
private final QueryFactory queryFactory;
|
||||
private final DataMiningQueryManager dataMiningQueryManager;
|
||||
|
||||
private final FunctionRegistry functionRegistry;
|
||||
private final FunctionProvider functionProvider;
|
||||
@@ -43,6 +47,7 @@ public class DataMiningServerImpl implements ModifiableDataMiningServer {
|
||||
this.stringMessages = new CompoundResourceBundleStringMessages();
|
||||
this.executorService = executorService;
|
||||
this.queryFactory = new QueryFactory();
|
||||
dataMiningQueryManager = new ConcurrentDataMiningQueryManager();
|
||||
this.functionRegistry = functionRegistry;
|
||||
this.functionProvider = functionProvider;
|
||||
dataSourceProviderMappedByDataSourceType = new HashMap<>();
|
||||
@@ -224,4 +229,9 @@ public class DataMiningServerImpl implements ModifiableDataMiningServer {
|
||||
return (DataSourceProvider<DataSourceType>) dataSourceProviderMappedByDataSourceType.get(dataSourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ResultType> QueryResult<ResultType> runNewQueryAndAbortPreviousQueries(DataMiningSession session, Query<ResultType> query) {
|
||||
return dataMiningQueryManager.runNewAndAbortPrevious(session, query);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -15,10 +16,12 @@ import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.Query;
|
||||
import com.sap.sse.datamining.QueryState;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.OverwritingResultDataBuilder;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.QueryResultState;
|
||||
import com.sap.sse.datamining.shared.impl.QueryResultImpl;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
|
||||
@@ -36,8 +39,7 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
|
||||
private final Object monitorObject = new Object();
|
||||
private Thread workingThread;
|
||||
private boolean workIsDone = false;
|
||||
private boolean processorTimedOut = false;
|
||||
private QueryState state;
|
||||
|
||||
/**
|
||||
* Creates a query that returns a result without any additional data (like the calculation time or the retrieved data amount).<br>
|
||||
@@ -54,12 +56,18 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
this.dataSource = dataSource;
|
||||
this.stringMessages = stringMessages;
|
||||
this.locale = locale;
|
||||
state = QueryState.NOT_STARTED;
|
||||
|
||||
resultReceiver = new ProcessResultReceiver();
|
||||
firstProcessor = createFirstProcessor();
|
||||
}
|
||||
|
||||
protected abstract Processor<DataSourceType, ?> createFirstProcessor();
|
||||
|
||||
@Override
|
||||
public QueryState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<AggregatedType> run() {
|
||||
@@ -85,23 +93,24 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
}
|
||||
|
||||
private QueryResult<AggregatedType> processQuery(long timeoutInMillis) throws InterruptedException, TimeoutException {
|
||||
processorTimedOut = false;
|
||||
state = QueryState.RUNNING;
|
||||
final long startTime = System.nanoTime();
|
||||
startWorking();
|
||||
waitTillWorkIsDone(timeoutInMillis);
|
||||
final long endTime = System.nanoTime();
|
||||
|
||||
logOccuredFailures();
|
||||
logOccuredFailuresAndThrowSevereFailure();
|
||||
|
||||
long calculationTimeInNanos = endTime - startTime;
|
||||
Map<GroupKey, AggregatedType> results = resultReceiver.getResult();
|
||||
QueryResultState resultState = state.asResultState();
|
||||
|
||||
if (stringMessages != null && locale != null) {
|
||||
AdditionalResultDataBuilder additionalDataBuilder = new OverwritingResultDataBuilder();
|
||||
additionalDataBuilder = firstProcessor.getAdditionalResultData(additionalDataBuilder);
|
||||
return new QueryResultImpl<>(results, additionalDataBuilder.build(calculationTimeInNanos, stringMessages, locale));
|
||||
return new QueryResultImpl<>(resultState, results, additionalDataBuilder.build(calculationTimeInNanos, stringMessages, locale));
|
||||
} else {
|
||||
return new QueryResultImpl<>(results);
|
||||
return new QueryResultImpl<>(resultState, results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +122,12 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
firstProcessor.processElement(dataSource);
|
||||
firstProcessor.finish();
|
||||
} catch (InterruptedException e) {
|
||||
if (processorTimedOut) {
|
||||
if (state == QueryState.TIMED_OUT) {
|
||||
LOGGER.log(Level.INFO, "The query processing timed out.");
|
||||
} else if (state == QueryState.ABORTED) {
|
||||
LOGGER.log(Level.INFO, "The query processing got aborted.");
|
||||
} else if (state == QueryState.ERROR) {
|
||||
LOGGER.log(Level.INFO, "A severe failure occured during the query processing.");
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "The query processing got interrupted.", e);
|
||||
}
|
||||
@@ -127,18 +140,24 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
private void waitTillWorkIsDone(long timeoutInMillis) throws InterruptedException, TimeoutException {
|
||||
setUpTimeoutTimer(timeoutInMillis);
|
||||
synchronized (monitorObject) {
|
||||
while (!workIsDone) {
|
||||
while (getState() == QueryState.RUNNING) {
|
||||
monitorObject.wait();
|
||||
if (processorTimedOut && !workIsDone) {
|
||||
if (processingHasToBeAborted()) {
|
||||
firstProcessor.abort();
|
||||
workingThread.interrupt();
|
||||
throw new TimeoutException("The query processing timed out");
|
||||
if (state == QueryState.TIMED_OUT) {
|
||||
throw new TimeoutException("The query processing timed out");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
workIsDone = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processingHasToBeAborted() {
|
||||
return state == QueryState.TIMED_OUT || state == QueryState.ABORTED || state == QueryState.ERROR;
|
||||
}
|
||||
|
||||
private void setUpTimeoutTimer(long timeoutInMillis) {
|
||||
if (timeoutInMillis > 0) {
|
||||
Timer timeoutTimer = new Timer();
|
||||
@@ -146,7 +165,7 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (monitorObject) {
|
||||
processorTimedOut = true;
|
||||
state = QueryState.TIMED_OUT;
|
||||
monitorObject.notify();
|
||||
}
|
||||
}
|
||||
@@ -154,10 +173,21 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
}
|
||||
}
|
||||
|
||||
private void logOccuredFailures() {
|
||||
private void logOccuredFailuresAndThrowSevereFailure() {
|
||||
for (Throwable failure : resultReceiver.getOccuredFailures()) {
|
||||
LOGGER.log(Level.SEVERE, "An error occured during the processing of an instruction: ", failure);
|
||||
}
|
||||
if (state == QueryState.ERROR) {
|
||||
throw new RuntimeException("A severe failure occured during the processing of an instruction", resultReceiver.getSevereFailure());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
synchronized (monitorObject) {
|
||||
state = QueryState.ABORTED;
|
||||
monitorObject.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public Processor<Map<GroupKey, AggregatedType>, Void> getResultReceiver() {
|
||||
@@ -169,6 +199,7 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
private final ReentrantLock resultsLock;
|
||||
private Map<GroupKey, AggregatedType> results;
|
||||
private List<Throwable> occuredFailures;
|
||||
private Throwable severeFailure;
|
||||
|
||||
public ProcessResultReceiver() {
|
||||
resultsLock = new ReentrantLock();
|
||||
@@ -188,13 +219,26 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
occuredFailures.add(failure);
|
||||
if (isSevereFailure(failure)) {
|
||||
severeFailure = failure;
|
||||
synchronized (monitorObject) {
|
||||
state = QueryState.ERROR;
|
||||
monitorObject.notify();
|
||||
}
|
||||
} else {
|
||||
state = QueryState.FAILURE;
|
||||
occuredFailures.add(failure);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSevereFailure(Throwable failure) {
|
||||
return !(failure instanceof Exception) || failure instanceof RejectedExecutionException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
synchronized (monitorObject) {
|
||||
workIsDone = true;
|
||||
state = QueryState.NORMAL;
|
||||
monitorObject.notify();
|
||||
}
|
||||
}
|
||||
@@ -212,6 +256,10 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
|
||||
public List<Throwable> getOccuredFailures() {
|
||||
return occuredFailures;
|
||||
}
|
||||
|
||||
public Throwable getSevereFailure() {
|
||||
return severeFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalResultDataBuilder getAdditionalResultData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
|
||||
+3
-4
@@ -2,7 +2,6 @@ package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -47,10 +46,10 @@ public abstract class AbstractParallelMultiDimensionalNestingGroupingProcessor<D
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<GroupedDataEntry<DataType>> createInstruction(final DataType element) {
|
||||
return new Callable<GroupedDataEntry<DataType>>() {
|
||||
protected ProcessorInstruction<GroupedDataEntry<DataType>> createInstruction(final DataType element) {
|
||||
return new ProcessorInstruction<GroupedDataEntry<DataType>>(this) {
|
||||
@Override
|
||||
public GroupedDataEntry<DataType> call() throws Exception {
|
||||
public GroupedDataEntry<DataType> computeResult() {
|
||||
return new GroupedDataEntry<DataType>(createCompoundKeyFor(element,
|
||||
dimensionsWithParameterProvider.iterator()), element);
|
||||
}
|
||||
|
||||
+31
-74
@@ -3,11 +3,9 @@ package com.sap.sse.datamining.impl.components;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -22,62 +20,49 @@ public abstract class AbstractPartitioningParallelProcessor<InputType, WorkingTy
|
||||
|
||||
private final Set<Processor<ResultType, ?>> resultReceivers;
|
||||
private final ExecutorService executor;
|
||||
private final UnfinishedInstructionsCounter unfinishedInstructionsCounter;
|
||||
private final AtomicInteger unfinishedInstructionsCounter;
|
||||
|
||||
private boolean isFinished = false;
|
||||
private boolean gotAborted = false;
|
||||
private boolean isAborted = false;
|
||||
|
||||
public AbstractPartitioningParallelProcessor(Class<InputType> inputType, Class<ResultType> resultType, ExecutorService executor, Collection<Processor<ResultType, ?>> resultReceivers) {
|
||||
super(inputType, resultType);
|
||||
this.executor = executor;
|
||||
this.resultReceivers = new HashSet<Processor<ResultType, ?>>(resultReceivers);
|
||||
unfinishedInstructionsCounter = new UnfinishedInstructionsCounter();
|
||||
unfinishedInstructionsCounter = new AtomicInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processElement(InputType element) {
|
||||
if (!isFinished && !gotAborted) {
|
||||
if (!isFinished && !isAborted) {
|
||||
for (WorkingType partialElement : partitionElement(element)) {
|
||||
final Callable<ResultType> instruction = createInstruction(partialElement);
|
||||
final ProcessorInstruction<ResultType> instruction = createInstruction(partialElement);
|
||||
if (isInstructionValid(instruction)) {
|
||||
Runnable instructionWrapper = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ResultType result = instruction.call();
|
||||
if (isResultValid(result)) {
|
||||
forwardResultToReceivers(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!gotAborted || !(e instanceof InterruptedException)) {
|
||||
onFailure(e);
|
||||
}
|
||||
} finally {
|
||||
AbstractPartitioningParallelProcessor.this.unfinishedInstructionsCounter.decrement();
|
||||
}
|
||||
}
|
||||
};
|
||||
unfinishedInstructionsCounter.increment();
|
||||
unfinishedInstructionsCounter.getAndIncrement();
|
||||
try {
|
||||
executor.execute(instructionWrapper);
|
||||
executor.execute(instruction);
|
||||
} catch (RejectedExecutionException exc){
|
||||
LOGGER.log(Level.WARNING, "A " + RejectedExecutionException.class.getSimpleName() +
|
||||
" appeared during the processing.");
|
||||
instructionWrapper.run();
|
||||
instruction.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isInstructionValid(Callable<ResultType> instruction) {
|
||||
private boolean isInstructionValid(ProcessorInstruction<ResultType> instruction) {
|
||||
return instruction != null;
|
||||
}
|
||||
|
||||
protected boolean isResultValid(ResultType result) {
|
||||
boolean isResultValid(ResultType result) {
|
||||
return result != null;
|
||||
}
|
||||
|
||||
AtomicInteger getUnfinishedInstructionsCounter() {
|
||||
return unfinishedInstructionsCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An invalid result, that won't be forwarded to the result receivers.
|
||||
*/
|
||||
@@ -91,7 +76,7 @@ public abstract class AbstractPartitioningParallelProcessor<InputType, WorkingTy
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Callable<ResultType> createInstruction(final WorkingType partialElement);
|
||||
protected abstract ProcessorInstruction<ResultType> createInstruction(final WorkingType partialElement);
|
||||
|
||||
protected abstract Iterable<WorkingType> partitionElement(InputType element);
|
||||
|
||||
@@ -105,20 +90,26 @@ public abstract class AbstractPartitioningParallelProcessor<InputType, WorkingTy
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
sleepUntilAllInstructionsFinished();
|
||||
if (!gotAborted) {
|
||||
if (!isAborted) {
|
||||
isFinished = true;
|
||||
tellResultReceiversToFinish();
|
||||
}
|
||||
}
|
||||
|
||||
protected void sleepUntilAllInstructionsFinished() throws InterruptedException {
|
||||
while (areUnfinishedInstructionsLeft()) {
|
||||
Thread.sleep(SLEEP_TIME_DURING_FINISHING);
|
||||
while (areUnfinishedInstructionsLeft() && !isAborted) {
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME_DURING_FINISHING);
|
||||
} catch (InterruptedException e) {
|
||||
if (!isAborted) {
|
||||
onFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean areUnfinishedInstructionsLeft() {
|
||||
return unfinishedInstructionsCounter.getUnfinishedInstructionsAmount() > 0;
|
||||
return unfinishedInstructionsCounter.get() > 0;
|
||||
}
|
||||
|
||||
protected void tellResultReceiversToFinish() {
|
||||
@@ -130,11 +121,14 @@ public abstract class AbstractPartitioningParallelProcessor<InputType, WorkingTy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isAborted() {
|
||||
return isAborted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
gotAborted = true;
|
||||
executor.shutdownNow();
|
||||
isAborted = true;
|
||||
tellResultReceiversToAbort();
|
||||
LOGGER.log(Level.INFO, "The processing got aborted.");
|
||||
}
|
||||
@@ -156,41 +150,4 @@ public abstract class AbstractPartitioningParallelProcessor<InputType, WorkingTy
|
||||
|
||||
protected abstract void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder);
|
||||
|
||||
/**
|
||||
* Thread safe class to manage, if there are unfinished instructions.
|
||||
*/
|
||||
private class UnfinishedInstructionsCounter {
|
||||
|
||||
private final Lock instructionsAmountLock;
|
||||
private int unfinishedInstructionsAmount;
|
||||
|
||||
public UnfinishedInstructionsCounter() {
|
||||
instructionsAmountLock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
instructionsAmountLock.lock();
|
||||
try {
|
||||
unfinishedInstructionsAmount++;
|
||||
} finally {
|
||||
instructionsAmountLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
instructionsAmountLock.lock();
|
||||
try {
|
||||
unfinishedInstructionsAmount--;
|
||||
unfinishedInstructionsAmount = Math.max(0, unfinishedInstructionsAmount);
|
||||
} finally {
|
||||
instructionsAmountLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getUnfinishedInstructionsAmount() {
|
||||
return unfinishedInstructionsAmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -21,10 +20,10 @@ public abstract class AbstractRetrievalProcessor<InputType, WorkingType, ResultT
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<ResultType> createInstruction(final WorkingType partialElement) {
|
||||
return new Callable<ResultType>() {
|
||||
protected ProcessorInstruction<ResultType> createInstruction(final WorkingType partialElement) {
|
||||
return new ProcessorInstruction<ResultType>(this) {
|
||||
@Override
|
||||
public ResultType call() throws Exception {
|
||||
public ResultType computeResult() {
|
||||
incrementRetrievedDataAmount();
|
||||
return convertWorkingToResultType(partialElement);
|
||||
}
|
||||
|
||||
+1
-2
@@ -2,7 +2,6 @@ package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
@@ -22,6 +21,6 @@ public abstract class AbstractSimpleParallelProcessor<InputType, ResultType>
|
||||
//Redefinition of the method to set the parameter name to element instead of partial element.
|
||||
//This makes the implementation of sub classes more fluent.
|
||||
@Override
|
||||
protected abstract Callable<ResultType> createInstruction(InputType element);
|
||||
protected abstract ProcessorInstruction<ResultType> createInstruction(InputType element);
|
||||
|
||||
}
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -24,10 +23,10 @@ public class ParallelFilteringProcessor<InputType> extends AbstractSimpleParalle
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<InputType> createInstruction(final InputType element) {
|
||||
return new Callable<InputType>() {
|
||||
protected ProcessorInstruction<InputType> createInstruction(final InputType element) {
|
||||
return new ProcessorInstruction<InputType>(this) {
|
||||
@Override
|
||||
public InputType call() throws Exception {
|
||||
public InputType computeResult() {
|
||||
if (filterCriterion.matches(element)) {
|
||||
return element;
|
||||
} else {
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
@@ -31,10 +30,10 @@ public class ParallelGroupedElementsValueExtractionProcessor<DataType, FunctionR
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<GroupedDataEntry<FunctionReturnType>> createInstruction(final GroupedDataEntry<DataType> element) {
|
||||
return new Callable<GroupedDataEntry<FunctionReturnType>>() {
|
||||
protected ProcessorInstruction<GroupedDataEntry<FunctionReturnType>> createInstruction(final GroupedDataEntry<DataType> element) {
|
||||
return new ProcessorInstruction<GroupedDataEntry<FunctionReturnType>>(this) {
|
||||
@Override
|
||||
public GroupedDataEntry<FunctionReturnType> call() throws Exception {
|
||||
public GroupedDataEntry<FunctionReturnType> computeResult() {
|
||||
FunctionReturnType value = extractionFunction.tryToInvoke(element.getDataEntry(), parameterProvider);
|
||||
return value != null ? new GroupedDataEntry<FunctionReturnType>(element.getKey(), value) :
|
||||
ParallelGroupedElementsValueExtractionProcessor.super.createInvalidResult();
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sse.datamining.impl.components;
|
||||
|
||||
public abstract class ProcessorInstruction<ResultType> implements Runnable {
|
||||
|
||||
private final AbstractPartitioningParallelProcessor<?, ?, ResultType> processor;
|
||||
|
||||
public ProcessorInstruction(AbstractPartitioningParallelProcessor<?, ?, ResultType> processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ResultType result = computeResult();
|
||||
if (processor.isResultValid(result) && !processor.isAborted()) {
|
||||
processor.forwardResultToReceivers(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!processor.isAborted() || !(e instanceof InterruptedException)) {
|
||||
processor.onFailure(e);
|
||||
}
|
||||
} finally {
|
||||
processor.getUnfinishedInstructionsCounter().getAndDecrement();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ResultType computeResult() throws Exception;
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,7 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.components.aggregators;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -9,6 +8,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor;
|
||||
import com.sap.sse.datamining.impl.components.ProcessorInstruction;
|
||||
|
||||
public abstract class AbstractParallelStoringAggregationProcessor<InputType, AggregatedType>
|
||||
extends AbstractSimpleParallelProcessor<InputType, AggregatedType> {
|
||||
@@ -27,10 +27,10 @@ public abstract class AbstractParallelStoringAggregationProcessor<InputType, Agg
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<AggregatedType> createInstruction(final InputType element) {
|
||||
return new Callable<AggregatedType>() {
|
||||
protected ProcessorInstruction<AggregatedType> createInstruction(final InputType element) {
|
||||
return new ProcessorInstruction<AggregatedType>(this) {
|
||||
@Override
|
||||
public AggregatedType call() throws Exception {
|
||||
public AggregatedType computeResult() {
|
||||
storeLock.lock();
|
||||
try {
|
||||
storeElement(element);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package java.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p><b>Do not use!</b></p>
|
||||
@@ -9,13 +10,43 @@ import java.io.Serializable;
|
||||
*/
|
||||
public class UUID implements Serializable, Comparable<UUID> {
|
||||
private static final long serialVersionUID = -3096287568577694784L;
|
||||
|
||||
private static final Random numberGenerator = new Random();
|
||||
|
||||
public static UUID fromString(String value) {
|
||||
public static UUID fromString(String value) {
|
||||
return new UUID(value);
|
||||
}
|
||||
|
||||
public static UUID randomUUID() {
|
||||
throw new UnsupportedOperationException("Not supported for emulation");
|
||||
//Creating a random byte array, analog to java.util.UUID.randomUUID()
|
||||
byte[] randomBytes = new byte[16];
|
||||
numberGenerator.nextBytes(randomBytes);
|
||||
randomBytes[6] &= 0x0f; /* clear version */
|
||||
randomBytes[6] |= 0x40; /* set to version 4 */
|
||||
randomBytes[8] &= 0x3f; /* clear variant */
|
||||
randomBytes[8] |= 0x80; /* set to IETF variant */
|
||||
|
||||
//Converting the byte array to two longs, analog to the constructor
|
||||
//UUID(byte[] data) of java.util.UUID
|
||||
long mostSigBits = 0;
|
||||
long leastSigBits = 0;
|
||||
for (int i=0; i<8; i++)
|
||||
mostSigBits = (mostSigBits << 8) | (randomBytes[i] & 0xff);
|
||||
for (int i=8; i<16; i++)
|
||||
leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xff);
|
||||
|
||||
//Converting the two longs to a String, analog to java.util.UUID.toString()
|
||||
return new UUID((digits(mostSigBits >> 32, 8) + "-" +
|
||||
digits(mostSigBits >> 16, 4) + "-" +
|
||||
digits(mostSigBits, 4) + "-" +
|
||||
digits(leastSigBits >> 48, 4) + "-" +
|
||||
digits(leastSigBits, 12)));
|
||||
}
|
||||
|
||||
/** Returns val represented by the specified number of hex digits. */
|
||||
private static String digits(long val, int digits) {
|
||||
long hi = 1L << (digits * 4);
|
||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
||||
}
|
||||
|
||||
private String uuidAsString;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="resources"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sse.threadmanager</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,7 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,21 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Threadmanager
|
||||
Bundle-SymbolicName: com.sap.sse.threadmanager
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Require-Bundle: com.sun.jersey;bundle-version="1.17.0",
|
||||
javax.servlet;bundle-version="3.1.0",
|
||||
org.apache.shiro.core;bundle-version="1.2.2",
|
||||
org.apache.shiro.web;bundle-version="1.2.2",
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sse.security,
|
||||
com.sap.sse.security.common,
|
||||
com.sap.sse.security.userstore.mongodb,
|
||||
com.sap.sse,
|
||||
com.sap.sse.common
|
||||
Import-Package: javax.ws.rs;version="1.1.1",
|
||||
javax.ws.rs.core,
|
||||
org.osgi.framework;version="1.8.0"
|
||||
Web-ContextPath: /threadmanager
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
|
||||
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
|
||||
|
||||
<!-- Disable directory listing: -->
|
||||
<servlet>
|
||||
<servlet-name>default</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet
|
||||
</servlet-class>
|
||||
<init-param>
|
||||
<param-name>dirAllowed</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
|
||||
<!-- Apache Shiro -->
|
||||
<context-param>
|
||||
<param-name>shiroEnvironmentClass</param-name>
|
||||
<param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value>
|
||||
</context-param>
|
||||
<listener>
|
||||
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
|
||||
</listener>
|
||||
<filter>
|
||||
<filter-name>ShiroFilter</filter-name>
|
||||
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
|
||||
</filter>
|
||||
<!-- Make sure any request you want accessible to Shiro is filtered. "/*"
|
||||
catches all requests. Usually this filter mapping is defined first (before all
|
||||
others) to ensure that Shiro works in subsequent filters in the filter chain: -->
|
||||
<filter-mapping>
|
||||
<filter-name>ShiroFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>INCLUDE</dispatcher>
|
||||
<dispatcher>ERROR</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Jersey REST API</servlet-name>
|
||||
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
|
||||
<init-param>
|
||||
<param-name>javax.ws.rs.Application</param-name>
|
||||
<param-value>com.sap.sse.threadmanager.RestApiApplication</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
|
||||
<param-value>com.sap.sse.threadmanager.AccessControlAndEncodingResponseFilter</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Jersey REST API</servlet-name>
|
||||
<url-pattern>/api/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
source.. = src/,\
|
||||
resources/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
WEB-INF/
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sse.threadmanager</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
[main]
|
||||
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
|
||||
credentialsMatcher.storedCredentialsHexEncoded = false
|
||||
credentialsMatcher.hashIterations = 1024
|
||||
|
||||
# Realm configuration:
|
||||
# --------------------
|
||||
|
||||
# Uncomment the following line to specify a bundle-specific permissions-for-role provider
|
||||
# permissionsForRoleProvider = com.sap.myapp....MyAppPermissionsForRoleProvider
|
||||
upRealm = com.sap.sse.security.UsernamePasswordRealm
|
||||
upRealm.credentialsMatcher = $credentialsMatcher
|
||||
# Uncomment the following line make the upRealm aware of the permissionsForRoleProvider
|
||||
# upRealm.permissionsForRoleProvider = $permissionsForRoleProvider
|
||||
oauthRealm = com.sap.sse.security.OAuthRealm
|
||||
# Uncomment the following line make the oauthRealm aware of the permissionsForRoleProvider
|
||||
# oauthRealm.permissionsForRoleProvider = $permissionsForRoleProvider
|
||||
bearerTokenRealm = com.sap.sse.security.BearerTokenRealm
|
||||
# Uncomment the following line make the bearerTokenRealm aware of the permissionsForRoleProvider
|
||||
# bearerTokenRealm.permissionsForRoleProvider = $permissionsForRoleProvider
|
||||
|
||||
# Putting it all together:
|
||||
sessionManager = com.sap.sse.security.SecurityWebSessionManager
|
||||
securityManager.sessionManager = $sessionManager
|
||||
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
|
||||
securityManager.sessionManager.sessionDAO = $sessionDAO
|
||||
cacheManager = com.sap.sse.security.SessionCacheManager
|
||||
securityManager.cacheManager = $cacheManager
|
||||
|
||||
# Authentication Filter Configurations
|
||||
# ------------------------------------
|
||||
|
||||
# A filter that requires the user to have at least one of the roles specified as
|
||||
# filter parameter. This makes it different from the default roles[...] filter
|
||||
# which requires the user to have ALL of the roles specified as parameters.
|
||||
anyofroles = com.sap.sse.security.AnyOfRolesFilter
|
||||
|
||||
# A custom filter for GWT pages that require an authenticated user.
|
||||
# Forwards unauthenticated users to the default login page. When
|
||||
# addressed directly (and not based on a redirect), users who logged
|
||||
# on successfully will be redirected to the UserManagement.html page
|
||||
# where they can adjust their profile.
|
||||
customGwt = com.sap.sse.security.CustomFilter
|
||||
customGwt.loginUrl = /security/ui/Login.html
|
||||
customGwt.successUrl = /UserManagement.html
|
||||
|
||||
# Configuration for the default shiro HTTP form authentication filter.
|
||||
# It assumes that form-based login parameters are sent to the
|
||||
# /api/restsecurity/login RESTlet and forwards successful login attempts
|
||||
# to the /api/restsecurity/hello service which is expected to respond
|
||||
# with a JSON document containing the authenticated subject's properties.
|
||||
authc.loginUrl = /api/restsecurity/login
|
||||
authc.successUrl = /api/restsecurity/hello
|
||||
|
||||
# This authentication filter accepts a bearer access token in the HTTP
|
||||
# Authorization header field, as in
|
||||
# Authorization: Bearer 1029741026501365024376093245
|
||||
# If no such bearer token is provided, the filter falls back to basic HTTP
|
||||
# authentication ("Authentication: Basic ...") and then regular form-based
|
||||
# authentication with POST parameters "username" and "password".
|
||||
bearerToken = com.sap.sse.security.BearerTokenOrBasicOrFormAuthenticationFilter
|
||||
|
||||
# Specifying filter chains for URL patterns
|
||||
|
||||
[urls]
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.sap.sse.threadmanager;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import com.sun.jersey.spi.container.ContainerRequest;
|
||||
import com.sun.jersey.spi.container.ContainerResponse;
|
||||
import com.sun.jersey.spi.container.ContainerResponseFilter;
|
||||
|
||||
public class AccessControlAndEncodingResponseFilter implements ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
|
||||
MultivaluedMap<String, Object> httpHeaders = response.getHttpHeaders();
|
||||
httpHeaders.add("Access-Control-Allow-Origin", "*");
|
||||
httpHeaders.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type");
|
||||
httpHeaders.add("Access-Control-Expose-Headers", "Location, Content-Disposition");
|
||||
httpHeaders.add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, HEAD, OPTIONS");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.sap.sse.threadmanager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.Application;
|
||||
|
||||
public class RestApiApplication extends Application {
|
||||
public Set<Class<?>> getClasses() {
|
||||
HashSet<Class<?>> classes = new HashSet<>();
|
||||
classes.add(ThreadManager.class);
|
||||
return classes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.sap.sse.threadmanager;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
@Path("/threads")
|
||||
public class ThreadManager {
|
||||
@Context ServletContext servletContext;
|
||||
|
||||
@Path("")
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response getThreads() {
|
||||
JSONArray threadsJson = new JSONArray();
|
||||
Thread[] threads = new Thread[10000];
|
||||
Thread.enumerate(threads);
|
||||
for (Thread t : threads) {
|
||||
if (t != null) {
|
||||
JSONObject threadJson = new JSONObject();
|
||||
threadJson.put("name", t.getName());
|
||||
threadJson.put("id", t.getId());
|
||||
threadJson.put("daemon", t.isDaemon());
|
||||
threadJson.put("alive", t.isAlive());
|
||||
threadJson.put("threadgroup", t.getThreadGroup().getName());
|
||||
threadsJson.add(threadJson);
|
||||
}
|
||||
}
|
||||
String json = threadsJson.toJSONString();
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // using Thread.suspend()
|
||||
@Path("{name}/suspend")
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response suspend(@PathParam("name") String name) {
|
||||
final Response response;
|
||||
JSONObject result = new JSONObject();
|
||||
Thread[] threads = new Thread[10000];
|
||||
boolean found = false;
|
||||
Thread.enumerate(threads);
|
||||
for (Thread t : threads) {
|
||||
if (t != null && t.getName().equals(name)) {
|
||||
t.suspend();
|
||||
result.put("status", "OK");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
String json = result.toJSONString();
|
||||
if (!found) {
|
||||
result.put("status", "Not found");
|
||||
response = Response.status(Status.NOT_FOUND).entity(json).build();
|
||||
} else {
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // using Thread.suspend()
|
||||
@Path("{name}/resume")
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response resume(@PathParam("name") String name) {
|
||||
final Response response;
|
||||
JSONObject result = new JSONObject();
|
||||
Thread[] threads = new Thread[10000];
|
||||
boolean found = false;
|
||||
Thread.enumerate(threads);
|
||||
for (Thread t : threads) {
|
||||
if (t != null && t.getName().equals(name)) {
|
||||
t.resume();
|
||||
result.put("status", "OK");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
String json = result.toJSONString();
|
||||
if (!found) {
|
||||
result.put("status", "Not found");
|
||||
response = Response.status(Status.NOT_FOUND).entity(json).build();
|
||||
} else {
|
||||
response = Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -697,7 +697,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the key from the cache. If any updates are still running, they may again insert the key into hte cache.
|
||||
* Removes the key from the cache. If any updates are still running, they may again insert the key into the cache.
|
||||
*/
|
||||
public void remove(K key) {
|
||||
cache(key, null);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<module>com.sap.sse.security.userstore.mongodb</module>
|
||||
<module>com.sap.sse.operationaltransformation</module>
|
||||
<module>com.sap.sse.replication</module>
|
||||
<module>com.sap.sse.threadmanager</module>
|
||||
<module>com.sap.sse.filestorage</module>
|
||||
<module>com.sap.sse.gwt.theme</module>
|
||||
<module>com.sap.sailing.domain.common</module>
|
||||
|
||||
@@ -349,8 +349,6 @@ _see [bug 2652](http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=2652)_
|
||||
|
||||
Instead of the checkin/checkout process of the tracking app, marks can be pinged using an API that hides the inner workings on the server completely. The server creates a device-mapping in the regatta-log for the exact timepoint of every fix, and adds the fixes to the GPSFixStore.
|
||||
|
||||
The interface (apart from the path) is identical to [Send Measurements](#fixes). Several fixes can be sent at once, but in the interest of pinging a mark, this should usually just be a single fix.
|
||||
|
||||
**Path:** ``leaderboards/{leaderboard-name}/marks/{mark-id}/gps_fixes``
|
||||
|
||||
**Verb:** ``POST``
|
||||
@@ -358,16 +356,20 @@ The interface (apart from the path) is identical to [Send Measurements](#fixes).
|
||||
**Request:**
|
||||
```
|
||||
{
|
||||
"deviceUuid" : "af855a56-9726-4a9c-a77e-da955bd289bf",
|
||||
"fixes" : [
|
||||
{
|
||||
"timestamp" : 14144160080000,
|
||||
"latitude" : 54.325246,
|
||||
"longitude" : 10.148556,
|
||||
"speed" : 3.61,
|
||||
"course" : 258.11,
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
If there is no existent GPS Fix for the Mark HTTP/200 will be returned.
|
||||
If there is an existent GPS Fix the latest known Position of the Mark will be returned:
|
||||
```
|
||||
{
|
||||
"timestamp" : 14144160080000,
|
||||
"latitude" : 54.325246,
|
||||
"longitude" : 10.148556,
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user