Merge branch 'master' into bug2707

This commit is contained in:
Axel Uhl committed 2015-03-20 17:17:06 +01:00
commit f1a52dc719
82 files changed
+1860 -888

No files matched your search

+1 -1
View File
@@ -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..."
@@ -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);
@@ -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
@@ -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;
@@ -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;
}
}
@@ -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);
}
}
@@ -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();
}
@@ -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());
}
}
+451 -444
View File
@@ -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>
+7 -3
View File
@@ -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;
@@ -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 "";
@@ -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();
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
}
}
@@ -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;
}
}
@@ -6,4 +6,8 @@ public interface VideoSynchPlayer extends VideoPlayerWithWidget, MediaSynchAdapt
void setEditFlag(EditFlag editFlag);
int getDefaultWidth();
int getDefaultHeight();
}
@@ -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);
@@ -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));
}
@@ -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();
@@ -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
@@ -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 {
@@ -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());
@@ -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
@@ -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() {
@@ -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);
@@ -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();
@@ -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*/);
@@ -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() {
@@ -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";
@@ -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;
}
@@ -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("&nbsp;");
if (mediaPlayerManagerComponent.isPlaying()) {
mediaSelectionButton.addStyleDependentName("mediaplaying");
} else {
mediaSelectionButton.setText(caption);
mediaSelectionButton.removeStyleDependentName("mediaplaying");
}
mediaSelectionButton.setText(caption);
mediaSelectionButton.setTitle(tooltip);
mediaManagementButton.setVisible(mediaPlayerManagerComponent.allowsEditing());
}
@@ -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;
}
@@ -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);
@@ -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);
}
};
@@ -0,0 +1,7 @@
package com.sap.sse.datamining.shared;
import java.io.Serializable;
public interface DataMiningSession extends Serializable {
}
@@ -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();
/**
@@ -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
}
@@ -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();
}
@@ -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() {
@@ -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;
}
}
@@ -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() {
@@ -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) {
}
};
}
}
@@ -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);
@@ -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;
}
};
@@ -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;
}
};
@@ -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) {
@@ -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() {
@@ -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) {
@@ -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 + "'");
}
}
}
@@ -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) {
@@ -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);
}
@@ -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;
}
}
}
@@ -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);
}
@@ -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);
}
@@ -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 {
@@ -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();
@@ -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;
}
@@ -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>
+28
View File
@@ -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/
+12
View File
@@ -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]
@@ -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);
+1
View File
@@ -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>
+11 -9
View File
@@ -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,
}
```