mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-02 10:23:51 +00:00
Merge branch 'master' into polar-api
Conflicts: java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
This commit is contained in:
commit
64fe82c2d8
222 files changed
+3148
-6309
No files matched your search
@@ -346,7 +346,7 @@ if [[ "$@" == "hot-deploy" ]]; then
|
||||
echo -n "Connecting to OSGi server..."
|
||||
NC_CMD="nc -t 127.0.0.1 $OSGI_TELNET_PORT"
|
||||
echo "OK"
|
||||
OLD_BUNDLE_INFORMATION=`echo -n ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
OLD_BUNDLE_INFORMATION=`echo ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
BUNDLE_ID=`echo $OLD_BUNDLE_INFORMATION | cut -d " " -f 1`
|
||||
OLD_ACTIVATED_NAME=`echo $OLD_BUNDLE_INFORMATION | cut -d " " -f 3`
|
||||
echo "Could identify bundle-id $BUNDLE_ID for $OLD_ACTIVATED_NAME"
|
||||
@@ -361,11 +361,11 @@ if [[ "$@" == "hot-deploy" ]]; then
|
||||
fi
|
||||
|
||||
# stop and uninstall
|
||||
echo -n stop $BUNDLE_ID | $NC_CMD > /dev/null
|
||||
echo -n uninstall $BUNDLE_ID | $NC_CMD > /dev/null
|
||||
echo stop $BUNDLE_ID | $NC_CMD > /dev/null
|
||||
echo uninstall $BUNDLE_ID | $NC_CMD > /dev/null
|
||||
|
||||
# make sure bundle is removed
|
||||
UNINSTALL_INFORMATION=`echo -n ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
UNINSTALL_INFORMATION=`echo ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
if [[ $UNINSTALL_INFORMATION == "" ]]; then
|
||||
echo "Uninstall procedure sucessful!"
|
||||
else
|
||||
@@ -374,14 +374,14 @@ if [[ "$@" == "hot-deploy" ]]; then
|
||||
fi
|
||||
|
||||
# now reinstall bundle
|
||||
NEW_BUNDLE_ID=`echo -n install file://$SERVERS_HOME/$active_branch/plugins/deploy/${NEW_BUNDLE_BASENAME}.jar | $NC_CMD`
|
||||
NEW_BUNDLE_INFORMATION=`echo -n ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
NEW_BUNDLE_ID=`echo install file://$SERVERS_HOME/$active_branch/plugins/deploy/${NEW_BUNDLE_BASENAME}.jar | $NC_CMD`
|
||||
NEW_BUNDLE_INFORMATION=`echo ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_`
|
||||
NEW_BUNDLE_ID=`echo $NEW_BUNDLE_INFORMATION | cut -d " " -f 1`
|
||||
echo "Installed new bundle file://$SERVERS_HOME/$active_branch/plugins/deploy/${NEW_BUNDLE_BASENAME}.jar with id $NEW_BUNDLE_ID"
|
||||
|
||||
# and start
|
||||
echo -n start $NEW_BUNDLE_ID | $NC_CMD > /dev/null && sleep 1
|
||||
NEW_BUNDLE_STATUS=`echo -n ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_ | grep ACTIVE`
|
||||
echo start $NEW_BUNDLE_ID | $NC_CMD > /dev/null && sleep 1
|
||||
NEW_BUNDLE_STATUS=`echo ss | $NC_CMD | grep ${OSGI_BUNDLE_NAME}_ | grep ACTIVE`
|
||||
if [[ $NEW_BUNDLE_STATUS == "" ]]; then
|
||||
echo "ERROR: Something went wrong with start of bundle. Please check if everything went ok."
|
||||
exit
|
||||
|
||||
@@ -151,7 +151,7 @@ def compute_branch(branch_name)
|
||||
branch.shared_size += blob.size
|
||||
branch.shared_packed_size += blob.packed_size
|
||||
else
|
||||
if dependable_blob_shas.include?(blob.sha)
|
||||
if $dependable_blob_shas.include?(blob.sha)
|
||||
branch.non_shared_dependable_size += blob.size
|
||||
branch.non_shared_dependable_packed_size += blob.packed_size
|
||||
else
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -22,6 +23,12 @@ public class Util {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T[] toArray(Iterable<T> what, T[] arr) {
|
||||
List<T> list = new ArrayList<T>();
|
||||
addAll(what, list);
|
||||
return list.toArray(arr);
|
||||
}
|
||||
|
||||
public static <T> int size(Iterable<T> i) {
|
||||
if (i instanceof Collection<?>) {
|
||||
return ((Collection<?>) i).size();
|
||||
|
||||
+5
-8
@@ -5,6 +5,7 @@ import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -16,6 +17,7 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiWindListener;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.AWA;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.AWS;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.COG;
|
||||
@@ -23,23 +25,18 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.GpsLatLong;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.HDG;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.SOG;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
|
||||
public class WindReceiverTest {
|
||||
@Test
|
||||
public void simpleWindReceiverTest() {
|
||||
final List<Wind> windReceived = new ArrayList<>();
|
||||
final String deviceSerialNumber = "Non-Existing Test Device";
|
||||
IgtimiWindReceiver receiver = new IgtimiWindReceiver(deviceSerialNumber);
|
||||
receiver.addListener(new WindListener() {
|
||||
IgtimiWindReceiver receiver = new IgtimiWindReceiver(Collections.singleton(deviceSerialNumber));
|
||||
receiver.addListener(new IgtimiWindListener() {
|
||||
@Override
|
||||
public void windDataReceived(Wind wind) {
|
||||
public void windDataReceived(Wind wind, String deviceSerialNumber) {
|
||||
windReceived.add(wind);
|
||||
}
|
||||
@Override
|
||||
public void windDataRemoved(Wind wind) {}
|
||||
@Override
|
||||
public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {}
|
||||
});
|
||||
TimePoint timePoint = MillisecondsTimePoint.now();
|
||||
Map<Integer, Object> awaMap = new HashMap<>(); awaMap.put(1, 123. /* degrees from */);
|
||||
|
||||
+21
-9
@@ -6,9 +6,11 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -20,11 +22,8 @@ import org.junit.Test;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.igtimiadapter.Account;
|
||||
import com.sap.sailing.domain.igtimiadapter.DataAccessWindow;
|
||||
import com.sap.sailing.domain.igtimiadapter.Group;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
|
||||
import com.sap.sailing.domain.igtimiadapter.Permission;
|
||||
import com.sap.sailing.domain.igtimiadapter.Resource;
|
||||
import com.sap.sailing.domain.igtimiadapter.Session;
|
||||
@@ -33,14 +32,17 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.AWA;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.AWS;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.igtimiadapter.impl.Activator;
|
||||
|
||||
public class BasicIgtimiAdapterTest extends AbstractTestWithIgtimiConnection {
|
||||
@Test
|
||||
public void testGetUsers() throws ClientProtocolException, IllegalStateException, IOException, ParseException {
|
||||
Iterable<User> users = connection.getUsers();
|
||||
assertEquals(1, Util.size(users));
|
||||
assertEquals(connection.getAccount().getUser().getId(), users.iterator().next().getId());
|
||||
assertEquals(2, Util.size(users));
|
||||
Set<Long> userIds = new HashSet<>();
|
||||
for (User user : users) {
|
||||
userIds.add(user.getId());
|
||||
}
|
||||
assertTrue(userIds.contains(connection.getAccount().getUser().getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,9 +115,6 @@ public class BasicIgtimiAdapterTest extends AbstractTestWithIgtimiConnection {
|
||||
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.GERMAN);
|
||||
TimePoint start = new MillisecondsTimePoint(dateFormat.parse("2013-11-09T07:00:00Z"));
|
||||
TimePoint end = new MillisecondsTimePoint(dateFormat.parse("2013-11-09T07:10:00Z"));
|
||||
final IgtimiConnectionFactory connectionFactory = Activator.getInstance().getConnectionFactory();
|
||||
Account account = connectionFactory.registerAccountForWhichClientIsAuthorized("3b6cbd0522423bb1ac274ddb9e7e579c4b3be6667622271086c4fdbf30634ba9");
|
||||
IgtimiConnection connection = connectionFactory.connect(account);
|
||||
// URL is https://www.igtimi.com/api/v1/devices/data_access_windows?type=read&start_time=1383811200000&end_time=1383933600000&access_token=3b6cbd0522423bb1ac274ddb9e7e579c4b3be6667622271086c4fdbf30634ba9
|
||||
Iterable<DataAccessWindow> daws = connection.getDataAccessWindows(Permission.read, start, end, /* deviceSerialNumbers; get all devices available for that time */ null);
|
||||
Set<String> deviceSerialNumbers = new HashSet<>();
|
||||
@@ -132,4 +131,17 @@ public class BasicIgtimiAdapterTest extends AbstractTestWithIgtimiConnection {
|
||||
assertTrue(foundWind);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadLatestData() throws IllegalStateException, ClientProtocolException, IOException, ParseException {
|
||||
Iterable<Fix> fixes = connection.getLatestFixes(Arrays.asList(new String[] { "DD-EE-AAHG", "GA-EN-AAEA", "DD-EE-AAGA" }), Type.SOG );
|
||||
assertEquals(2, Util.size(fixes));
|
||||
Iterator<Fix> i = fixes.iterator();
|
||||
Fix fix1 = i.next();
|
||||
assertEquals("DD-EE-AAGA", fix1.getSensor().getDeviceSerialNumber());
|
||||
assertEquals(Type.SOG, fix1.getType());
|
||||
Fix fix2 = i.next();
|
||||
assertEquals("DD-EE-AAHG", fix2.getSensor().getDeviceSerialNumber());
|
||||
assertEquals(Type.SOG, fix2.getType());
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.igtimiadapter.impl.FixFactory;
|
||||
|
||||
public class LatestDatumTest {
|
||||
|
||||
private final String sample1 = "{\"latest_data\":[{\"latest_datum\":{\"serial_number\":\"DD-EE-AAGA\",\"resource_id\":1012353,\"c1\":0.5556,\"timestamp\":1384091813000.0}},{\"latest_datum\":{\"serial_number\":\"DD-EE-AAHG\",\"resource_id\":1012356,\"c1\":0.3704,\"timestamp\":1384078160000.0}}]}";
|
||||
private final String sample2 = "{\"latest_data\":[{\"latest_datum\":{\"serial_number\":\"DD-EE-AAHG\",\"resource_id\":1012356,\"c1\":4.0744,\"timestamp\":1384078157500.0}}]}";
|
||||
|
||||
@Test
|
||||
public void testFixProductionFromSample1() throws ParseException {
|
||||
Iterable<Fix> fixes = new FixFactory().createFixesFromLastDatum((JSONObject) new JSONParser().parse(sample1), Type.SOG);
|
||||
assertEquals(2, Util.size(fixes));
|
||||
Iterator<Fix> i = fixes.iterator();
|
||||
Fix fix1 = i.next();
|
||||
assertEquals("DD-EE-AAGA", fix1.getSensor().getDeviceSerialNumber());
|
||||
assertEquals(Type.SOG, fix1.getType());
|
||||
Fix fix2 = i.next();
|
||||
assertEquals("DD-EE-AAHG", fix2.getSensor().getDeviceSerialNumber());
|
||||
assertEquals(Type.SOG, fix2.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixProductionFromSample2() throws ParseException {
|
||||
Iterable<Fix> fixes = new FixFactory().createFixesFromLastDatum((JSONObject) new JSONParser().parse(sample2), Type.AWS);
|
||||
assertEquals(1, Util.size(fixes));
|
||||
Iterator<Fix> i = fixes.iterator();
|
||||
Fix fix1 = i.next();
|
||||
assertEquals("DD-EE-AAHG", fix1.getSensor().getDeviceSerialNumber());
|
||||
assertEquals(Type.AWS, fix1.getType());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -165,6 +165,6 @@ public class WebSocketTest {
|
||||
});
|
||||
assertNotNull(liveDataConnection);
|
||||
assertTrue("Connection handshake not successful within 5s", liveDataConnection.waitForConnection(5000l));
|
||||
liveDataConnection.disconnect();
|
||||
liveDataConnection.stop();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
.,\
|
||||
WEB-INF/
|
||||
+21
-1
@@ -10,7 +10,9 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A connection to the Igtimi system for one {@link Client} and one {@link Account}.
|
||||
@@ -92,7 +94,7 @@ public interface IgtimiConnection {
|
||||
* are forwarded in the batches in which they are received to the listeners that can be added to the live connection
|
||||
* using {@link LiveDataConnection#addListener(BulkFixReceiver)}.
|
||||
*
|
||||
* @return a connection that the caller can use to stop the live feed by calling {@link LiveDataConnection#disconnect()}.
|
||||
* @return a connection that the caller can use to stop the live feed by calling {@link LiveDataConnection#stop()}.
|
||||
*/
|
||||
LiveDataConnection createLiveConnection(Iterable<String> deviceSerialNumbers) throws Exception;
|
||||
|
||||
@@ -141,4 +143,22 @@ public interface IgtimiConnection {
|
||||
Iterable<Group> getGroups() throws IllegalStateException, ClientProtocolException, IOException, ParseException;
|
||||
|
||||
Account getAccount();
|
||||
|
||||
/**
|
||||
* Finds all data access windows that have wind data for the time span around the race, loads their wind data and
|
||||
* {@link DynamicTrackedRace#recordWind(com.sap.sailing.domain.tracking.Wind, com.sap.sailing.domain.common.WindSource)
|
||||
* records it} in the tracked races.
|
||||
*
|
||||
* @return the number of wind fixes imported per tracked race; contains an entry for all elements in
|
||||
* <code>trackedRaces</code>
|
||||
*/
|
||||
Map<TrackedRace, Integer> importWindIntoRace(Iterable<DynamicTrackedRace> trackedRaces) throws IllegalStateException,
|
||||
ClientProtocolException, IOException, ParseException;
|
||||
|
||||
/**
|
||||
* Returns the latest datum for the specified devices that contains a fix of the <code>type</code> requested. The
|
||||
* result contains entries only for those devices that have actually produced a fix of the <code>type</code> requested
|
||||
* that is readable by the {@link #getAccount()} used by this connection.
|
||||
*/
|
||||
Iterable<Fix> getLatestFixes(Iterable<String> deviceSerialNumbers, Type type) throws IllegalStateException, ClientProtocolException, IOException, ParseException;
|
||||
}
|
||||
+6
@@ -22,6 +22,12 @@ public interface IgtimiConnectionFactory {
|
||||
|
||||
IgtimiConnection connect(Account account);
|
||||
|
||||
/**
|
||||
* Removes the account and the credentials associated with it permanently. The account is identified by the e-mail
|
||||
* address of the owner of the data to which the account granted access. See also {@link #getExistingAccountByEmail(String)}.
|
||||
*/
|
||||
void removeAccount(String eMail);
|
||||
|
||||
/**
|
||||
* Obtains a URL that a user agent (e.g., a web browser) can be sent to in order to allow that user to authenticate
|
||||
* and then authorize this factory's {@link Client} for accessing the user's Igtimi data. The URL is chosen such that
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.sap.sailing.domain.igtimiadapter;
|
||||
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
|
||||
public interface IgtimiWindListener {
|
||||
void windDataReceived(Wind wind, String deviceSerialNumber);
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ public interface LiveDataConnection {
|
||||
/**
|
||||
* Disconnects this connection. Afterwards, the connection will no longer feed live data to its listener(s).
|
||||
*/
|
||||
void disconnect() throws Exception;
|
||||
void stop() throws Exception;
|
||||
|
||||
/**
|
||||
* Waits for a successful connection for <code>timeoutInMillis</code> milliseconds. If the connection is successful
|
||||
|
||||
+12
-1
@@ -1,11 +1,22 @@
|
||||
package com.sap.sailing.domain.igtimiadapter;
|
||||
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
|
||||
|
||||
/**
|
||||
* You can think of resources really as meta-info - identifying time blocks of data that have some meaning. For an
|
||||
* Igtimi device it's a power cycle. However data access is not forced to be "through" a resource. If you only wanted to
|
||||
* get data from a specific resource then of course you would just use the start and end time stamps in the request.
|
||||
* Resources are meant to be non-overlapping, although this is not strictly enforced.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface Resource extends HasId, HasPermissions, HasStartAndEndTime {
|
||||
|
||||
boolean isBlob();
|
||||
|
||||
int[] getDataTypes();
|
||||
Iterable<Type> getDataTypes();
|
||||
|
||||
String getDeviceSerialNumber();
|
||||
|
||||
|
||||
+10
-1
@@ -12,6 +12,7 @@ import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
|
||||
import com.sap.sailing.domain.igtimiadapter.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.igtimiadapter.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.igtimiadapter.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
||||
|
||||
/**
|
||||
* Maintains data about a default {@link Client} that represents this application when interacting with the Igtimi
|
||||
@@ -33,7 +34,8 @@ public class Activator implements BundleActivator {
|
||||
private static final String CLIENT_ID_PROPERTY_NAME = "igtimi.client.id";
|
||||
private static final String CLIENT_SECRET_PROPERTY_NAME = "igtimi.client.secret";
|
||||
private static final String CLIENT_REDIRECT_URI_PROPERTY_NAME = "igtimi.client.redirecturi";
|
||||
private IgtimiConnectionFactoryImpl connectionFactory;
|
||||
private final IgtimiConnectionFactoryImpl connectionFactory;
|
||||
private final IgtimiWindTrackerFactory windTrackerFactory;
|
||||
|
||||
public Activator() throws ClientProtocolException, IllegalStateException, IOException, ParseException {
|
||||
final String clientId = System.getProperty(CLIENT_ID_PROPERTY_NAME, DEFAULT_CLIENT_ID);
|
||||
@@ -43,12 +45,15 @@ public class Activator implements BundleActivator {
|
||||
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory();
|
||||
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory();
|
||||
connectionFactory = new IgtimiConnectionFactoryImpl(client, domainObjectFactory, mongoObjectFactory);
|
||||
windTrackerFactory = new IgtimiWindTrackerFactory(connectionFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
INSTANCE = this;
|
||||
context.registerService(IgtimiConnectionFactory.class, connectionFactory, /* properties */ null);
|
||||
context.registerService(WindTrackerFactory.class, windTrackerFactory, /* properties */ null);
|
||||
context.registerService(IgtimiWindTrackerFactory.class, windTrackerFactory, /* properties */ null);
|
||||
}
|
||||
|
||||
public static Activator getInstance() throws ClientProtocolException, IllegalStateException, IOException, ParseException {
|
||||
@@ -61,6 +66,10 @@ public class Activator implements BundleActivator {
|
||||
public IgtimiConnectionFactoryImpl getConnectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
public IgtimiWindTrackerFactory getWindTrackerFactory() {
|
||||
return windTrackerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
|
||||
+28
-1
@@ -28,7 +28,8 @@ public class FixFactory {
|
||||
String deviceSerialNumber = (String) e.getKey();
|
||||
JSONObject typesJson = (JSONObject) e.getValue();
|
||||
for (Entry<Object, Object> fixTypeAndFixesJson : typesJson.entrySet()) {
|
||||
final String[] fixTypeAndOptionalColonSeparatedSensorsSubId = ((String) fixTypeAndFixesJson.getKey()).split(":");
|
||||
final String fixTypeAndOptionalSensorId = (String) fixTypeAndFixesJson.getKey();
|
||||
final String[] fixTypeAndOptionalColonSeparatedSensorsSubId = fixTypeAndOptionalSensorId.split(":");
|
||||
int fixType = Integer.valueOf(fixTypeAndOptionalColonSeparatedSensorsSubId[0]);
|
||||
JSONObject fixesJson = (JSONObject) fixTypeAndFixesJson.getValue();
|
||||
JSONArray timePointsMillis = (JSONArray) fixesJson.get("t");
|
||||
@@ -53,6 +54,32 @@ public class FixFactory {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastDataJson expected to use "c1", "c2", ... instead of "1" and "2" for the sensor parameters, and
|
||||
* "timestamp" instead of "t" for the timestamp. The values are not provided as arrays but as single values.
|
||||
*/
|
||||
public Iterable<Fix> createFixesFromLastDatum(JSONObject lastDataJson, Type type) {
|
||||
List<Fix> result = new ArrayList<>();
|
||||
JSONArray latestDataArray = (JSONArray) lastDataJson.get("latest_data");
|
||||
for (Object d : latestDataArray) {
|
||||
JSONObject latestDatum = (JSONObject) ((JSONObject) d).get("latest_datum");
|
||||
String serialNumber = (String) latestDatum.get("serial_number");
|
||||
// there is a field called "resource_id" but we're currently ignoring it because not all fixes have one and we currently
|
||||
// don't have a use for it
|
||||
Map<Integer, Object> valuesPerSubindex = new HashMap<>();
|
||||
int i=1;
|
||||
Object c_i;
|
||||
while ((c_i=latestDatum.get("c"+i)) != null) {
|
||||
valuesPerSubindex.put(i, c_i);
|
||||
i++;
|
||||
}
|
||||
Sensor sensor = new SensorImpl(serialNumber, /* sensor ID */ 0); // Note: the sensor ID isn't obvious from neither the URL nor the response; using 0 as default
|
||||
TimePoint timestamp = new MillisecondsTimePoint(((Number) latestDatum.get("timestamp")).longValue());
|
||||
result.add(createFix(sensor, type, timestamp, valuesPerSubindex));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Fix createFix(Sensor sensor, Type fixType, TimePoint timePoint, Map<Integer, Object> valuesPerSubindex) {
|
||||
try {
|
||||
|
||||
+25
-1
@@ -211,6 +211,19 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public String getLatestDatumUrl(Iterable<String> deviceSerialNumbers, Type type, Account account) {
|
||||
StringBuilder url = new StringBuilder(getApiV1BaseUrl());
|
||||
url.append("resources/data/latest?type=");
|
||||
url.append(type.getCode());
|
||||
for (String deviceSerialNumber : deviceSerialNumbers) {
|
||||
url.append("&serial_numbers[]=");
|
||||
url.append(deviceSerialNumber);
|
||||
}
|
||||
url.append("&");
|
||||
url.append(getAccessTokenUrlParameter(account));
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public String getResourceDataUrl(TimePoint startTime, TimePoint endTime, Iterable<String> serialNumbers,
|
||||
Map<Type, Double> typeAndCompression, Account account) {
|
||||
StringBuilder url = new StringBuilder(getApiV1BaseUrl());
|
||||
@@ -293,7 +306,7 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
|
||||
|
||||
@Override
|
||||
public String getAuthorizationUrl() {
|
||||
return getBaseUrl()+"/oauth";
|
||||
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+"&redirect_uri="+client.getRedirectUri();
|
||||
}
|
||||
|
||||
private Client getClient() {
|
||||
@@ -477,4 +490,15 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAccount(String eMail) {
|
||||
Account account = getExistingAccountByEmail(eMail);
|
||||
if (account != null) {
|
||||
String accessToken = accessTokensByAccount.remove(account);
|
||||
accountsByEmail.remove(eMail);
|
||||
mongoObjectFactory.removeAccessToken(accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+79
-1
@@ -2,9 +2,14 @@ package com.sap.sailing.domain.igtimiadapter.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
@@ -14,6 +19,8 @@ import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.igtimiadapter.Account;
|
||||
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
|
||||
import com.sap.sailing.domain.igtimiadapter.DataAccessWindow;
|
||||
@@ -29,9 +36,12 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.igtimiadapter.websocket.WebSocketConnectionManager;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackImpl;
|
||||
|
||||
public class IgtimiConnectionImpl implements IgtimiConnection {
|
||||
private static final Logger logger = Logger.getLogger(IgtimiConnectionImpl.class.getName());
|
||||
private final Account account;
|
||||
private final IgtimiConnectionFactoryImpl connectionFactory;
|
||||
|
||||
@@ -94,6 +104,14 @@ public class IgtimiConnectionImpl implements IgtimiConnection {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Fix> getLatestFixes(Iterable<String> deviceSerialNumbers, Type type) throws IllegalStateException, ClientProtocolException, IOException, ParseException {
|
||||
HttpClient client = connectionFactory.getHttpClient();
|
||||
HttpGet getLatestData = new HttpGet(connectionFactory.getLatestDatumUrl(deviceSerialNumbers, type, account));
|
||||
JSONObject latestDataJson = ConnectivityUtils.getJsonFromResponse(client.execute(getLatestData));
|
||||
return new FixFactory().createFixesFromLastDatum(latestDataJson, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Session> getSessions(Iterable<Long> sessionIds, Boolean isPublic, Integer limit,
|
||||
Boolean includeIncomplete) throws IllegalStateException, ClientProtocolException, IOException,
|
||||
@@ -122,6 +140,7 @@ public class IgtimiConnectionImpl implements IgtimiConnection {
|
||||
@Override
|
||||
public Iterable<Fix> getResourceData(TimePoint startTime, TimePoint endTime,
|
||||
Iterable<String> deviceSerialNumbers, Map<Type, Double> typeAndCompression) throws IllegalStateException, ClientProtocolException, IOException, ParseException {
|
||||
logger.info("Obtaining resource data from "+startTime+" to "+endTime+" for devices "+deviceSerialNumbers+" for types "+typeAndCompression);
|
||||
HttpClient client = connectionFactory.getHttpClient();
|
||||
HttpGet getResourceData = new HttpGet(connectionFactory.getResourceDataUrl(startTime, endTime, deviceSerialNumbers, typeAndCompression, account));
|
||||
JSONObject resourceDataJson = ConnectivityUtils.getJsonFromResponse(client.execute(getResourceData));
|
||||
@@ -143,6 +162,7 @@ public class IgtimiConnectionImpl implements IgtimiConnection {
|
||||
Iterable<String> deviceSerialNumbers, BulkFixReceiver bulkFixReceiver, Type... types)
|
||||
throws IllegalStateException, ClientProtocolException, IOException, ParseException {
|
||||
Iterable<Fix> result = getResourceData(startTime, endTime, deviceSerialNumbers, types);
|
||||
logger.info("Received "+Util.size(result)+" fixes; will pass them to BulkFixReceiver for further processing now.");
|
||||
bulkFixReceiver.received(result);
|
||||
return result;
|
||||
}
|
||||
@@ -209,4 +229,62 @@ public class IgtimiConnectionImpl implements IgtimiConnection {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TrackedRace, Integer> importWindIntoRace(Iterable<DynamicTrackedRace> trackedRaces) throws IllegalStateException, ClientProtocolException, IOException, ParseException {
|
||||
logger.info("Importing Igtimi wind for tracked races "+trackedRaces);
|
||||
TimePoint startOfWindow = new MillisecondsTimePoint(Long.MAX_VALUE);
|
||||
TimePoint endOfWindow = new MillisecondsTimePoint(0);
|
||||
for (DynamicTrackedRace trackedRace : trackedRaces) {
|
||||
startOfWindow = Collections.min(Arrays.asList(startOfWindow, IgtimiWindTracker.getReceivingStartTime(trackedRace)));
|
||||
endOfWindow = Collections.max(Arrays.asList(endOfWindow, IgtimiWindTracker.getReceivingEndTime(trackedRace)));
|
||||
}
|
||||
Iterable<DataAccessWindow> daws = getDataAccessWindows(Permission.read, startOfWindow, endOfWindow, /* find all deviceSerialNumbers for window */ null);
|
||||
logger.info("Found "+Util.size(daws)+" data access windows. Analyzing which ones contain wind data...");
|
||||
Set<String> deviceSerialNumbers = new HashSet<>();
|
||||
for (DataAccessWindow daw : daws) {
|
||||
String deviceSerialNumber = daw.getDeviceSerialNumber();
|
||||
// now filter for the wind-providing devices
|
||||
Iterable<Resource> resources = getResources(Permission.read, startOfWindow, endOfWindow,
|
||||
Collections.singleton(deviceSerialNumber), /* streamIds */ null);
|
||||
if (hasWind(resources)) {
|
||||
StringBuilder resourceIDs = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Resource resource : resources) {
|
||||
if (!first) {
|
||||
resourceIDs.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
resourceIDs.append(resource.getId());
|
||||
}
|
||||
logger.info(" Resources ["+resourceIDs+"] for device "+deviceSerialNumber+" contain wind data");
|
||||
deviceSerialNumbers.add(deviceSerialNumber);
|
||||
}
|
||||
}
|
||||
final Map<TrackedRace, Integer> result;
|
||||
if (!deviceSerialNumbers.isEmpty()) {
|
||||
IgtimiWindReceiver windReceiver = new IgtimiWindReceiver(deviceSerialNumbers);
|
||||
final WindListenerSendingToTrackedRace windListener = new WindListenerSendingToTrackedRace(
|
||||
trackedRaces, Activator.getInstance().getWindTrackerFactory());
|
||||
windReceiver.addListener(windListener);
|
||||
getAndNotifyResourceData(startOfWindow, endOfWindow, deviceSerialNumbers, windReceiver,
|
||||
windReceiver.getFixTypes());
|
||||
result = windListener.getFixesAppliedPerTrackedRace();
|
||||
logger.info("Imported the following number of wind fixes for the following list of races: "+result);
|
||||
} else {
|
||||
logger.info("No Igtimi devices that measure wind found for time window "+startOfWindow+".."+endOfWindow);
|
||||
result = new HashMap<>();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean hasWind(Iterable<Resource> resources) {
|
||||
for (Resource resource : resources) {
|
||||
if (Util.contains(resource.getDataTypes(), Type.AWS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+36
-17
@@ -20,10 +20,13 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.confidence.ScalableValue;
|
||||
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiFixReceiverAdapter;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiWindListener;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.AWA;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.AWS;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.COG;
|
||||
@@ -32,6 +35,8 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.GpsLatLong;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.HDG;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.HDGM;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.SOG;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.igtimiadapter.websocket.WebSocketConnectionManager;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
@@ -41,9 +46,14 @@ import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
|
||||
/**
|
||||
* Receives Igtimi {@link Fix}es and tries to generate a {@link Wind} object from each {@link AWS} fix. For this to
|
||||
* work, the time-wise adjacent {@link AWA}, {@link HDG}/{@link HDGM} and {@link GpsLatLong} fixes are used. If only
|
||||
* a magnetic heading ({@link HDGM}) is available, the {@link DeclinationService} is used to map that to a true heading.
|
||||
* The true wind direction is determined by adding the boat speed vector onto the apparent wind vector.
|
||||
* work, the time-wise adjacent {@link AWA}, {@link HDG}/{@link HDGM} and {@link GpsLatLong} fixes are used. If only a
|
||||
* magnetic heading ({@link HDGM}) is available, the {@link DeclinationService} is used to map that to a true heading.
|
||||
* The true wind direction is determined by adding the boat speed vector onto the apparent wind vector.
|
||||
* <p>
|
||||
*
|
||||
* Use the class by hooking it up to a {@link WebWocketConnectionManager} using
|
||||
* {@link WebSocketConnectionManager#addListener(BulkFixReceiver)} and {@link #addListener(WindListener) add} a
|
||||
* {@link WindListener} to this instance.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
@@ -59,7 +69,7 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
private final DynamicTrack<HDGM> hdgmTrack;
|
||||
private final FixReceiver receiver;
|
||||
private final DeclinationService declinationService;
|
||||
private final ConcurrentHashMap<WindListener, WindListener> listeners;
|
||||
private final ConcurrentHashMap<IgtimiWindListener, IgtimiWindListener> listeners;
|
||||
|
||||
private class FixReceiver extends IgtimiFixReceiverAdapter {
|
||||
@Override
|
||||
@@ -98,17 +108,17 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
public IgtimiWindReceiver(String deviceSerialNumber) {
|
||||
public IgtimiWindReceiver(Iterable<String> deviceSerialNumbers) {
|
||||
receiver = new FixReceiver();
|
||||
declinationService = DeclinationService.INSTANCE;
|
||||
listeners = new ConcurrentHashMap<>();
|
||||
awaTrack = new DynamicTrackImpl<>("AWA Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
awsTrack = new DynamicTrackImpl<>("AWS Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
gpsTrack = new DynamicTrackImpl<>("GPS Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
cogTrack = new DynamicTrackImpl<>("COG Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
sogTrack = new DynamicTrackImpl<>("SOG Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
hdgTrack = new DynamicTrackImpl<>("HDG Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
hdgmTrack = new DynamicTrackImpl<>("HDGM Track for Igtimi wind track for device "+deviceSerialNumber);
|
||||
awaTrack = new DynamicTrackImpl<>("AWA Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
awsTrack = new DynamicTrackImpl<>("AWS Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
gpsTrack = new DynamicTrackImpl<>("GPS Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
cogTrack = new DynamicTrackImpl<>("COG Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
sogTrack = new DynamicTrackImpl<>("SOG Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
hdgTrack = new DynamicTrackImpl<>("HDG Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
hdgmTrack = new DynamicTrackImpl<>("HDGM Track for Igtimi wind track for device "+deviceSerialNumbers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +138,12 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
}
|
||||
});
|
||||
}
|
||||
logger.info("Received "+Util.size(awsFixes)+" wind fixes");
|
||||
for (AWS aws : awsFixes) {
|
||||
try {
|
||||
final Wind wind = getWind(aws.getTimePoint());
|
||||
if (wind != null) {
|
||||
notifyListeners(wind);
|
||||
notifyListeners(wind, aws.getSensor().getDeviceSerialNumber());
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException | ParseException e) {
|
||||
logger.log(Level.INFO, "Exception while trying to construct Wind fix from Igtimi fix " + aws, e);
|
||||
@@ -140,13 +151,13 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(WindListener listener) {
|
||||
public void addListener(IgtimiWindListener listener) {
|
||||
listeners.put(listener, listener);
|
||||
}
|
||||
|
||||
public void notifyListeners(Wind wind) {
|
||||
for (WindListener listener : listeners.keySet()) {
|
||||
listener.windDataReceived(wind);
|
||||
public void notifyListeners(Wind wind, String deviceSerialNumber) {
|
||||
for (IgtimiWindListener listener : listeners.keySet()) {
|
||||
listener.windDataReceived(wind, deviceSerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,4 +410,12 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
private DynamicTrack<HDGM> getHdgmTrack() {
|
||||
return hdgmTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the set of types that this wind receiver is interested in. Can be used to subscribe for fixes from
|
||||
* resource data. See {@link IgtimiConnection#getResourceData(TimePoint, TimePoint, Iterable, Type...)}.
|
||||
*/
|
||||
public Type[] getFixTypes() {
|
||||
return new Type[] { Type.AWA, Type.AWS, Type.HDG, Type.HDGM, Type.gps_latlong, Type.COG, Type.SOG };
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.igtimiadapter.Account;
|
||||
import com.sap.sailing.domain.igtimiadapter.DataAccessWindow;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
|
||||
import com.sap.sailing.domain.igtimiadapter.LiveDataConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.Permission;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.tracking.AbstractWindTracker;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
|
||||
public class IgtimiWindTracker extends AbstractWindTracker implements WindTracker {
|
||||
private static final Logger logger = Logger.getLogger(IgtimiWindTracker.class.getName());
|
||||
private static final int TIME_INTERVAL_TO_TRACK_BEFORE_RACE_START_MILLIS = 10*60*1000; // 10 minutes
|
||||
private static final long TIME_INTERVAL_TO_TRACK_AFTER_END_OF_RACE_MILLIS = 60*60*1000; // 60 minutes
|
||||
private final Map<LiveDataConnection, Pair<Set<String>, Account>> liveConnectionsAndDeviceSerialNumber;
|
||||
private final IgtimiWindTrackerFactory windTrackerFactory;
|
||||
private boolean stopping;
|
||||
|
||||
protected IgtimiWindTracker(final DynamicTrackedRace trackedRace, final IgtimiConnectionFactory connectionFactory,
|
||||
final IgtimiWindTrackerFactory windTrackerFactory) throws Exception {
|
||||
super(trackedRace);
|
||||
this.windTrackerFactory = windTrackerFactory;
|
||||
liveConnectionsAndDeviceSerialNumber = new HashMap<>();
|
||||
new Thread("IgtimiWindTracker start-up thread for race " + trackedRace.getRace().getName()) {
|
||||
public void run() {
|
||||
logger.info("Starting up Igtimi wind tracker for race "+trackedRace.getRace().getName());
|
||||
// avoid a race condition with stop() being called while this start-up thread is still running
|
||||
synchronized (IgtimiWindTracker.this) {
|
||||
Iterable<Account> accounts = connectionFactory.getAllAccounts();
|
||||
for (Account account : accounts) {
|
||||
try {
|
||||
if (!stopping) {
|
||||
IgtimiConnection connection = connectionFactory.connect(account);
|
||||
// find all the devices from which we may read
|
||||
Iterable<DataAccessWindow> dataAccessWindows = connection.getDataAccessWindows(
|
||||
Permission.read, /* start time */ null, /* end time */ null,
|
||||
/* get data for all available deviceSerialNumbers */null);
|
||||
Set<String> deviceSerialNumbersWeCanRead = new HashSet<>();
|
||||
for (DataAccessWindow daw : dataAccessWindows) {
|
||||
deviceSerialNumbersWeCanRead.add(daw.getDeviceSerialNumber());
|
||||
}
|
||||
// find all that haven't even sent GPS; those may never have sent ever, so we need to listen to them for new stuff; they could be wind sensors
|
||||
Iterable<Fix> gpsFixes = connection.getLatestFixes(deviceSerialNumbersWeCanRead, Type.gps_latlong);
|
||||
Set<String> devicesWithGps = getDeviceSerialNumbers(gpsFixes);
|
||||
Iterable<Fix> awsFixes = connection.getLatestFixes(deviceSerialNumbersWeCanRead, Type.AWS); // look for latest fixes with apparent wind speed in the fix
|
||||
Set<String> devicesWithWind = getDeviceSerialNumbers(awsFixes);
|
||||
Set<String> devicesThatHaveNeverSentGpsNorWind = new HashSet<>(deviceSerialNumbersWeCanRead);
|
||||
devicesThatHaveNeverSentGpsNorWind.removeAll(devicesWithGps);
|
||||
devicesThatHaveNeverSentGpsNorWind.removeAll(devicesWithWind);
|
||||
Set<String> devicesWeShouldListenTo = new HashSet<>();
|
||||
devicesWeShouldListenTo.addAll(devicesWithWind);
|
||||
devicesWeShouldListenTo.addAll(devicesThatHaveNeverSentGpsNorWind);
|
||||
logger.info("Will listen to devices "
|
||||
+ devicesWeShouldListenTo
|
||||
+ " because from all devices "+deviceSerialNumbersWeCanRead+" for "
|
||||
+ devicesThatHaveNeverSentGpsNorWind
|
||||
+ " we don't know what they are as they never sent anything we can access, and for "
|
||||
+ devicesWithWind + " we know they sent wind");
|
||||
if (!stopping) {
|
||||
LiveDataConnection liveConnection = connection.createLiveConnection(devicesWeShouldListenTo);
|
||||
IgtimiWindReceiver windReceiver = new IgtimiWindReceiver(devicesWeShouldListenTo);
|
||||
liveConnection.addListener(windReceiver);
|
||||
windReceiver.addListener(new WindListenerSendingToTrackedRace(Collections.singleton(getTrackedRace()), windTrackerFactory));
|
||||
liveConnectionsAndDeviceSerialNumber.put(liveConnection, new Pair<Set<String>, Account>(devicesWeShouldListenTo, account));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception trying to start Igtimi wind tracker for race "
|
||||
+ getTrackedRace().getRace().getName() + " for account " + account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private Set<String> getDeviceSerialNumbers(Iterable<Fix> fixes) {
|
||||
Set<String> deviceSerialNumbers = new HashSet<>();
|
||||
for (Fix fix : fixes) {
|
||||
deviceSerialNumbers.add(fix.getSensor().getDeviceSerialNumber());
|
||||
}
|
||||
return deviceSerialNumbers;
|
||||
}
|
||||
|
||||
public static TimePoint getReceivingEndTime(DynamicTrackedRace trackedRace) {
|
||||
TimePoint endOfRace = trackedRace.getEndOfRace();
|
||||
TimePoint endOfTracking = trackedRace.getEndOfTracking();
|
||||
final TimePoint endTime;
|
||||
if (endOfRace == null) {
|
||||
if (endOfTracking == null) {
|
||||
endTime = null;
|
||||
} else {
|
||||
endTime = endOfTracking.plus(TIME_INTERVAL_TO_TRACK_AFTER_END_OF_RACE_MILLIS);
|
||||
}
|
||||
} else {
|
||||
if (endOfTracking == null) {
|
||||
endTime = endOfRace;
|
||||
} else {
|
||||
endTime = Collections.max(Arrays.asList(endOfRace, endOfTracking));
|
||||
}
|
||||
}
|
||||
return endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the tracked race's time parameters and the current time, decides for a good start time for receiving
|
||||
* live wind data. Get all devices that have been sending during the last 10 minutes before start of race, start of
|
||||
* tracking or now, whichever came first.
|
||||
*/
|
||||
public static TimePoint getReceivingStartTime(DynamicTrackedRace trackedRace) {
|
||||
List<TimePoint> startCandidates = new ArrayList<>();
|
||||
final TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||
if (startOfRace != null) {
|
||||
startCandidates.add(startOfRace);
|
||||
}
|
||||
final TimePoint startOfTracking = trackedRace.getStartOfTracking();
|
||||
if (startOfTracking != null) {
|
||||
startCandidates.add(startOfTracking);
|
||||
}
|
||||
startCandidates.add(MillisecondsTimePoint.now());
|
||||
return Collections.min(startCandidates).minus(TIME_INTERVAL_TO_TRACK_BEFORE_RACE_START_MILLIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.info("Stopping Igtimi wind tracker for race "+getTrackedRace().getRace().getName());
|
||||
stopping = true; // in case stop() is called while the start-up thread is still running, avoid more connections to be created
|
||||
// this synchronizes with the start-up thread and waits until that has finished and no longer writes to liveConnectionsAndDeviceSerialNumber
|
||||
synchronized (this) {
|
||||
windTrackerFactory.windTrackerStopped(getTrackedRace().getRace(), this);
|
||||
for (LiveDataConnection ldc : liveConnectionsAndDeviceSerialNumber.keySet()) {
|
||||
try {
|
||||
logger.info("Stopping Igtimi live connection "+ldc);
|
||||
ldc.stop();
|
||||
} catch (Exception e) {
|
||||
final Pair<Set<String>, Account> deviceSerialNumberAndAccount = liveConnectionsAndDeviceSerialNumber.get(ldc);
|
||||
logger.log(Level.INFO,
|
||||
"Exception trying to stop Igtimi live connection for wind receiver for race "
|
||||
+ getTrackedRace().getRace() + " and device " + deviceSerialNumberAndAccount.getA()
|
||||
+ " in account " + deviceSerialNumberAndAccount.getB());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.impl;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
||||
|
||||
public class IgtimiWindTrackerFactory implements WindTrackerFactory {
|
||||
private static final Logger logger = Logger.getLogger(IgtimiWindTrackerFactory.class.getName());
|
||||
private final IgtimiConnectionFactoryImpl connectionFactory;
|
||||
private final WeakHashMap<RaceDefinition, WindTracker> trackersForRace;
|
||||
|
||||
public IgtimiWindTrackerFactory(IgtimiConnectionFactoryImpl connectionFactory) {
|
||||
trackersForRace = new WeakHashMap<>();
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindTracker createWindTracker(DynamicTrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
boolean correctByDeclination) throws Exception {
|
||||
DynamicTrackedRace trackedRace = trackedRegatta.getTrackedRace(race);
|
||||
IgtimiWindTracker windTracker = new IgtimiWindTracker(trackedRace, connectionFactory, this);
|
||||
trackersForRace.put(race, windTracker);
|
||||
return windTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindTracker getExistingWindTracker(RaceDefinition race) {
|
||||
return trackersForRace.get(race);
|
||||
}
|
||||
|
||||
void windTrackerStopped(RaceDefinition race, IgtimiWindTracker igtimiWindTracker) {
|
||||
WindTracker removedTracker = trackersForRace.remove(race);
|
||||
if (removedTracker != igtimiWindTracker) {
|
||||
logger.warning("Expected to remove wind tracker "+igtimiWindTracker+" but did remove "+removedTracker);
|
||||
}
|
||||
}
|
||||
|
||||
WindSource getWindSource(String deviceSerialNumber) {
|
||||
return new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, deviceSerialNumber);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-2
@@ -1,9 +1,13 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.Permission;
|
||||
import com.sap.sailing.domain.igtimiadapter.Resource;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
|
||||
public class ResourceImpl implements Resource {
|
||||
private final long id;
|
||||
@@ -47,8 +51,12 @@ public class ResourceImpl implements Resource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getDataTypes() {
|
||||
return dataTypes;
|
||||
public Iterable<Type> getDataTypes() {
|
||||
List<Type> result = new ArrayList<Type>();
|
||||
for (int dataType : dataTypes) {
|
||||
result.add(Type.valueOf(dataType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiWindListener;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
|
||||
class WindListenerSendingToTrackedRace implements IgtimiWindListener {
|
||||
private final Iterable<DynamicTrackedRace> trackedRaces;
|
||||
private final IgtimiWindTrackerFactory windTrackerFactory;
|
||||
private final Map<TrackedRace, Integer> numberOfFixesAppliedPerTrackedRace;
|
||||
|
||||
WindListenerSendingToTrackedRace(Iterable<DynamicTrackedRace> trackedRaces, IgtimiWindTrackerFactory windTrackerFactory) {
|
||||
this.trackedRaces = trackedRaces;
|
||||
this.windTrackerFactory = windTrackerFactory;
|
||||
numberOfFixesAppliedPerTrackedRace = new HashMap<>();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
numberOfFixesAppliedPerTrackedRace.put(trackedRace, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windDataReceived(Wind wind, String deviceSerialNumber) {
|
||||
for (DynamicTrackedRace trackedRace : trackedRaces) {
|
||||
if (trackedRace.recordWind(wind, windTrackerFactory.getWindSource(deviceSerialNumber))) {
|
||||
numberOfFixesAppliedPerTrackedRace.put(trackedRace, numberOfFixesAppliedPerTrackedRace.get(trackedRace)+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TrackedRace, Integer> getFixesAppliedPerTrackedRace() {
|
||||
return numberOfFixesAppliedPerTrackedRace;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -34,14 +34,14 @@ public class AuthorizationCallback {
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
@Produces("text/plain;charset=UTF-8")
|
||||
@Path(AUTHORIZATIONCALLBACK)
|
||||
public Response obtainAccessToken(@QueryParam("code") String code) throws ClientProtocolException, IOException, IllegalStateException, ParseException, URISyntaxException {
|
||||
Response result;
|
||||
if (code != null) {
|
||||
try {
|
||||
connectionFactory.obtainAccessTokenFromAuthorizationCode(code);
|
||||
result = Response.ok().build();
|
||||
result = Response.ok().entity("SAP Sailing Analytics authorized successfully to access user's tracks").build();
|
||||
} catch (Exception e) {
|
||||
result = Response.status(Status.UNAUTHORIZED).entity(e.getMessage()).build();
|
||||
logger.log(Level.SEVERE, "Error trying to obtain access token from authentication code " + code, e);
|
||||
|
||||
+18
-13
@@ -2,7 +2,6 @@ package com.sap.sailing.domain.igtimiadapter.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
@@ -58,8 +57,9 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
client = new WebSocketClient();
|
||||
configurationMessage = connectionFactory.getWebSocketConfigurationMessage(account, deviceSerialNumbers);
|
||||
request = new ClientUpgradeRequest();
|
||||
client.start();
|
||||
reconnect();
|
||||
startClientHeartbeat();
|
||||
startListeningForServerHeartbeat();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,8 +82,9 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() throws Exception {
|
||||
public void stop() throws Exception {
|
||||
targetState = TargetState.CLOSED;
|
||||
timer.cancel();
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@@ -93,8 +94,6 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
logger.info("received connection "+session+" for "+this);
|
||||
try {
|
||||
getRemote().sendString(configurationMessage.toString());
|
||||
startClientHeartbeat();
|
||||
startListeningForServerHeartbeat();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Could not send configuration package to Igtimi web socket server in "+this, e);
|
||||
throw new RuntimeException(e);
|
||||
@@ -107,7 +106,7 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
logger.finest("Received "+message+" in "+this);
|
||||
}
|
||||
if (message.equals("1")) {
|
||||
logger.fine("Received server heartbeat");
|
||||
logger.fine("Received server heartbeat for "+this);
|
||||
receivedServerHeartbeatInInterval = true;
|
||||
} else if (message.startsWith("[")) {
|
||||
List<Fix> fixes = new ArrayList<>();
|
||||
@@ -117,7 +116,7 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
Util.addAll(fixFactory.createFixes((JSONObject) o), fixes);
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.finest("Received fixes"+fixes);
|
||||
logger.finest("Received fixes"+fixes+" for "+this);
|
||||
}
|
||||
notifyListeners(fixes);
|
||||
} catch (ParseException e) {
|
||||
@@ -176,8 +175,11 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
public void run() {
|
||||
try {
|
||||
if (!receivedServerHeartbeatInInterval) {
|
||||
logger.info("Didn't receive server heartbeat in interval for "+this+". Reconnecting...");
|
||||
logger.info("Didn't receive server heartbeat in interval for "+WebSocketConnectionManager.this+". Reconnecting...");
|
||||
client.stop();
|
||||
reconnect();
|
||||
} else {
|
||||
receivedServerHeartbeatInInterval = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Error with server heartbeat in "+this, e);
|
||||
@@ -191,22 +193,25 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logger.fine("Sending client heartbeat");
|
||||
getRemote().sendString("1");
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.WARNING, "Couldn't send heartbeat to Igtimi web socket session in "+this, e);
|
||||
if (getRemote() != null) {
|
||||
logger.fine("Sending client heartbeat for " + WebSocketConnectionManager.this);
|
||||
getRemote().sendString("1");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Couldn't send heartbeat to Igtimi web socket session in "+WebSocketConnectionManager.this+". Will continue to try...", e);
|
||||
}
|
||||
}
|
||||
}, /* delay */ 0, /* send ping message every other minute; has to be at least every five minutes, so this should be safe */ 120000l);
|
||||
}
|
||||
|
||||
private void reconnect() throws IOException, IllegalStateException, ParseException, URISyntaxException {
|
||||
private void reconnect() throws Exception {
|
||||
IOException lastException = null;
|
||||
for (URI uri : connectionFactory.getWebsocketServers()) {
|
||||
try {
|
||||
if (uri.getScheme().equals("ws")) { // as Jetty 9.0.4 currently doesn't seem to support wss, explicitly
|
||||
// look for ws connectivity
|
||||
logger.log(Level.INFO, "Trying to connect to " + uri + " for " + this);
|
||||
client.start();
|
||||
client.connect(this, uri, request);
|
||||
logger.log(Level.INFO, "Successfully connected to " + uri + " for " + this);
|
||||
lastException = null;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class EventImpl extends EventBaseImpl implements Event {
|
||||
super(name, venue, publicationUrl, isPublic, id);
|
||||
this.regattas = new HashSet<Regatta>();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<Regatta> getRegattas() {
|
||||
return Collections.unmodifiableSet(regattas);
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
public abstract class AbstractWindTracker implements WindTracker {
|
||||
private final DynamicTrackedRace trackedRace;
|
||||
|
||||
protected AbstractWindTracker(DynamicTrackedRace trackedRace) {
|
||||
super();
|
||||
this.trackedRace = trackedRace;
|
||||
}
|
||||
|
||||
protected DynamicTrackedRace getTrackedRace() {
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.net.SocketException;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
|
||||
/**
|
||||
@@ -12,7 +10,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
*/
|
||||
public interface WindTrackerFactory {
|
||||
WindTracker createWindTracker(DynamicTrackedRegatta trackedRegatta, RaceDefinition race, boolean correctByDeclination)
|
||||
throws SocketException;
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Returns a {@link WindTracker} is one has been previously created for <code>race</code> and hasn't been
|
||||
|
||||
+9
-5
@@ -98,6 +98,9 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
listeners = new HashSet<RaceChangeListener>();
|
||||
logListener = new DynamicTrackedRaceLogListener(this);
|
||||
courseDesignChangedListeners = new HashSet<CourseDesignChangedListener>();
|
||||
startTimeChangedListeners = new HashSet<StartTimeChangedListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,24 +640,25 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
|
||||
@Override
|
||||
public boolean recordWind(Wind wind, WindSource windSource) {
|
||||
final boolean result;
|
||||
// TODO check what a good filter is; remember that start/end of tracking may change over time; what if we have discarded valuable wind fixes?
|
||||
TimePoint startOfRace = getStartOfRace();
|
||||
TimePoint startOfTracking = getStartOfTracking();
|
||||
TimePoint endOfRace = getEndOfRace();
|
||||
TimePoint endOfTracking = getEndOfTracking();
|
||||
if ((startOfTracking == null || !startOfTracking.after(wind.getTimePoint()) ||
|
||||
(startOfRace != null && !startOfRace.after(wind.getTimePoint())))
|
||||
if ((startOfTracking == null || !startOfTracking.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint()) ||
|
||||
(startOfRace != null && !startOfRace.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint())))
|
||||
&&
|
||||
(endOfTracking == null || endOfTracking.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint()) ||
|
||||
(endOfRace != null && endOfRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint())))) {
|
||||
getOrCreateWindTrack(windSource).add(wind);
|
||||
result = getOrCreateWindTrack(windSource).add(wind);
|
||||
updated(/* time point */null); // wind events shouldn't advance race time
|
||||
triggerManeuverCacheRecalculationForAllCompetitors();
|
||||
notifyListeners(wind, windSource);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
@@ -110,6 +110,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
// TODO make this variable
|
||||
private static final long DELAY_FOR_CACHE_CLEARING_IN_MILLISECONDS = 7500;
|
||||
|
||||
public static final long TIME_BEFORE_START_TO_TRACK_WIND_MILLIS = 4 * 60 * 1000l; // let wind start four minutes before race
|
||||
|
||||
private TrackedRaceStatus status;
|
||||
|
||||
private final Object statusNotifier;
|
||||
|
||||
+3
-2
@@ -130,8 +130,9 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
|
||||
* returned instead.
|
||||
*/
|
||||
protected TimePoint getFrom() {
|
||||
return from == null ? getTrackedRace().getStartOfRace() == null ? new MillisecondsTimePoint(Long.MAX_VALUE)
|
||||
: floorToResolution(getTrackedRace().getStartOfRace()) : from;
|
||||
final TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
return from == null ? startOfRace == null ? new MillisecondsTimePoint(Long.MAX_VALUE)
|
||||
: floorToResolution(startOfRace.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS)) : from;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-5
@@ -57,19 +57,20 @@ public abstract class VirtualWindTrackImpl extends WindTrackImpl {
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> getAveragedWindWithConfidence(Position p, TimePoint at) {
|
||||
WindWithConfidence<Pair<Position, TimePoint>> result = null;
|
||||
TimePoint adjustedAt;
|
||||
TimePoint raceStartTimePoint = getTrackedRace().getStartOfRace();
|
||||
final TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
TimePoint timePointOfNewestEvent = getTrackedRace().getTimePointOfNewestEvent();
|
||||
if (raceStartTimePoint != null) {
|
||||
if (startOfRace != null) {
|
||||
TimePoint fourMinutesBeforeRaceStartTimePoint = startOfRace.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS); // let wind tracks start four minutes before start
|
||||
if (timePointOfNewestEvent != null) {
|
||||
if (at.compareTo(raceStartTimePoint) < 0) {
|
||||
adjustedAt = raceStartTimePoint;
|
||||
if (at.compareTo(fourMinutesBeforeRaceStartTimePoint) < 0) {
|
||||
adjustedAt = fourMinutesBeforeRaceStartTimePoint;
|
||||
} else if (at.compareTo(timePointOfNewestEvent) > 0) {
|
||||
adjustedAt = timePointOfNewestEvent;
|
||||
} else {
|
||||
adjustedAt = at;
|
||||
}
|
||||
} else {
|
||||
adjustedAt = raceStartTimePoint;
|
||||
adjustedAt = fourMinutesBeforeRaceStartTimePoint;
|
||||
}
|
||||
} else {
|
||||
if (timePointOfNewestEvent != null) {
|
||||
|
||||
+9
-7
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.tracking.AbstractWindTracker;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
@@ -25,11 +26,9 @@ import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ExpeditionWindTracker implements ExpeditionListener, WindTracker {
|
||||
public class ExpeditionWindTracker extends AbstractWindTracker implements ExpeditionListener, WindTracker {
|
||||
private static final Logger logger = Logger.getLogger(ExpeditionWindTracker.class.getName());
|
||||
|
||||
private final DynamicTrackedRace race;
|
||||
|
||||
private final DeclinationService declinationService;
|
||||
|
||||
private final Map<Integer, Position> lastKnownPositionPerBoatID;
|
||||
@@ -49,9 +48,8 @@ public class ExpeditionWindTracker implements ExpeditionListener, WindTracker {
|
||||
*/
|
||||
public ExpeditionWindTracker(DynamicTrackedRace race, DeclinationService declinationService,
|
||||
UDPExpeditionReceiver receiver, ExpeditionWindTrackerFactory factory) {
|
||||
super();
|
||||
super(race);
|
||||
this.lastKnownPositionPerBoatID = new HashMap<Integer, Position>();
|
||||
this.race = race;
|
||||
this.declinationService = declinationService;
|
||||
this.receiver = receiver;
|
||||
this.factory = factory;
|
||||
@@ -62,7 +60,7 @@ public class ExpeditionWindTracker implements ExpeditionListener, WindTracker {
|
||||
public void stop() {
|
||||
synchronized (factory) {
|
||||
receiver.removeListener(this);
|
||||
factory.windTrackerStopped(race.getRace(), this);
|
||||
factory.windTrackerStopped(getTrackedRace().getRace(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +113,13 @@ public class ExpeditionWindTracker implements ExpeditionListener, WindTracker {
|
||||
if (windSpeed != null && lastKnownPositionPerBoatID.get(message.getBoatID()) != null) {
|
||||
Wind wind = new WindImpl(lastKnownPositionPerBoatID.get(message.getBoatID()), message.getTimePoint(), windSpeed);
|
||||
String windSourceID = Integer.valueOf(message.getBoatID()).toString();
|
||||
race.recordWind(wind, new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, windSourceID));
|
||||
sendWindToRace(wind, windSourceID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendWindToRace(Wind wind, String windSourceID) {
|
||||
getTrackedRace().recordWind(wind, new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, windSourceID));
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -45,7 +45,7 @@ public class ExpeditionWindTrackerFactory implements WindTrackerFactory {
|
||||
@Override
|
||||
public WindTracker createWindTracker(DynamicTrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
boolean correctByDeclination) throws SocketException {
|
||||
WindTracker result = windTrackers.get(race);
|
||||
WindTracker result = getExistingWindTracker(race);
|
||||
if (result == null) {
|
||||
DynamicTrackedRace trackedRace = trackedRegatta.getTrackedRace(race);
|
||||
UDPExpeditionReceiver receiver = getOrCreateWindReceiverOnDefaultPort();
|
||||
|
||||
+6
@@ -6,6 +6,9 @@ import java.util.logging.Logger;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
private static Logger logger = Logger.getLogger(Activator.class.getName());
|
||||
|
||||
@@ -31,6 +34,9 @@ public class Activator implements BundleActivator {
|
||||
port = Integer.valueOf(context.getProperty(EXPEDITION_UDP_PORT_PROPERTY_NAME));
|
||||
logger.log(Level.INFO, "found "+EXPEDITION_UDP_PORT_PROPERTY_NAME+"="+port+" in OSGi context");
|
||||
}
|
||||
// register the Expedition wind tracker factory as an OSGi service
|
||||
context.registerService(ExpeditionWindTrackerFactory.class, ExpeditionWindTrackerFactory.getInstance(), /* properties */null);
|
||||
context.registerService(WindTrackerFactory.class, ExpeditionWindTrackerFactory.getInstance(), /* properties */null);
|
||||
}
|
||||
|
||||
public static Activator getInstance() {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
<configurations>
|
||||
<plugin id="com.sap.sailing.barbados.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.domain.igtimiadapter" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.domain.swisstimingadapter" autoStart="false" startLevel="4" />
|
||||
<plugin id="com.sap.sailing.domain.swisstimingreplayadapter" autoStart="false" startLevel="4" />
|
||||
<plugin id="com.sap.sailing.domain.tractracadapter" autoStart="false" startLevel="4" />
|
||||
|
||||
@@ -27,7 +27,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.simulator;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0",
|
||||
de.csenk.gwt.ws,
|
||||
com.google.gwt.osgi;bundle-version="2.5.1"
|
||||
com.google.gwt.osgi;bundle-version="2.5.1",
|
||||
com.sap.sailing.domain.igtimiadapter
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
|
||||
-1
@@ -28,7 +28,6 @@ public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel
|
||||
// TrackedEventsComposite should exist in every *ManagementPanel.
|
||||
trackedRacesListComposite = new TrackedRacesListComposite(sailingService, errorReporter, regattaRefresher,
|
||||
raceSelectionProvider, stringMessages, /* multiselection */ true);
|
||||
trackedRacesListComposite.ensureDebugId("TrackedRacesListComposite");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-7
@@ -62,7 +62,7 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
|
||||
|
||||
RegattaStructureManagementPanel eventStructureManagementPanel = new RegattaStructureManagementPanel(
|
||||
sailingService, this, stringMessages, this);
|
||||
eventStructureManagementPanel.ensureDebugId("RegattaStructureManagement");
|
||||
// eventStructureManagementPanel.ensureDebugId("RegattaStructureManagement");
|
||||
eventStructureManagementPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, eventStructureManagementPanel, stringMessages.regattas());
|
||||
regattaDisplayers.add(eventStructureManagementPanel);
|
||||
@@ -91,23 +91,28 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
|
||||
stringMessages);
|
||||
// createSwissTimingRacePanel.ensureDebugId("CreateSwissTimingRace");
|
||||
createSwissTimingRacePanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, createSwissTimingRacePanel, "Create SwissTiming race");
|
||||
addScrollableTab(tabPanel, createSwissTimingRacePanel, stringMessages.createSwissTimingRace());
|
||||
|
||||
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(sailingService, this, stringMessages);
|
||||
igtimiAccountsPanel.ensureDebugId("IgtimiAccounts");
|
||||
igtimiAccountsPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, igtimiAccountsPanel, stringMessages.igtimiAccounts());
|
||||
|
||||
TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(sailingService, this,
|
||||
this, stringMessages);
|
||||
trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
|
||||
// trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
|
||||
trackedRacesManagementPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, trackedRacesManagementPanel, stringMessages.trackedRaces());
|
||||
regattaDisplayers.add(trackedRacesManagementPanel);
|
||||
|
||||
final CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, stringMessages, this);
|
||||
competitorPanel.ensureDebugId("CompetitorManagement");
|
||||
// trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
|
||||
trackedRacesManagementPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, competitorPanel, stringMessages.competitors());
|
||||
|
||||
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(sailingService, this, this,
|
||||
stringMessages);
|
||||
raceCourseManagementPanel.ensureDebugId("RaceCourseManagement");
|
||||
// raceCourseManagementPanel.ensureDebugId("RaceCourseManagement");
|
||||
raceCourseManagementPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, raceCourseManagementPanel, stringMessages.courseLayout());
|
||||
regattaDisplayers.add(raceCourseManagementPanel);
|
||||
@@ -115,14 +120,14 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
|
||||
final AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
|
||||
WindPanel windPanel = new WindPanel(sailingService, asyncActionsExecutor, this, this, stringMessages);
|
||||
windPanel.ensureDebugId("WindManagement");
|
||||
// windPanel.ensureDebugId("WindManagement");
|
||||
regattaDisplayers.add(windPanel);
|
||||
windPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, windPanel, stringMessages.wind());
|
||||
|
||||
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(sailingService,
|
||||
this, this, stringMessages);
|
||||
leaderboardGroupConfigPanel.ensureDebugId("LeaderboardGroupConfiguration");
|
||||
// leaderboardGroupConfigPanel.ensureDebugId("LeaderboardGroupConfiguration");
|
||||
leaderboardGroupConfigPanel.setSize("90%", "90%");
|
||||
addScrollableTab(tabPanel, leaderboardGroupConfigPanel, stringMessages.leaderboardGroupConfiguration());
|
||||
regattaDisplayers.add(leaderboardGroupConfigPanel);
|
||||
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.cell.client.FieldUpdater;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.google.gwt.user.cellview.client.CellTable;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
|
||||
import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.PasswordTextBox;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.domain.common.impl.NaturalComparator;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.components.ImagesBarCell;
|
||||
import com.sap.sailing.gwt.ui.client.shared.panels.AbstractFilterablePanel;
|
||||
|
||||
public class IgtimiAccountsPanel extends FlowPanel {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final CellTable<String> allAccounts;
|
||||
private final AbstractFilterablePanel<String> filterAccountsPanel;
|
||||
|
||||
public static class AccountImagesBarCell extends ImagesBarCell {
|
||||
public static final String ACTION_REMOVE = "ACTION_REMOVE";
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public AccountImagesBarCell(StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
public AccountImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringMessages = stringConstants;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<ImageSpec> getImageSpecs() {
|
||||
return Arrays.asList(
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())));
|
||||
}
|
||||
}
|
||||
|
||||
public IgtimiAccountsPanel(final SailingServiceAsync sailingService, final ErrorReporter errorReporter, final StringMessages stringMessages) {
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
|
||||
allAccounts = new CellTable<String>(/* pageSize */10000, tableRes);
|
||||
final SingleSelectionModel<String> accountsSelectionModel = new SingleSelectionModel<String>();
|
||||
allAccounts.setSelectionModel(accountsSelectionModel);
|
||||
final ListDataProvider<String> filteredAccounts = new ListDataProvider<String>();
|
||||
ListHandler<String> accountColumnListHandler = new ListHandler<String>(filteredAccounts.getList());
|
||||
filteredAccounts.addDataDisplay(allAccounts);
|
||||
final List<String> emptyList = Collections.emptyList();
|
||||
filterAccountsPanel = new AbstractFilterablePanel<String>(new Label(stringMessages.igtimiAccounts()), emptyList, allAccounts, filteredAccounts) {
|
||||
@Override
|
||||
public Iterable<String> getSearchableStrings(String t) {
|
||||
Set<String> strings = Collections.singleton(t);
|
||||
return strings;
|
||||
}
|
||||
};
|
||||
final Panel controlsPanel = new HorizontalPanel();
|
||||
final Button removeAccountButton = new Button(stringMessages.remove());
|
||||
removeAccountButton.setEnabled(false);
|
||||
removeAccountButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
if (accountsSelectionModel.getSelectedObject() != null) {
|
||||
if (Window.confirm("Do you really want to remove the leaderboards?")) {
|
||||
removeAccount(accountsSelectionModel.getSelectedObject(), filteredAccounts);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
accountsSelectionModel.addSelectionChangeHandler(new Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
removeAccountButton.setEnabled(accountsSelectionModel.getSelectedObject() != null);
|
||||
}
|
||||
});
|
||||
controlsPanel.add(filterAccountsPanel);
|
||||
controlsPanel.add(removeAccountButton);
|
||||
add(controlsPanel);
|
||||
add(allAccounts);
|
||||
Column<String, String> accountEmailColumn = new TextColumn<String>() {
|
||||
@Override
|
||||
public String getValue(String object) {
|
||||
return object;
|
||||
}
|
||||
};
|
||||
accountEmailColumn.setSortable(true);
|
||||
accountColumnListHandler.setComparator(accountEmailColumn, new NaturalComparator(/* caseSensitive */ false));
|
||||
allAccounts.addColumn(accountEmailColumn, stringMessages.emailAddress());
|
||||
ImagesBarColumn<String, AccountImagesBarCell> accountActionColumn = new ImagesBarColumn<String, AccountImagesBarCell>(
|
||||
new AccountImagesBarCell(stringMessages));
|
||||
accountActionColumn.setFieldUpdater(new FieldUpdater<String, String>() {
|
||||
@Override
|
||||
public void update(int index, String accountEmail, String value) {
|
||||
if (AccountImagesBarCell.ACTION_REMOVE.equals(value)) {
|
||||
if (Window.confirm(stringMessages.doYouReallyWantToRemoveIgtimiAccount(accountEmail))) {
|
||||
removeAccount(accountEmail, filteredAccounts);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
allAccounts.addColumn(accountActionColumn, stringMessages.actions());
|
||||
updateAllAccounts(sailingService, filterAccountsPanel, stringMessages, errorReporter);
|
||||
Button addAccountButton = new Button(stringMessages.addIgtimiAccount());
|
||||
addAccountButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
addAccount();
|
||||
}
|
||||
});
|
||||
add(addAccountButton);
|
||||
Button refreshButton = new Button(stringMessages.refresh());
|
||||
refreshButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
updateAllAccounts(sailingService, filterAccountsPanel, stringMessages, errorReporter);
|
||||
}
|
||||
});
|
||||
add(refreshButton);
|
||||
this.sailingService.getIgtimiAuthorizationUrl(new AsyncCallback<String>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(IgtimiAccountsPanel.this.stringMessages.errorGettingIgtimiAuthorizationUrl(caught.getMessage()),
|
||||
/* silentMode */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
Anchor addIgtimiUserLink = new Anchor(stringMessages.addIgtimiUser(), result);
|
||||
controlsPanel.add(addIgtimiUserLink);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class UserData {
|
||||
private final String eMail;
|
||||
private final String password;
|
||||
protected UserData(String eMail, String password) {
|
||||
super();
|
||||
this.eMail = eMail;
|
||||
this.password = password;
|
||||
}
|
||||
protected String geteMail() {
|
||||
return eMail;
|
||||
}
|
||||
protected String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
||||
private class AddAccountDialog extends DataEntryDialog<UserData> {
|
||||
private TextBox eMail;
|
||||
private PasswordTextBox password;
|
||||
|
||||
public AddAccountDialog(final AbstractFilterablePanel<String> filterAccountsPanel, final SailingServiceAsync sailingService, final StringMessages stringMessages, final ErrorReporter errorReporter) {
|
||||
super(stringMessages.addIgtimiUser(), stringMessages.addIgtimiUser(), stringMessages.ok(), stringMessages.cancel(),
|
||||
new Validator<UserData>() {
|
||||
@Override
|
||||
public String getErrorMessage(UserData valueToValidate) {
|
||||
final String errorMessage;
|
||||
if (valueToValidate.geteMail() == null || valueToValidate.geteMail().isEmpty()) {
|
||||
errorMessage = stringMessages.eMailMustNotBeEmpty();
|
||||
} else {
|
||||
errorMessage = null;
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
}, /* animationEnabled */ true, new DialogCallback<UserData>() {
|
||||
@Override
|
||||
public void ok(final UserData editedObject) {
|
||||
sailingService.authorizeAccessToIgtimiUser(editedObject.geteMail(), editedObject.getPassword(), new AsyncCallback<Boolean>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorAuthorizingAccessToIgtimiUser(editedObject.geteMail(),
|
||||
caught.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
if (result) {
|
||||
Window.alert(stringMessages.successfullyAuthorizedAccessToIgtimiUser(editedObject.geteMail()));
|
||||
updateAllAccounts(sailingService, filterAccountsPanel, stringMessages, errorReporter);
|
||||
} else {
|
||||
Window.alert(stringMessages.couldNotAuthorizedAccessToIgtimiUser(editedObject.geteMail()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
Grid grid = new Grid(2, 2);
|
||||
grid.setWidget(0, 0, new Label(stringMessages.emailAddress()));
|
||||
eMail = createTextBox("");
|
||||
grid.setWidget(0, 1, eMail);
|
||||
grid.setWidget(1, 0, new Label(stringMessages.password()));
|
||||
password = createPasswordTextBox("");
|
||||
grid.setWidget(1, 1, password);
|
||||
return grid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
eMail.setFocus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserData getResult() {
|
||||
return new UserData(eMail.getText(), password.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateAllAccounts(SailingServiceAsync sailingService, final AbstractFilterablePanel<String> filterAccountsPanel,
|
||||
final StringMessages stringMessages, final ErrorReporter errorReporter) {
|
||||
sailingService.getAllIgtimiAccountEmailAddresses(new AsyncCallback<Iterable<String>>() {
|
||||
@Override
|
||||
public void onSuccess(Iterable<String> result) {
|
||||
filterAccountsPanel.updateAll(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorFetchingIgtimiAccounts(caught.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addAccount() {
|
||||
new AddAccountDialog(filterAccountsPanel, sailingService, stringMessages, errorReporter).show();
|
||||
}
|
||||
|
||||
private void removeAccount(final String eMailOfAccountToRemove, final ListDataProvider<String> removeFrom) {
|
||||
sailingService.removeIgtimiAccount(eMailOfAccountToRemove, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorTryingToRemoveIgtimiAccount(eMailOfAccountToRemove));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
Window.alert(stringMessages.successfullyRemoveIgtimiAccount(eMailOfAccountToRemove));
|
||||
removeFrom.getList().remove(eMailOfAccountToRemove);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -211,7 +211,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
leaderboardRemoveButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
if (Window.confirm("Do you really want to remove the leaderboards?")) {
|
||||
if (Window.confirm(stringMessages.doYouReallyWantToRemoveLeaderboards())) {
|
||||
removeLeaderboards(leaderboardSelectionModel.getSelectedSet());
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
@Override
|
||||
public void update(int index, StrippedLeaderboardDTO leaderboardDTO, String value) {
|
||||
if (LeaderboardConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
|
||||
if (Window.confirm("Do you really want to remove the leaderboard: '" + leaderboardDTO.name + "' ?")) {
|
||||
if (Window.confirm(stringMessages.doYouReallyWantToRemoveLeaderboard(leaderboardDTO.name))) {
|
||||
removeLeaderboard(leaderboardDTO);
|
||||
}
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_EDIT.equals(value)) {
|
||||
@@ -318,7 +318,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
otherExistingLeaderboard.addAll(availableLeaderboardList);
|
||||
otherExistingLeaderboard.remove(leaderboardDTO);
|
||||
if (leaderboardDTO.type.isMetaLeaderboard()) {
|
||||
Window.alert("This is a meta leaderboard. It can't be changed here.");
|
||||
Window.alert(stringMessages.metaLeaderboardCannotBeChanged());
|
||||
} else {
|
||||
if (leaderboardDTO.type.isRegattaLeaderboard()) {
|
||||
LeaderboardDescriptor descriptor = new LeaderboardDescriptor(leaderboardDTO.name,
|
||||
@@ -736,7 +736,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
if (!result) {
|
||||
Window.alert("Failed to set new start time.");
|
||||
Window.alert(stringMessages.failedToSetNewStartTime());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1120,7 +1120,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
});
|
||||
}
|
||||
});
|
||||
dialog.ensureDebugId("FlexibleLeaderboardCreateDialog");
|
||||
dialog.ensureDebugId("CreateFlexibleLeaderboardDialog");
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@@ -1273,5 +1273,5 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
@Override
|
||||
public StrippedLeaderboardDTO getSelectedLeaderboard() {
|
||||
return leaderboardSelectionModel.getSelectedSet().isEmpty() ? null : leaderboardSelectionModel.getSelectedSet().iterator().next();
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-10
@@ -40,7 +40,6 @@ import com.sap.sailing.gwt.ui.client.AbstractRegattaPanel;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardGroupRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.MarkedAsyncCallback;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
@@ -157,7 +156,6 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
|
||||
private Widget createLeaderboardsGUI(Resources tableRes) {
|
||||
CaptionPanel leaderboardsCaptionPanel = new CaptionPanel(stringMessages.leaderboards());
|
||||
leaderboardsCaptionPanel.ensureDebugId("LeaderboardsCaptionPanel");
|
||||
leaderboardsCaptionPanel.setWidth("95%");
|
||||
|
||||
VerticalPanel leaderboardsPanel = new VerticalPanel();
|
||||
@@ -173,7 +171,6 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
leaderboardsProvider = new ListDataProvider<StrippedLeaderboardDTO>();
|
||||
ListHandler<StrippedLeaderboardDTO> leaderboardsListHandler = new ListHandler<StrippedLeaderboardDTO>(leaderboardsProvider.getList());
|
||||
leaderboardsTable = new CellTable<StrippedLeaderboardDTO>(10000, tableRes);
|
||||
leaderboardsTable.ensureDebugId("LeaderboardsTable");
|
||||
leaderboardsFilterablePanel = new AbstractFilterablePanel<StrippedLeaderboardDTO>(filterLeaderboardsLabel, availableLeaderboards, leaderboardsTable, leaderboardsProvider) {
|
||||
@Override
|
||||
public Iterable<String> getSearchableStrings(StrippedLeaderboardDTO t) {
|
||||
@@ -191,7 +188,6 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
refreshLeaderboardsList();
|
||||
}
|
||||
});
|
||||
refreshLeaderboardsButton.ensureDebugId("RefreshLeaderboardsButton");
|
||||
leaderboardsFunctionPanel.add(refreshLeaderboardsButton);
|
||||
TextColumn<StrippedLeaderboardDTO> leaderboardsNameColumn = new TextColumn<StrippedLeaderboardDTO>() {
|
||||
@Override
|
||||
@@ -396,7 +392,6 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
groupsProvider = new ListDataProvider<LeaderboardGroupDTO>();
|
||||
ListHandler<LeaderboardGroupDTO> leaderboardGroupsListHandler = new ListHandler<LeaderboardGroupDTO>(groupsProvider.getList());
|
||||
groupsTable = new CellTable<LeaderboardGroupDTO>(10000, tableRes);
|
||||
groupsTable.ensureDebugId("LeaderboardGroupsTable");
|
||||
groupsFilterablePanel = new AbstractFilterablePanel<LeaderboardGroupDTO>(filterLeaderboardGroupsLbl, availableLeaderboardGroups, groupsTable, groupsProvider) {
|
||||
@Override
|
||||
public Iterable<String> getSearchableStrings(LeaderboardGroupDTO t) {
|
||||
@@ -413,7 +408,6 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
addNewGroup();
|
||||
}
|
||||
});
|
||||
createGroupButton.ensureDebugId("CreateLeaderboardGroupButton");
|
||||
leaderboardGroupsFunctionPanel.add(createGroupButton);
|
||||
|
||||
removeButton = new Button(stringMessages.remove());
|
||||
@@ -606,21 +600,20 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
|
||||
createNewGroup(newGroup);
|
||||
}
|
||||
});
|
||||
dialog.ensureDebugId("LeaderboardGroupCreateDialog");
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void createNewGroup(final LeaderboardGroupDescriptor newGroup) {
|
||||
sailingService.createLeaderboardGroup(newGroup.getName(), newGroup.getDescription(), newGroup.isDisplayLeaderboardsInReverseOrder(),
|
||||
newGroup.getOverallLeaderboardDiscardThresholds(),
|
||||
newGroup.getOverallLeaderboardScoringSchemeType(), new MarkedAsyncCallback<LeaderboardGroupDTO>() {
|
||||
newGroup.getOverallLeaderboardScoringSchemeType(), new AsyncCallback<LeaderboardGroupDTO>() {
|
||||
@Override
|
||||
public void handleFailure(Throwable t) {
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to create new leaderboard group" + newGroup.getName()
|
||||
+ ": " + t.getMessage());
|
||||
}
|
||||
@Override
|
||||
public void handleSuccess(LeaderboardGroupDTO newGroup) {
|
||||
public void onSuccess(LeaderboardGroupDTO newGroup) {
|
||||
availableLeaderboardGroups.add(newGroup);
|
||||
groupsProvider.getList().add(newGroup);
|
||||
groupsSelectionModel.clear();
|
||||
|
||||
+1
-3
@@ -12,9 +12,7 @@ public class LeaderboardGroupCreateDialog extends LeaderboardGroupDialog {
|
||||
super(new LeaderboardGroupDTO(), stringMessages,
|
||||
callback, existingGroups);
|
||||
nameEntryField = createTextBox(null, 50);
|
||||
nameEntryField.ensureDebugId("NameTextBox");
|
||||
descriptionEntryField = createTextArea(null);
|
||||
descriptionEntryField.ensureDebugId("DescriptionTextBox");
|
||||
descriptionEntryField = createTextArea(null);
|
||||
displayLeaderboardsInReverseOrderCheckBox.setValue(false);
|
||||
useOverallLeaderboardCheckBox.setValue(false);
|
||||
}
|
||||
|
||||
+1
-14
@@ -69,34 +69,22 @@ public class RegattaDetailsComposite extends Composite {
|
||||
mainPanel.add(vPanel);
|
||||
Grid grid = new Grid(5, 2);
|
||||
vPanel.add(grid);
|
||||
|
||||
regattaName = new Label();
|
||||
regattaName.ensureDebugId("RegattaNameLabel");
|
||||
grid.setWidget(0 , 0, new Label(stringMessages.regattaName() + ":"));
|
||||
grid.setWidget(0 , 1, regattaName);
|
||||
|
||||
boatClassName = new Label();
|
||||
boatClassName.ensureDebugId("BoatClassNameLabel");
|
||||
grid.setWidget(1 , 0, new Label(stringMessages.boatClass() + ":"));
|
||||
grid.setWidget(1 , 1, boatClassName);
|
||||
|
||||
defaultCourseArea = new Label();
|
||||
defaultCourseArea.ensureDebugId("CourseAreaLabel");
|
||||
grid.setWidget(2 , 0, new Label(stringMessages.courseArea() + ":"));
|
||||
grid.setWidget(2 , 1, defaultCourseArea);
|
||||
|
||||
configuration = new Label();
|
||||
configuration.ensureDebugId("RacingProcedureConfigurationLabel");
|
||||
grid.setWidget(3, 0, new Label(stringMessages.racingProcedureConfiguration() + ":"));
|
||||
grid.setWidget(3, 1, configuration);
|
||||
|
||||
grid.setWidget(3, 1, configuration);;
|
||||
scoringSystem = new Label();
|
||||
scoringSystem.ensureDebugId("ScoringSystemLabel");
|
||||
grid.setWidget(4 , 0, new Label(stringMessages.scoringSystem() + ":"));
|
||||
grid.setWidget(4 , 1, scoringSystem);
|
||||
|
||||
seriesTable = createRegattaSeriesTable();
|
||||
seriesTable.ensureDebugId("SeriesTable");
|
||||
seriesSelectionModel = new SingleSelectionModel<SeriesDTO>();
|
||||
seriesSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
@@ -251,7 +239,6 @@ public class RegattaDetailsComposite extends Composite {
|
||||
updateRacesOfRegattaSeries(regatta, result);
|
||||
}
|
||||
});
|
||||
raceDialog.ensureDebugId("SeriesEditDialog");
|
||||
raceDialog.show();
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -16,17 +16,14 @@ public class RegattaLeaderboardCreateDialog extends RegattaLeaderboardDialog {
|
||||
super(stringMessages.createRegattaLeaderboard(), new LeaderboardDescriptor(), existingRegattas, stringMessages, errorReporter, new RegattaLeaderboardDialog.LeaderboardParameterValidator(stringMessages, existingLeaderboards), callback);
|
||||
|
||||
nameTextBox = createTextBox(null);
|
||||
nameTextBox.ensureDebugId("LeaderboardNameField");
|
||||
displayNameTextBox = createTextBox(null);
|
||||
displayNameTextBox.ensureDebugId("DisplayNameField");
|
||||
|
||||
|
||||
// the name of the regatta leaderboard will be derived from the selected regatta
|
||||
nameTextBox.setEnabled(false);
|
||||
nameTextBox.setVisibleLength(50);
|
||||
displayNameTextBox.setVisibleLength(50);
|
||||
|
||||
regattaListBox = createSortedRegattaListBox(existingRegattas, null);
|
||||
regattaListBox.ensureDebugId("RegattaDropDown");
|
||||
regattaListBox.addChangeHandler(new ChangeHandler() {
|
||||
public void onChange(ChangeEvent event) {
|
||||
int selectedIndex = regattaListBox.getSelectedIndex();
|
||||
|
||||
+2
-12
@@ -79,17 +79,12 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
mainPanel.setWidget(panel);
|
||||
Label filterRegattasLabel = new Label(stringMessages.filterRegattasByName() + ":");
|
||||
filterRegattasLabel.setWordWrap(false);
|
||||
|
||||
noRegattasLabel = new Label(stringMessages.noRegattasYet());
|
||||
noRegattasLabel.ensureDebugId("NoRegattasLabel");
|
||||
noRegattasLabel.setWordWrap(false);
|
||||
panel.add(noRegattasLabel);
|
||||
|
||||
regattaListDataProvider = new ListDataProvider<RegattaDTO>();
|
||||
regattaTable = createRegattaTable();
|
||||
regattaTable.ensureDebugId("RegattasTable");
|
||||
regattaTable.setVisible(false);
|
||||
|
||||
filterablePanelRegattas = new AbstractFilterablePanel<RegattaDTO>(filterRegattasLabel, allRegattas,
|
||||
regattaTable, regattaListDataProvider) {
|
||||
@Override
|
||||
@@ -101,7 +96,6 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
}
|
||||
};
|
||||
panel.add(filterablePanelRegattas);
|
||||
|
||||
regattaSelectionModel = new MultiSelectionModel<RegattaDTO>();
|
||||
regattaSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
@@ -119,7 +113,6 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
panel.add(regattaTable);
|
||||
|
||||
initWidget(mainPanel);
|
||||
|
||||
}
|
||||
|
||||
private CellTable<RegattaDTO> createRegattaTable() {
|
||||
@@ -179,7 +172,7 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
private void removeRegatta(final RegattaDTO regatta) {
|
||||
final RegattaIdentifier regattaIdentifier = new RegattaName(regatta.getName());
|
||||
sailingService.removeRegatta(regattaIdentifier, new AsyncCallback<Void>() {
|
||||
@@ -195,7 +188,6 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
});
|
||||
}
|
||||
|
||||
// TODO [D049941]: Use MarkedAsyncCallback
|
||||
private void editRegatta(final RegattaDTO toBeEdited) {
|
||||
final Collection<RegattaDTO> existingRegattas = getAllRegattas();
|
||||
sailingService.getEvents(new AsyncCallback<List<EventDTO>>() {
|
||||
@@ -223,11 +215,9 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer
|
||||
commitEditedRegatta(editedRegatta);
|
||||
}
|
||||
});
|
||||
dialog.ensureDebugId("RegattaEditDialog");
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// TODO [D049941]: Use MarkedAsyncCallback
|
||||
|
||||
private void commitEditedRegatta(final RegattaDTO editedRegatta) {
|
||||
final RegattaIdentifier regattaName = new RegattaName(editedRegatta.getName());
|
||||
|
||||
|
||||
+1
-7
@@ -66,7 +66,6 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega
|
||||
HorizontalPanel regattaManagementControlsPanel = new HorizontalPanel();
|
||||
regattaManagementControlsPanel.setSpacing(5);
|
||||
Button addRegattaBtn = new Button(stringMessages.addRegatta());
|
||||
addRegattaBtn.ensureDebugId("AddRegattaButton");
|
||||
addRegattaBtn.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
@@ -76,7 +75,6 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega
|
||||
regattaManagementControlsPanel.add(addRegattaBtn);
|
||||
|
||||
removeRegattaButton = new Button(stringMessages.remove());
|
||||
removeRegattaButton.ensureDebugId("RemoveRegattaButton");
|
||||
removeRegattaButton.setEnabled(false);
|
||||
removeRegattaButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
@@ -102,12 +100,10 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega
|
||||
regattaSelectionProvider.addRegattaSelectionChangeListener(this);
|
||||
|
||||
regattaListComposite = new RegattaListComposite(sailingService, regattaSelectionProvider, regattaRefresher, errorReporter, stringMessages);
|
||||
regattaListComposite.ensureDebugId("RegattaListSection");
|
||||
grid.setWidget(0, 0, regattaListComposite);
|
||||
grid.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP);
|
||||
grid.getColumnFormatter().getElement(1).getStyle().setPaddingTop(2.0, Unit.EM);
|
||||
regattaDetailsComposite = new RegattaDetailsComposite(sailingService, regattaRefresher, errorReporter, stringMessages);
|
||||
regattaDetailsComposite.ensureDebugId("RegattaDetailsSection");
|
||||
regattaDetailsComposite.setVisible(false);
|
||||
grid.setWidget(0, 1, regattaDetailsComposite);
|
||||
}
|
||||
@@ -127,8 +123,7 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [D049941]: Use MarkedAsyncCallback
|
||||
|
||||
private void openCreateRegattaDialog() {
|
||||
final Collection<RegattaDTO> existingRegattas = Collections.unmodifiableCollection(regattaListComposite.getAllRegattas());
|
||||
|
||||
@@ -157,7 +152,6 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega
|
||||
createNewRegatta(newRegatta);
|
||||
}
|
||||
});
|
||||
dialog.ensureDebugId("RegattaCreateDialog");
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
-7
@@ -45,19 +45,16 @@ public abstract class RegattaWithSeriesAndFleetsDialog extends DataEntryDialog<R
|
||||
this.existingEvents = existingEvents;
|
||||
|
||||
nameEntryField = createTextBox(null);
|
||||
nameEntryField.ensureDebugId("RegattaNameTextField");
|
||||
nameEntryField.setVisibleLength(40);
|
||||
nameEntryField.setText(regatta.getName());
|
||||
|
||||
boatClassEntryField = createTextBox(null);
|
||||
boatClassEntryField.ensureDebugId("BoatClassTextField");
|
||||
boatClassEntryField.setVisibleLength(20);
|
||||
if (regatta.boatClass != null) {
|
||||
boatClassEntryField.setText(regatta.boatClass.getName());
|
||||
}
|
||||
|
||||
scoringSchemeListBox = createListBox(false);
|
||||
scoringSchemeListBox.ensureDebugId("ScoringSystemDropDown");
|
||||
for (ScoringSchemeType scoringSchemeType : ScoringSchemeType.values()) {
|
||||
scoringSchemeListBox.addItem(ScoringSchemeTypeFormatter.format(scoringSchemeType, stringMessages),
|
||||
String.valueOf(scoringSchemeType.ordinal()));
|
||||
@@ -67,11 +64,7 @@ public abstract class RegattaWithSeriesAndFleetsDialog extends DataEntryDialog<R
|
||||
}
|
||||
|
||||
sailingEventsListBox = createListBox(false);
|
||||
sailingEventsListBox.ensureDebugId("EventDropDown");
|
||||
|
||||
courseAreaListBox = createListBox(false);
|
||||
courseAreaListBox.ensureDebugId("CourseAreaDropDown");
|
||||
|
||||
setupEventAndCourseAreaListBoxes(stringMessages);
|
||||
|
||||
courseAreaListBox.setEnabled(false);
|
||||
|
||||
+88
-12
@@ -1,8 +1,10 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@@ -17,22 +19,26 @@ import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.cellview.client.CellTable;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
|
||||
import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.google.gwt.view.client.MultiSelectionModel;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.sap.sailing.domain.common.impl.NaturalComparator;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.EventRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.URLEncoder;
|
||||
import com.sap.sailing.gwt.ui.client.shared.panels.AbstractFilterablePanel;
|
||||
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
|
||||
@@ -50,6 +56,8 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
private CellTable<EventDTO> eventTable;
|
||||
private MultiSelectionModel<EventDTO> eventSelectionModel;
|
||||
private ListDataProvider<EventDTO> eventProvider;
|
||||
private List<EventDTO> allEvents;
|
||||
private AbstractFilterablePanel<EventDTO> filterTextbox;
|
||||
private Button removeEventsButton;
|
||||
|
||||
public static class AnchorCell extends AbstractCell<SafeHtml> {
|
||||
@@ -65,7 +73,7 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
}
|
||||
|
||||
private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
|
||||
|
||||
|
||||
private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
|
||||
|
||||
public SailingEventManagementPanel(final SailingServiceAsync sailingService, final ErrorReporter errorReporter,
|
||||
@@ -90,7 +98,7 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
}
|
||||
});
|
||||
eventsPanel.add(createEventBtn);
|
||||
|
||||
|
||||
removeEventsButton = new Button(stringMessages.remove());
|
||||
removeEventsButton.setEnabled(false);
|
||||
removeEventsButton.addClickHandler(new ClickHandler() {
|
||||
@@ -169,6 +177,12 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
}
|
||||
});
|
||||
|
||||
eventNameColumn.setSortable(true);
|
||||
venueNameColumn.setSortable(true);
|
||||
publicationUrlColumn.setSortable(true);
|
||||
isPublicColumn.setSortable(true);
|
||||
courseAreasColumn.setSortable(true);
|
||||
|
||||
eventTable = new CellTable<EventDTO>(10000, tableRes);
|
||||
eventTable.addColumn(eventNameColumn, stringMessages.event());
|
||||
eventTable.addColumn(venueNameColumn, stringMessages.venue());
|
||||
@@ -189,10 +203,68 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
eventProvider = new ListDataProvider<EventDTO>();
|
||||
eventProvider.addDataDisplay(eventTable);
|
||||
mainPanel.add(eventTable);
|
||||
allEvents = new ArrayList<EventDTO>();
|
||||
eventTable.addColumnSortHandler(getEventTableColumnSortHandler(eventProvider.getList(), eventNameColumn,
|
||||
venueNameColumn, publicationUrlColumn, isPublicColumn, courseAreasColumn));
|
||||
filterTextbox = new AbstractFilterablePanel<EventDTO>(new Label("Filter events by name: "), allEvents,
|
||||
eventTable, eventProvider) {
|
||||
|
||||
@Override
|
||||
public Iterable<String> getSearchableStrings(EventDTO t) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
result.add(t.getName());
|
||||
result.add(t.venue.getName());
|
||||
for (CourseAreaDTO c : t.venue.getCourseAreas()) {
|
||||
result.add(c.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
eventsPanel.add(filterTextbox);
|
||||
fillEvents();
|
||||
}
|
||||
|
||||
private ListHandler<EventDTO> getEventTableColumnSortHandler(List<EventDTO> eventRecords,
|
||||
Column<EventDTO, SafeHtml> eventNameColumn, TextColumn<EventDTO> venueNameColumn,
|
||||
TextColumn<EventDTO> publicationUrlColumn, TextColumn<EventDTO> isPublicColumn,
|
||||
Column<EventDTO, SafeHtml> courseAreasColumn) {
|
||||
ListHandler<EventDTO> result = new ListHandler<EventDTO>(eventRecords);
|
||||
result.setComparator(eventNameColumn, new Comparator<EventDTO>() {
|
||||
@Override
|
||||
public int compare(EventDTO e1, EventDTO e2) {
|
||||
return new NaturalComparator().compare(e1.getName(), e2.getName());
|
||||
}
|
||||
});
|
||||
result.setComparator(venueNameColumn, new Comparator<EventDTO>() {
|
||||
@Override
|
||||
public int compare(EventDTO e1, EventDTO e2) {
|
||||
return new NaturalComparator().compare(e1.venue.getName(), e2.venue.getName());
|
||||
}
|
||||
});
|
||||
result.setComparator(publicationUrlColumn, new Comparator<EventDTO>() {
|
||||
@Override
|
||||
public int compare(EventDTO e1, EventDTO e2) {
|
||||
return new NaturalComparator().compare(e1.publicationUrl, e2.publicationUrl);
|
||||
}
|
||||
});
|
||||
result.setComparator(isPublicColumn, new Comparator<EventDTO>() {
|
||||
@Override
|
||||
public int compare(EventDTO e1, EventDTO e2) {
|
||||
return e1.isPublic == e2.isPublic ? 0 : e1.isPublic ? 1 : -1;
|
||||
}
|
||||
});
|
||||
result.setComparator(courseAreasColumn, new Comparator<EventDTO>() {
|
||||
@Override
|
||||
public int compare(EventDTO e1, EventDTO e2) {
|
||||
return new NaturalComparator().compare(Arrays.toString(e1.venue.getCourseAreas().toArray()),
|
||||
Arrays.toString(e2.venue.getCourseAreas().toArray()));
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private void removeEvents(Collection<EventDTO> events) {
|
||||
if (!events.isEmpty()) {
|
||||
Collection<String> eventIds = new HashSet<String>();
|
||||
@@ -261,12 +333,12 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
|
||||
private void updateEvent(final EventDTO oldEvent, final EventDTO updatedEvent) {
|
||||
List<String> regattaNames = new ArrayList<String>();
|
||||
// for(RegattaDTO regatta: updatedEvent.regattas) {
|
||||
// regattaNames.add(regatta.name);
|
||||
// }
|
||||
// for(RegattaDTO regatta: updatedEvent.regattas) {
|
||||
// regattaNames.add(regatta.name);
|
||||
// }
|
||||
List<CourseAreaDTO> courseAreasToAdd = getCourseAreasToAdd(oldEvent, updatedEvent);
|
||||
|
||||
sailingService.updateEvent(oldEvent.getName(), oldEvent.id, updatedEvent.venue, updatedEvent.publicationUrl,
|
||||
sailingService.updateEvent(oldEvent.getName(), oldEvent.id, updatedEvent.venue, updatedEvent.publicationUrl,
|
||||
updatedEvent.isPublic, regattaNames, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
@@ -276,15 +348,17 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
fillEvents();
|
||||
if(!oldEvent.getName().equals(updatedEvent.getName())) {
|
||||
if (!oldEvent.getName().equals(updatedEvent.getName())) {
|
||||
sailingService.renameEvent(oldEvent.id, updatedEvent.getName(), new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
fillEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to rename sailing event " + oldEvent.getName() + ": " + t.getMessage());
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -315,12 +389,12 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
List<String> courseAreaNamesToAdd = new ArrayList<String>();
|
||||
|
||||
List<String> newCourseAreaNames = new ArrayList<String>();
|
||||
for(CourseAreaDTO courseArea : updatedEvent.venue.getCourseAreas()) {
|
||||
for (CourseAreaDTO courseArea : updatedEvent.venue.getCourseAreas()) {
|
||||
newCourseAreaNames.add(courseArea.getName());
|
||||
}
|
||||
|
||||
List<String> oldCourseAreaNames = new ArrayList<String>();
|
||||
for(CourseAreaDTO courseArea : oldEvent.venue.getCourseAreas()) {
|
||||
for (CourseAreaDTO courseArea : oldEvent.venue.getCourseAreas()) {
|
||||
oldCourseAreaNames.add(courseArea.getName());
|
||||
}
|
||||
|
||||
@@ -329,7 +403,7 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
courseAreaNamesToAdd.add(newCourseAreaName);
|
||||
}
|
||||
|
||||
for(CourseAreaDTO courseArea : updatedEvent.venue.getCourseAreas()) {
|
||||
for (CourseAreaDTO courseArea : updatedEvent.venue.getCourseAreas()) {
|
||||
if (courseAreaNamesToAdd.contains(courseArea.getName())) {
|
||||
courseAreasToAdd.add(courseArea);
|
||||
}
|
||||
@@ -347,6 +421,7 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to create new event" + newEvent.getName() + ": " + t.getMessage());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -365,8 +440,9 @@ public class SailingEventManagementPanel extends SimplePanel implements EventRef
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<EventDTO> result) {
|
||||
eventProvider.getList().clear();
|
||||
eventProvider.getList().addAll(result);
|
||||
allEvents.clear();
|
||||
allEvents.addAll(result);
|
||||
filterTextbox.updateAll(allEvents);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-11
@@ -153,24 +153,16 @@ public class SeriesEditDialog extends DataEntryDialog<SeriesDescriptor> {
|
||||
String seriesName = getSelectedSeries().getName();
|
||||
seriesPanel.add(new Label(stringMessages.series() + ": " + seriesName));
|
||||
additionalWidgetPanel.add(seriesPanel);
|
||||
|
||||
isMedalCheckbox = createCheckbox(stringMessages.medalSeries());
|
||||
isMedalCheckbox.ensureDebugId("MedalSeriesCheckbox");
|
||||
isMedalCheckbox.setValue(selectedSeries.isMedal());
|
||||
additionalWidgetPanel.add(isMedalCheckbox);
|
||||
|
||||
startWithZeroScoreCheckbox = createCheckbox(stringMessages.startsWithZeroScore());
|
||||
startWithZeroScoreCheckbox.ensureDebugId("StartsWithZeroScoreCheckbox");
|
||||
startWithZeroScoreCheckbox.setValue(selectedSeries.isStartsWithZeroScore());
|
||||
additionalWidgetPanel.add(startWithZeroScoreCheckbox);
|
||||
|
||||
firstColumnIsNonDiscardableCarryForwardCheckbox = createCheckbox(stringMessages.firstRaceIsNonDiscardableCarryForward());
|
||||
firstColumnIsNonDiscardableCarryForwardCheckbox.ensureDebugId("StartsWithNonDiscardableCarryForwardCheckbox");
|
||||
firstColumnIsNonDiscardableCarryForwardCheckbox.setValue(selectedSeries.isFirstColumnIsNonDiscardableCarryForward());
|
||||
additionalWidgetPanel.add(firstColumnIsNonDiscardableCarryForwardCheckbox);
|
||||
|
||||
useSeriesResultDiscardingThresholdsCheckbox = createCheckbox(stringMessages.seriesDefinesResultDiscardingRule());
|
||||
useSeriesResultDiscardingThresholdsCheckbox.ensureDebugId("DefinesResultDiscardingRulesCheckbox");
|
||||
useSeriesResultDiscardingThresholdsCheckbox.setValue(selectedSeries.getDiscardThresholds() != null);
|
||||
useSeriesResultDiscardingThresholdsCheckbox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
@@ -179,13 +171,10 @@ public class SeriesEditDialog extends DataEntryDialog<SeriesDescriptor> {
|
||||
}
|
||||
});
|
||||
additionalWidgetPanel.add(useSeriesResultDiscardingThresholdsCheckbox);
|
||||
|
||||
additionalWidgetPanel.add(discardThresholdBoxes.getWidget());
|
||||
discardThresholdBoxes.getWidget().setVisible(useSeriesResultDiscardingThresholdsCheckbox.getValue());
|
||||
|
||||
raceNamesEditor = new StringListEditorComposite(getExistingRacesOfSeries(), new RaceNamesEditorUi(stringMessages, resources.removeIcon(), seriesName));
|
||||
additionalWidgetPanel.add(raceNamesEditor);
|
||||
|
||||
return additionalWidgetPanel;
|
||||
}
|
||||
|
||||
|
||||
-12
@@ -101,31 +101,19 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog<SeriesDTO> {
|
||||
this.stringMessages = stringMessages;
|
||||
this.series = new SeriesDTO();
|
||||
nameEntryField = createTextBox(null);
|
||||
nameEntryField.ensureDebugId("NameTextField");
|
||||
nameEntryField.setVisibleLength(40);
|
||||
|
||||
isMedalSeriesCheckbox = createCheckbox(stringMessages.medalSeries());
|
||||
isMedalSeriesCheckbox.ensureDebugId("MedalSeriesCheckbox");
|
||||
|
||||
startsWithZeroScoreCheckbox = createCheckbox(stringMessages.startsWithZeroScore());
|
||||
startsWithZeroScoreCheckbox.ensureDebugId("StartsWithZeroScoreCheckbox");
|
||||
|
||||
firstColumnIsNonDiscardableCarryForwardCheckbox = createCheckbox(stringMessages.firstRaceIsNonDiscardableCarryForward());
|
||||
firstColumnIsNonDiscardableCarryForwardCheckbox.ensureDebugId("StartsWithNonDiscardableCarryForwardCheckbox");
|
||||
|
||||
useSeriesResultDiscardingThresholdsCheckbox = createCheckbox(stringMessages.seriesDefinesResultDiscardingRule());
|
||||
useSeriesResultDiscardingThresholdsCheckbox.ensureDebugId("DefinesResultDiscardingRulesCheckbox");
|
||||
useSeriesResultDiscardingThresholdsCheckbox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
discardThresholdBoxes.getWidget().setVisible(event.getValue());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
discardThresholdBoxes = new DiscardThresholdBoxes(this, stringMessages);
|
||||
discardThresholdBoxes.getWidget().setVisible(false);
|
||||
|
||||
fleetListComposite = FleetListEditorComposite.createExpanded(Arrays.asList(new FleetDTO("Default", 0, null)), stringMessages, resources.removeIcon());
|
||||
fleetListComposite.addValueChangeHandler(new ValueChangeHandler<List<FleetDTO>>() {
|
||||
|
||||
|
||||
+3
-5
@@ -102,7 +102,7 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite
|
||||
@Override
|
||||
protected void addControlButtons(HorizontalPanel trackedRacesButtonPanel) {
|
||||
btnRemoveRace = new Button(stringMessages.remove());
|
||||
btnRemoveRace.ensureDebugId("RemoveButton");
|
||||
btnRemoveRace.ensureDebugId("RemoveRave");
|
||||
btnRemoveRace.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
@@ -112,7 +112,7 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite
|
||||
btnRemoveRace.setEnabled(false);
|
||||
trackedRacesButtonPanel.add(btnRemoveRace);
|
||||
btnUntrack = new Button(stringMessages.stopTracking());
|
||||
btnUntrack.ensureDebugId("StopTrackingButton");
|
||||
btnUntrack.ensureDebugId("UntrackRace");
|
||||
btnUntrack.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent click) {
|
||||
@@ -124,7 +124,7 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite
|
||||
|
||||
|
||||
btnSetDelayToLive = new Button(stringMessages.setDelayToLive() + "...");
|
||||
btnSetDelayToLive.ensureDebugId("SetDelayToLiveButton");
|
||||
btnSetDelayToLive.ensureDebugId("SetDelayToLive");
|
||||
btnSetDelayToLive.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
@@ -134,9 +134,7 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite
|
||||
trackedRacesButtonPanel.add(btnSetDelayToLive);
|
||||
|
||||
exportPopup = new ExportPopup(stringMessages);
|
||||
exportPopup.ensureDebugId("ExportPopup");
|
||||
btnExport = new Button(stringMessages.export());
|
||||
btnExport.ensureDebugId("ExportButton");
|
||||
btnExport.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
|
||||
+53
-6
@@ -6,6 +6,7 @@ import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.cell.client.ActionCell;
|
||||
@@ -21,6 +22,7 @@ import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.google.gwt.regexp.shared.MatchResult;
|
||||
import com.google.gwt.regexp.shared.RegExp;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.cellview.client.CellTable;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent.Handler;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
|
||||
@@ -240,19 +242,65 @@ public class WindPanel extends FormPanel implements RegattaDisplayer, WindShower
|
||||
rawWindFixesTable.getColumnSortList().push(timeColumn);
|
||||
windFixesDisplayPanel.add(rawWindFixesTable);
|
||||
|
||||
createWindImportPanel(mainPanel, stringMessages);
|
||||
mainPanel.add(createExpeditionWindImportPanel());
|
||||
mainPanel.add(createIgtimiWindImportPanel(mainPanel));
|
||||
|
||||
}
|
||||
|
||||
private void createWindImportPanel(Panel mainPanel, final StringMessages stringMessages) {
|
||||
private CaptionPanel createIgtimiWindImportPanel(VerticalPanel mainPanel) {
|
||||
CaptionPanel igtimiWindImportRootPanel = new CaptionPanel(stringMessages.igtimiWindImport());
|
||||
VerticalPanel contentPanel = new VerticalPanel();
|
||||
igtimiWindImportRootPanel.add(contentPanel);
|
||||
contentPanel.add(new Label(stringMessages.seeIgtimiTabForAccountSettings()));
|
||||
final Button importButton = new Button(stringMessages.importWindFromIgtimi());
|
||||
final HTML resultReport = new HTML();
|
||||
importButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
final String warningMessage;
|
||||
if (trackedRacesListComposite.getSelectedRaces().isEmpty()) {
|
||||
warningMessage = stringMessages.windImport_AllRacesWarning();
|
||||
} else {
|
||||
warningMessage = stringMessages.windImport_SelectedRacesWarning(trackedRacesListComposite.getSelectedRaces().size());
|
||||
}
|
||||
if (Window.confirm(warningMessage)) {
|
||||
resultReport.setText(stringMessages.loading());
|
||||
sailingService.importWindFromIgtimi(trackedRacesListComposite.getSelectedRaces(), new AsyncCallback<Map<RegattaAndRaceIdentifier, Integer>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorImportingIgtimiWind(caught.getMessage()));
|
||||
resultReport.setText(stringMessages.errorImportingIgtimiWind(caught.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Map<RegattaAndRaceIdentifier, Integer> result) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
for (Entry<RegattaAndRaceIdentifier, Integer> e : result.entrySet()) {
|
||||
sb.append(e.getKey().getRegattaName());
|
||||
sb.append('/');
|
||||
sb.append(e.getKey().getRaceName());
|
||||
sb.append(": ");
|
||||
sb.append(e.getValue());
|
||||
sb.append("\n");
|
||||
}
|
||||
resultReport.setHTML(new SafeHtmlBuilder().appendEscapedLines(stringMessages.resultFromIgtimiWindImport(sb.toString())).toSafeHtml());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
contentPanel.add(importButton);
|
||||
contentPanel.add(resultReport);
|
||||
return igtimiWindImportRootPanel;
|
||||
}
|
||||
|
||||
private CaptionPanel createExpeditionWindImportPanel() {
|
||||
/*
|
||||
* To style the "browse" button of the file upload widget
|
||||
* see http://www.shauninman.com/archive/2007/09/10/styling_file_inputs_with_css_and_the_dom
|
||||
*/
|
||||
|
||||
CaptionPanel windImportRootPanel = new CaptionPanel(stringMessages.windImport_Title());
|
||||
mainPanel.add(windImportRootPanel);
|
||||
VerticalPanel windImportContentPanel = new VerticalPanel();
|
||||
windImportRootPanel.add(windImportContentPanel);
|
||||
final FormPanel form = new FormPanel();
|
||||
@@ -369,7 +417,7 @@ public class WindPanel extends FormPanel implements RegattaDisplayer, WindShower
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return windImportRootPanel;
|
||||
}
|
||||
|
||||
private void showWindSettingDialog(RaceDTO race, CoursePositionsDTO course) {
|
||||
@@ -532,7 +580,6 @@ public class WindPanel extends FormPanel implements RegattaDisplayer, WindShower
|
||||
@Override
|
||||
public void onSuccess(WindInfoForRaceDTO result) {
|
||||
windFixPanel.clear();
|
||||
|
||||
for (WindSourceType input : new WindSourceType[] { WindSourceType.COMBINED }) {
|
||||
windFixPanel.add(new HTML(" "));
|
||||
windFixPanel.add(new Label(stringMessages.windFixListingDescription() + " " + input.name()));
|
||||
|
||||
+38
@@ -23,6 +23,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.LongBox;
|
||||
import com.google.gwt.user.client.ui.PasswordTextBox;
|
||||
import com.google.gwt.user.client.ui.RadioButton;
|
||||
import com.google.gwt.user.client.ui.TextArea;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
@@ -182,6 +183,43 @@ public abstract class DataEntryDialog<T> {
|
||||
return textBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a password text box with a key-up listener attached which ensures the value is updated after each
|
||||
* key-up event and the entire dialog is {@link #validate() validated} in this case.
|
||||
*
|
||||
* @param initialValue initial value to show in text box; <code>null</code> is permissible
|
||||
*/
|
||||
public PasswordTextBox createPasswordTextBox(String initialValue) {
|
||||
return createPasswordTextBoxInternal(initialValue, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a password text box with a key-up listener attached which ensures the value is updated after each
|
||||
* key-up event and the entire dialog is {@link #validate() validated} in this case.
|
||||
*
|
||||
* @param initialValue initial value to show in text box; <code>null</code> is permissible
|
||||
* @param visibleLength the visible length of the text box
|
||||
*/
|
||||
public PasswordTextBox createPasswordTextBox(String initialValue, int visibleLength) {
|
||||
return createPasswordTextBoxInternal(initialValue, visibleLength);
|
||||
}
|
||||
|
||||
private PasswordTextBox createPasswordTextBoxInternal(String initialValue, int visibleLength) {
|
||||
PasswordTextBox parrwordTextBox = new PasswordTextBox();
|
||||
parrwordTextBox.setVisibleLength(visibleLength);
|
||||
parrwordTextBox.setText(initialValue == null ? "" : initialValue);
|
||||
AbstractEntryPoint.addFocusUponKeyUpToggler(parrwordTextBox);
|
||||
parrwordTextBox.addChangeHandler(new ChangeHandler() {
|
||||
@Override
|
||||
public void onChange(ChangeEvent event) {
|
||||
validate();
|
||||
}
|
||||
});
|
||||
AbstractEntryPoint.linkEnterToButton(getOkButton(), parrwordTextBox);
|
||||
AbstractEntryPoint.linkEscapeToButton(getCancelButton(), parrwordTextBox);
|
||||
return parrwordTextBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text area with a key-up listener attached which ensures the value is updated after each
|
||||
* key-up event and the entire dialog is {@link #validate() validated} in this case.
|
||||
|
||||
+17
@@ -4,6 +4,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||
@@ -27,6 +28,22 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
|
||||
autoAdjustPlayMode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race's start time is already known and the <code>time</code> is before the start, append a count-down to the label
|
||||
*/
|
||||
@Override
|
||||
protected String getTimeLabelText(Date time) {
|
||||
final String result;
|
||||
RaceTimesInfoDTO selectedRaceTimes = raceTimesInfoProvider.getRaceTimesInfo(selectedRace);
|
||||
if (selectedRaceTimes.startOfRace != null && time.before(selectedRaceTimes.startOfRace)) {
|
||||
result = super.getTimeLabelText(time) + ", " + stringMessages.countDownInMillis(
|
||||
NumberFormat.getFormat("0.00").format(((double) selectedRaceTimes.startOfRace.getTime()-time.getTime()) / 1000.));
|
||||
} else {
|
||||
result = super.getTimeLabelText(time);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(RaceTimePanelSettings newSettings) {
|
||||
super.updateSettings(newSettings);
|
||||
|
||||
+10
-3
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -309,8 +308,6 @@ public interface SailingService extends RemoteService {
|
||||
PolarSheetGenerationResponse generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces,
|
||||
PolarSheetGenerationSettings settings, String name) throws Exception;
|
||||
|
||||
EventDTO getEventById(Serializable id);
|
||||
|
||||
CourseAreaDTO createCourseArea(String eventIdAsString, String courseAreaName);
|
||||
|
||||
EventDTO getEventByIdAsString(String eventIdAsString);
|
||||
@@ -355,4 +352,14 @@ public interface SailingService extends RemoteService {
|
||||
boolean setStartTime(RaceLogSetStartTimeDTO dto);
|
||||
|
||||
Pair<Date, Integer> getStartTime(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
Iterable<String> getAllIgtimiAccountEmailAddresses();
|
||||
|
||||
String getIgtimiAuthorizationUrl();
|
||||
|
||||
boolean authorizeAccessToIgtimiUser(String eMailAddress, String password) throws Exception;
|
||||
|
||||
void removeIgtimiAccount(String eMailOfAccountToRemove);
|
||||
|
||||
Map<RegattaAndRaceIdentifier, Integer> importWindFromIgtimi(List<RaceDTO> selectedRaces) throws Exception;
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -320,8 +319,6 @@ public interface SailingServiceAsync {
|
||||
*/
|
||||
void getEventByName(String eventName, AsyncCallback<EventDTO> callback);
|
||||
|
||||
void getEventById(Serializable id, AsyncCallback<EventDTO> callback);
|
||||
|
||||
/**
|
||||
* Renames the event with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no event with the name <code>oldName</code> or there's already a event with the name
|
||||
@@ -478,6 +475,15 @@ public interface SailingServiceAsync {
|
||||
|
||||
void getStartTime(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Pair<Date, Integer>> callback);
|
||||
|
||||
void getAllIgtimiAccountEmailAddresses(AsyncCallback<Iterable<String>> callback);
|
||||
|
||||
void getIgtimiAuthorizationUrl(AsyncCallback<String> callback);
|
||||
|
||||
void authorizeAccessToIgtimiUser(String eMailAddress, String password, AsyncCallback<Boolean> callback);
|
||||
|
||||
void removeIgtimiAccount(String eMailOfAccountToRemove, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void importWindFromIgtimi(List<RaceDTO> selectedRaces, AsyncCallback<Map<RegattaAndRaceIdentifier, Integer>> asyncCallback);
|
||||
}
|
||||
|
||||
+25
@@ -881,4 +881,29 @@ public interface StringMessages extends Messages {
|
||||
String hasAdditionalGolfDownTime();
|
||||
String additionalGolfDownTimeHelpText();
|
||||
String invalidColor(String message);
|
||||
String createSwissTimingRace();
|
||||
String igtimiAccounts();
|
||||
String errorFetchingIgtimiAccounts(String message);
|
||||
String addIgtimiAccount();
|
||||
String errorAuthorizingAccessToIgtimiUser(String text, String message);
|
||||
String successfullyAuthorizedAccessToIgtimiUser(String username);
|
||||
String couldNotAuthorizedAccessToIgtimiUser(String text);
|
||||
String errorGettingIgtimiAuthorizationUrl(String message);
|
||||
String addIgtimiUser();
|
||||
String doYouReallyWantToRemoveLeaderboards();
|
||||
String errorTryingToRemoveIgtimiAccount(String eMailOfAccountToRemove);
|
||||
String successfullyRemoveIgtimiAccount(String eMailOfAccountToRemove);
|
||||
String eMailMustNotBeEmpty();
|
||||
String emailAddress();
|
||||
String password();
|
||||
String doYouReallyWantToRemoveLeaderboard(String name);
|
||||
String metaLeaderboardCannotBeChanged();
|
||||
String failedToSetNewStartTime();
|
||||
String doYouReallyWantToRemoveIgtimiAccount(String accountEmail);
|
||||
String igtimiWindImport();
|
||||
String seeIgtimiTabForAccountSettings();
|
||||
String importWindFromIgtimi();
|
||||
String errorImportingIgtimiWind(String message);
|
||||
String resultFromIgtimiWindImport(String string);
|
||||
String countDownInMillis(String timeToStartInFractionalSeconds);
|
||||
}
|
||||
+26
-1
@@ -868,4 +868,29 @@ currentPass=Current pass
|
||||
setStartTimeDescription=Select a new start time for the race
|
||||
hasAdditionalGolfDownTime=Activate additional golf down time
|
||||
additionalGolfDownTimeHelpText=Activate additional golf down time
|
||||
invalidColor=Invalid color: {0}
|
||||
invalidColor=Invalid color: {0}
|
||||
createSwissTimingRace=Create SwissTiming race
|
||||
igtimiAccounts=Igtimi Accounts
|
||||
errorFetchingIgtimiAccounts=Error fetching all Igtimi accounts: {0}
|
||||
addIgtimiAccount=Add Igtimi Account
|
||||
errorAuthorizingAccessToIgtimiUser=Error authorizing access to Igtimi user {0}: {1}
|
||||
successfullyAuthorizedAccessToIgtimiUser=Successfully authorized access to Igtimi user {0}
|
||||
couldNotAuthorizedAccessToIgtimiUser=Could not authorize user {0}; invalid user name or password
|
||||
errorGettingIgtimiAuthorizationUrl=Error getting Igtimi authorization URL: {0}
|
||||
addIgtimiUser=Add Igtimi User
|
||||
doYouReallyWantToRemoveLeaderboards=Do you really want to remove the leaderboards?
|
||||
errorTryingToRemoveIgtimiAccount=Error trying to remove Igtimi account for user {0}
|
||||
successfullyRemoveIgtimiAccount=Successfully removed Igtimi account for user {0}
|
||||
eMailMustNotBeEmpty=e-Mail address must not be empty
|
||||
emailAddress=e-mail address
|
||||
password=Password
|
||||
doYouReallyWantToRemoveLeaderboard=Do you really want to remove the leaderboard: ''{0}''?
|
||||
metaLeaderboardCannotBeChanged=This is a meta leaderboard. It can''t be changed here.
|
||||
failedToSetNewStartTime=Failed to set new start time.
|
||||
doYouReallyWantToRemoveIgtimiAccount=Do you really want to remove Igtimi account granting access to data of user {0}?
|
||||
igtimiWindImport=Import Wind from Igtimi
|
||||
seeIgtimiTabForAccountSettings=See the ''Igtimi'' tab for account settings determining which data from Igtimi will be considered.
|
||||
importWindFromIgtimi=Import Wind from Igtimi
|
||||
errorImportingIgtimiWind=Error importing wind data from Igtimi: {0}
|
||||
resultFromIgtimiWindImport=The following number of fixes were imported for the listed races: {0}
|
||||
countDownInMillis={0}s to start
|
||||
+26
-1
@@ -864,4 +864,29 @@ currentPass=Aktueller Pass
|
||||
setStartTimeDescription=Wähle eine Startzeit für das Rennen aus
|
||||
hasAdditionalGolfDownTime=Aktiviere Golf-Flaggen Zusatzzeit
|
||||
additionalGolfDownTimeHelpText=Aktiviere Golf-Flaggen Zusatzzeit
|
||||
invalidColor=Ungültige Farbangabe: {0}
|
||||
invalidColor=Ungültige Farbangabe: {0}
|
||||
createSwissTimingRace=SwissTiming-Rennen anlegen
|
||||
igtimiAccounts=Igtimi-Konten
|
||||
errorFetchingIgtimiAccounts=Fehler beim Laden aller Igtimi-Konten: {0}
|
||||
addIgtimiAccount=Igtimi-Konto hinzufügen
|
||||
errorAuthorizingAccessToIgtimiUser=Fehler beim autorisieren des Benutzers mit der e-Mail-Adresse {0}: {1}
|
||||
successfullyAuthorizedAccessToIgtimiUser=Zugriff auf Daten von Benutzer {0} erfolgreich authorisiert
|
||||
couldNotAuthorizedAccessToIgtimiUser=Benutzer {0} konnte nicht authentifiziert werden; ungültiger Benutzername oder falsches Passwort
|
||||
errorGettingIgtimiAuthorizationUrl=Fehler beim Beschaffen der Igtimi Authorisierungs-URL: {0}
|
||||
addIgtimiUser=Igtimi-Benutzer hinzufügen
|
||||
doYouReallyWantToRemoveLeaderboards=Möchten Sie wirklich diese Ergebnislisten löschen?
|
||||
errorTryingToRemoveIgtimiAccount=Fehler beim Löschen des Zugangs zum Benutzerkonto {0}
|
||||
successfullyRemoveIgtimiAccount=Zugang zum Igtimi-Benutzerkonto {0} erfolgreich gelöscht
|
||||
eMailMustNotBeEmpty=e-Mailadresse darf nicht leer sein
|
||||
emailAddress=e-Mailadresse
|
||||
password=Kennwort
|
||||
doYouReallyWantToRemoveLeaderboard=Möchten Sie wirklich die Ergebnlisliste ''{0}'' löschen?
|
||||
metaLeaderboardCannotBeChanged=Dies ist ein Meta-Leaderboard, das hier nicht geändert werden kann.
|
||||
failedToSetNewStartTime=Neue Startzeit konnte nicht gesetzt werden.
|
||||
doYouReallyWantToRemoveIgtimiAccount=Möchten Sie wirklich den Zugang zu den Daten des Benutzers {0} löschen?
|
||||
igtimiWindImport=Wind von Igtimi importieren
|
||||
seeIgtimiTabForAccountSettings=Siehe den ''Igtimi'' Reiter für die Einstellungen, von welchen Igtimi-Konten Winddaten geladen werden sollen.
|
||||
importWindFromIgtimi=Wind von Igtimi importieren
|
||||
errorImportingIgtimiWind=Fehler beim Importieren von Wind-Daten von Igtimi: {0}
|
||||
resultFromIgtimiWindImport=Die folgenden Anzahlen von Windmessungen wurden für die aufgelisteten Wettfahrten importiert: {0}
|
||||
countDownInMillis={0}s bis zum Start
|
||||
+13
-3
@@ -307,12 +307,22 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
timeSlider.setCurrentValue(new Double(time.getTime()), false);
|
||||
}
|
||||
}
|
||||
dateLabel.setText(dateFormatter.format(time));
|
||||
dateLabel.setText(getDateLabelText(time));
|
||||
timeLabel.setText(getTimeLabelText(time));
|
||||
}
|
||||
|
||||
protected String getTimeLabelText(Date time) {
|
||||
final String timeLabelText;
|
||||
if (lastReceivedDataTimepoint == null) {
|
||||
timeLabel.setText(timeFormatter.format(time));
|
||||
timeLabelText = timeFormatter.format(time);
|
||||
} else {
|
||||
timeLabel.setText(timeFormatter.format(time) + " (" + timeFormatter.format(lastReceivedDataTimepoint) + ")");
|
||||
timeLabelText = timeFormatter.format(time) + " (" + timeFormatter.format(lastReceivedDataTimepoint) + ")";
|
||||
}
|
||||
return timeLabelText;
|
||||
}
|
||||
|
||||
protected String getDateLabelText(Date time) {
|
||||
return dateFormatter.format(time);
|
||||
}
|
||||
|
||||
protected Date getFromTime() {
|
||||
|
||||
-1
@@ -42,7 +42,6 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
this.display = display;
|
||||
this.filtered = filtered;
|
||||
this.textBox = new TextBox();
|
||||
this.textBox.ensureDebugId("FilterTextField");
|
||||
this.all = all;
|
||||
add(label);
|
||||
add(getTextBox());
|
||||
|
||||
+6
@@ -78,6 +78,9 @@ public class BoatClassImageData {
|
||||
|
||||
public ImageTransformer getBoatImageTransformerByLegTypeAndTack(LegType legType, Tack tack, boolean isSelected) {
|
||||
ImageTransformer result = null;
|
||||
if (tack == null) {
|
||||
tack = Tack.STARBOARD; // TODO this is just a fallback / workaround for not having a good image resource for unknown tack
|
||||
}
|
||||
switch (tack) {
|
||||
case PORT:
|
||||
switch (legType) {
|
||||
@@ -135,6 +138,9 @@ public class BoatClassImageData {
|
||||
|
||||
public ImageTransformer getBoatImageTransformerByTack(Tack tack, boolean isSelected) {
|
||||
ImageTransformer result = null;
|
||||
if (tack == null) {
|
||||
tack = Tack.STARBOARD; // TODO defaulting to a tack to avoid NPE; need to find a default representation for boats in unknown wind conditions
|
||||
}
|
||||
switch (tack) {
|
||||
case STARBOARD:
|
||||
if (isSelected) {
|
||||
|
||||
+6
-1
@@ -9,6 +9,7 @@ import com.google.gwt.maps.client.geometrylib.SphericalUtils;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
|
||||
/**
|
||||
@@ -51,7 +52,11 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
boatImageTransformer = boatClassImageData.getBoatImageTransformerByTack(boatFix.tack, isSelected());
|
||||
}
|
||||
double realBoatSizeScaleFactor = getRealBoatSizeScaleFactor(boatImageTransformer.getImageSize());
|
||||
double boatDrawingAngle = boatFix.speedWithBearing.bearingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE;
|
||||
SpeedWithBearingDTO speedWithBearing = boatFix.speedWithBearing;
|
||||
if (speedWithBearing == null) {
|
||||
speedWithBearing = new SpeedWithBearingDTO(0, 0);
|
||||
}
|
||||
double boatDrawingAngle = speedWithBearing.bearingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE;
|
||||
if (boatDrawingAngle < 0) {
|
||||
boatDrawingAngle += 360;
|
||||
}
|
||||
|
||||
+50
-14
@@ -173,7 +173,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
/**
|
||||
* html5 canvases used for competitor info display on the map
|
||||
*/
|
||||
private final Map<CompetitorDTO, CompetitorInfoOverlay> competitorInfoOverlays;
|
||||
private final Map<CompetitorDTO, SmallTransparentInfoOverlay> competitorInfoOverlays;
|
||||
|
||||
private SmallTransparentInfoOverlay countDownOverlay;
|
||||
|
||||
/**
|
||||
* Map overlays with html5 canvas used to display wind sensors
|
||||
@@ -268,7 +270,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
markDTOs = new HashMap<String, MarkDTO>();
|
||||
courseSidelines = new HashMap<SidelineDTO, Polygon>();
|
||||
boatOverlays = new HashMap<CompetitorDTO, BoatOverlay>();
|
||||
competitorInfoOverlays = new HashMap<CompetitorDTO, CompetitorInfoOverlay>();
|
||||
competitorInfoOverlays = new HashMap<CompetitorDTO, SmallTransparentInfoOverlay>();
|
||||
windSensorOverlays = new HashMap<WindSource, WindSensorOverlay>();
|
||||
courseMarkOverlays = new HashMap<String, CourseMarkOverlay>();
|
||||
this.competitorSelection = competitorSelection;
|
||||
@@ -637,14 +639,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (fixesAndTails.hasFixesFor(competitorDTO)) {
|
||||
GPSFixDTO lastBoatFix = getBoatFix(competitorDTO, date);
|
||||
if (lastBoatFix != null) {
|
||||
CompetitorInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(competitorDTO);
|
||||
SmallTransparentInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(competitorDTO);
|
||||
if (competitorInfoOverlay == null) {
|
||||
competitorInfoOverlay = createCompetitorInfoOverlay(RaceMapOverlaysZIndexes.COMPETITOR_INFO_ZINDEX, competitorDTO);
|
||||
competitorInfoOverlay = createCompetitorInfoOverlay(RaceMapOverlaysZIndexes.INFO_OVERLAY_ZINDEX, competitorDTO);
|
||||
competitorInfoOverlays.put(competitorDTO, competitorInfoOverlay);
|
||||
competitorInfoOverlay.setBoatFix(lastBoatFix);
|
||||
competitorInfoOverlay.setPosition(lastBoatFix.position);
|
||||
competitorInfoOverlay.addToMap();
|
||||
} else {
|
||||
competitorInfoOverlay.setBoatFix(lastBoatFix);
|
||||
competitorInfoOverlay.setPosition(lastBoatFix.position);
|
||||
competitorInfoOverlay.draw();
|
||||
}
|
||||
toRemoveCompetorInfoOverlays.remove(competitorDTO);
|
||||
@@ -652,13 +654,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
for (CompetitorDTO toRemoveCompetorDTO : toRemoveCompetorInfoOverlays) {
|
||||
CompetitorInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(toRemoveCompetorDTO);
|
||||
SmallTransparentInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(toRemoveCompetorDTO);
|
||||
competitorInfoOverlay.removeFromMap();
|
||||
competitorInfoOverlays.remove(toRemoveCompetorDTO);
|
||||
}
|
||||
} else {
|
||||
// remove all overlays
|
||||
for (CompetitorInfoOverlay competitorInfoOverlay : competitorInfoOverlays.values()) {
|
||||
for (SmallTransparentInfoOverlay competitorInfoOverlay : competitorInfoOverlays.values()) {
|
||||
competitorInfoOverlay.removeFromMap();
|
||||
}
|
||||
competitorInfoOverlays.clear();
|
||||
@@ -851,6 +853,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
int legOfLeadingCompetitor = leadingVisibleCompetitorInfo == null ? -1 : leadingVisibleCompetitorInfo.getA();
|
||||
int numberOfLegs = lastRaceTimesInfo.legInfos.size();
|
||||
// draw the start line
|
||||
updateCountdownCanvas(courseDTO.startMarkPositions);
|
||||
if (legOfLeadingCompetitor <= 1 &&
|
||||
settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINE) && courseDTO.startMarkPositions != null && courseDTO.startMarkPositions.size() == 2) {
|
||||
LatLng startLinePoint1 = LatLng.newInstance(courseDTO.startMarkPositions.get(0).latDeg, courseDTO.startMarkPositions.get(0).lngDeg);
|
||||
@@ -898,8 +901,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
startLine.getPath().insertAt(0, startLinePoint1);
|
||||
startLine.getPath().insertAt(1, startLinePoint2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (startLine != null) {
|
||||
startLine.setMap(null);
|
||||
startLine = null;
|
||||
@@ -1011,6 +1013,33 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If, according to {@link #lastRaceTimesInfo} and {@link #timer} the race is
|
||||
* still in the pre-start phase, show a {@link SmallTransparentInfoOverlay} at the
|
||||
* start line that shows the count down.
|
||||
*/
|
||||
private void updateCountdownCanvas(List<PositionDTO> startMarkPositions) {
|
||||
if (!settings.isShowSelectedCompetitorsInfo() || startMarkPositions == null || startMarkPositions.isEmpty()
|
||||
|| lastRaceTimesInfo.startOfRace == null || timer.getTime().after(lastRaceTimesInfo.startOfRace)) {
|
||||
if (countDownOverlay != null) {
|
||||
countDownOverlay.removeFromMap();
|
||||
countDownOverlay = null;
|
||||
}
|
||||
} else {
|
||||
final String countDownText = "-"+NumberFormat.getFormat("0.0").format(
|
||||
Math.round(((double) lastRaceTimesInfo.startOfRace.getTime() - timer.getTime().getTime()) / 100.)/10.);
|
||||
if (countDownOverlay == null) {
|
||||
countDownOverlay = new SmallTransparentInfoOverlay(map, RaceMapOverlaysZIndexes.INFO_OVERLAY_ZINDEX,
|
||||
countDownText, raceMapImageManager);
|
||||
countDownOverlay.addToMap();
|
||||
} else {
|
||||
countDownOverlay.setInfoText(countDownText);
|
||||
}
|
||||
countDownOverlay.setPosition(startMarkPositions.get(startMarkPositions.size() - 1));
|
||||
countDownOverlay.draw();
|
||||
}
|
||||
}
|
||||
|
||||
private void zoomMapToNewBounds(LatLngBounds newBounds) {
|
||||
if (newBounds != null) {
|
||||
List<ZoomTypes> oldZoomSettings = settings.getZoomSettings().getTypesToConsiderOnZoom();
|
||||
@@ -1058,8 +1087,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
return courseMarkOverlay;
|
||||
}
|
||||
|
||||
private CompetitorInfoOverlay createCompetitorInfoOverlay(int zIndex, final CompetitorDTO competitorDTO) {
|
||||
return new CompetitorInfoOverlay(map, zIndex, competitorDTO, raceMapImageManager);
|
||||
private SmallTransparentInfoOverlay createCompetitorInfoOverlay(int zIndex, final CompetitorDTO competitorDTO) {
|
||||
return new SmallTransparentInfoOverlay(map, zIndex,
|
||||
/* infoText */ (competitorDTO.getSailID() == null || competitorDTO.getSailID().isEmpty()) ? competitorDTO.getName() : competitorDTO.getSailID(),
|
||||
raceMapImageManager);
|
||||
}
|
||||
|
||||
private BoatOverlay createBoatOverlay(int zIndex, final CompetitorDTO competitorDTO, boolean highlighted) {
|
||||
@@ -1213,9 +1244,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (rank != null) {
|
||||
vPanel.add(createInfoWindowLabelAndValue(stringMessages.rank(), String.valueOf(rank)));
|
||||
}
|
||||
SpeedWithBearingDTO speedWithBearing = lastFix.speedWithBearing;
|
||||
if (speedWithBearing == null) {
|
||||
// TODO should we show the boat at all?
|
||||
speedWithBearing = new SpeedWithBearingDTO(0, 0);
|
||||
}
|
||||
vPanel.add(createInfoWindowLabelAndValue(stringMessages.speed(),
|
||||
NumberFormatterFactory.getDecimalFormat(1).format(lastFix.speedWithBearing.speedInKnots) + " "+stringMessages.knotsUnit()));
|
||||
vPanel.add(createInfoWindowLabelAndValue(stringMessages.bearing(), (int) lastFix.speedWithBearing.bearingInDegrees + " "+stringMessages.degreesShort()));
|
||||
NumberFormatterFactory.getDecimalFormat(1).format(speedWithBearing.speedInKnots) + " "+stringMessages.knotsUnit()));
|
||||
vPanel.add(createInfoWindowLabelAndValue(stringMessages.bearing(), (int) speedWithBearing.bearingInDegrees + " "+stringMessages.degreesShort()));
|
||||
if (lastFix.degreesBoatToTheWind != null) {
|
||||
vPanel.add(createInfoWindowLabelAndValue(stringMessages.degreesBoatToTheWind(),
|
||||
(int) Math.abs(lastFix.degreesBoatToTheWind) + " " + stringMessages.degreesShort()));
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public interface RaceMapOverlaysZIndexes {
|
||||
public static int COURSEMARK_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 2;
|
||||
public static int WINDSENSOR_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 3;
|
||||
public static int BOATS_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 4;
|
||||
public static int COMPETITOR_INFO_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 5;
|
||||
public static int INFO_OVERLAY_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 5;
|
||||
|
||||
/** the z-index of the info window should always be higher than the rest */
|
||||
public static int INFO_WINDOW_ZINDEX = BASE_CANVAS_OVERLAY_ZINDEX + 11;
|
||||
|
||||
+27
-26
@@ -6,24 +6,27 @@ import com.google.gwt.canvas.dom.client.TextMetrics;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.Point;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
|
||||
/**
|
||||
* A google map overlay based on a HTML5 canvas for drawing competitor information close to the boat
|
||||
* A google map overlay based on a HTML5 canvas for drawing a short textual information close to some object on a map
|
||||
* with a given position.
|
||||
*
|
||||
* @author Frank Mittag
|
||||
* @author Axel Uhl
|
||||
*/
|
||||
public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
/**
|
||||
* The competitor.
|
||||
* The text to display in the canvas
|
||||
*/
|
||||
private final CompetitorDTO competitorDTO;
|
||||
private String infoText;
|
||||
|
||||
/**
|
||||
* The current GPS fix of the boat position of the competitor.
|
||||
*/
|
||||
private GPSFixDTO boatFix;
|
||||
private PositionDTO position;
|
||||
|
||||
private int canvasWidth;
|
||||
private int canvasHeight;
|
||||
@@ -31,10 +34,9 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
private int infoBoxWidth;
|
||||
private double cornerRadius;
|
||||
|
||||
public CompetitorInfoOverlay(MapWidget map, int zIndex, CompetitorDTO competitorDTO, RaceMapImageManager raceMapImageManager) {
|
||||
public SmallTransparentInfoOverlay(MapWidget map, int zIndex, String infoText, RaceMapImageManager raceMapImageManager) {
|
||||
super(map, zIndex);
|
||||
this.competitorDTO = competitorDTO;
|
||||
|
||||
this.infoText = infoText;
|
||||
canvasWidth = 20;
|
||||
canvasHeight = 45;
|
||||
infoBoxWidth = 20;
|
||||
@@ -51,18 +53,13 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
@Override
|
||||
protected void draw() {
|
||||
if (mapProjection != null && boatFix != null) {
|
||||
LatLng latLngPosition = LatLng.newInstance(boatFix.position.latDeg, boatFix.position.lngDeg);
|
||||
String infoText = competitorDTO.getSailID();
|
||||
if (infoText == null || infoText.isEmpty()) {
|
||||
infoText = competitorDTO.getName();
|
||||
}
|
||||
|
||||
if (mapProjection != null && position != null) {
|
||||
LatLng latLngPosition = LatLng.newInstance(position.latDeg, position.lngDeg);
|
||||
Context2d context2d = getCanvas().getContext2d();
|
||||
CssColor grayTransparentColor = CssColor.make("rgba(255,255,255,0.75)");
|
||||
|
||||
context2d.setFont("12px bold Verdana sans-serif");
|
||||
TextMetrics measureText = context2d.measureText(competitorDTO.getSailID());
|
||||
TextMetrics measureText = context2d.measureText(infoText);
|
||||
double textWidth = measureText.getWidth();
|
||||
|
||||
canvasWidth = (int) textWidth + 17;
|
||||
@@ -87,11 +84,11 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
context2d.beginPath();
|
||||
context2d.setFillStyle("black");
|
||||
context2d.fillText(competitorDTO.getSailID(), 8, 14);
|
||||
context2d.fillText(infoText, 8, 14);
|
||||
context2d.stroke();
|
||||
|
||||
Point boatPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
setCanvasPosition(boatPositionInPx.getX(), boatPositionInPx.getY() - canvasHeight);
|
||||
Point objectPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
setCanvasPosition(objectPositionInPx.getX(), objectPositionInPx.getY() - canvasHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,11 +107,15 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
context.fill();
|
||||
}
|
||||
|
||||
public GPSFixDTO getBoatFix() {
|
||||
return boatFix;
|
||||
public void setPosition(PositionDTO position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void setBoatFix(GPSFixDTO boatFix) {
|
||||
this.boatFix = boatFix;
|
||||
|
||||
/**
|
||||
* Updates the text to show and re-draws the canvas
|
||||
*/
|
||||
public void setInfoText(String infoText) {
|
||||
this.infoText = infoText;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
-1
@@ -168,7 +168,6 @@ public class LeaderboardEntryPoint extends AbstractEntryPoint {
|
||||
leaderboardSettings, preselectedRace, leaderboardGroupName, leaderboardName, this, stringMessages, userAgent,
|
||||
showRaceDetails, hideToolbar, autoExpandLastRaceColumn, showCharts, chartDetailType, showOverallLeaderboard);
|
||||
}
|
||||
leaderboardViewer.ensureDebugId("LeaderboardViewerWidget");
|
||||
contentScrollPanel.setWidget(leaderboardViewer);
|
||||
mainPanel.add(contentScrollPanel);
|
||||
}
|
||||
|
||||
+5
-11
@@ -1393,7 +1393,6 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
setRaceColumnSelectionToLastNStrategy(settings.getNumberOfLastRacesToShow());
|
||||
break;
|
||||
}
|
||||
|
||||
totalRankColumn = new TotalRankColumn();
|
||||
RACE_COLUMN_HEADER_STYLE = tableResources.cellTableStyle().cellTableRaceColumnHeader();
|
||||
LEG_COLUMN_HEADER_STYLE = tableResources.cellTableStyle().cellTableLegColumnHeader();
|
||||
@@ -1402,7 +1401,9 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
LEG_COLUMN_STYLE = tableResources.cellTableStyle().cellTableLegColumn();
|
||||
LEG_DETAIL_COLUMN_STYLE = tableResources.cellTableStyle().cellTableLegDetailColumn();
|
||||
TOTAL_COLUMN_STYLE = tableResources.cellTableStyle().cellTableTotalColumn();
|
||||
|
||||
leaderboardTable = new SortedCellTableWithStylableHeaders<LeaderboardRowDTO>(
|
||||
/* pageSize */10000, tableResources);
|
||||
getLeaderboardTable().setWidth("100%");
|
||||
leaderboardSelectionModel = new MultiSelectionModel<LeaderboardRowDTO>();
|
||||
leaderboardSelectionModel.addSelectionChangeHandler(new Handler() {
|
||||
@Override
|
||||
@@ -1415,12 +1416,6 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
updateLeaderboard(getLeaderboard());
|
||||
}
|
||||
});
|
||||
|
||||
this.leaderboardTable = new SortedCellTableWithStylableHeaders<LeaderboardRowDTO>(
|
||||
/* pageSize */10000, tableResources);
|
||||
this.leaderboardTable.ensureDebugId("LeaderboardTable");
|
||||
this.leaderboardTable.setWidth("100%");
|
||||
|
||||
if (userAgent.isMobile() == UserAgentDetails.PlatformTypes.MOBILE) {
|
||||
//Setting up the toggle selection
|
||||
leaderboardTable.addCellPreviewHandler(new ToggleSelectionCellPreviewHandler<LeaderboardRowDTO>());
|
||||
@@ -1429,7 +1424,6 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
} else {
|
||||
leaderboardTable.setSelectionModel(leaderboardSelectionModel);
|
||||
}
|
||||
|
||||
loadCompleteLeaderboard(getLeaderboardDisplayDate());
|
||||
|
||||
if (this.preSelectedRace == null) {
|
||||
@@ -1455,9 +1449,9 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
liveRaceLabel.setVisible(false);
|
||||
informationPanel.add(liveRaceLabel);
|
||||
|
||||
// the toolbar panel
|
||||
// the toolbar panel
|
||||
DockPanel toolbarPanel = new DockPanel();
|
||||
toolbarPanel.setStyleName(STYLE_LEADERBOARD_TOOLBAR);
|
||||
toolbarPanel.setStyleName(STYLE_LEADERBOARD_TOOLBAR);
|
||||
busyIndicator = new SimpleBusyIndicator(false, 0.8f);
|
||||
if (!isEmbedded) {
|
||||
toolbarPanel.add(informationPanel, DockPanel.WEST);
|
||||
|
||||
+161
-63
@@ -47,6 +47,7 @@ import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
@@ -146,6 +147,9 @@ import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.racelog.FlagPole;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.igtimiadapter.Account;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
|
||||
import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
@@ -175,6 +179,7 @@ import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
@@ -326,6 +331,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
private final MongoObjectFactory mongoObjectFactory;
|
||||
|
||||
private final SwissTimingAdapterPersistence swissTimingAdapterPersistence;
|
||||
|
||||
private final ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory> swissTimingAdapterTracker;
|
||||
|
||||
private final ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> tractracAdapterTracker;
|
||||
|
||||
private final ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory> igtimiAdapterTracker;
|
||||
|
||||
private final com.sap.sailing.domain.tractracadapter.persistence.MongoObjectFactory tractracMongoObjectFactory;
|
||||
|
||||
@@ -355,28 +366,29 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
* {@link #LEADERBOARD_DIFFERENCE_CACHE_SIZE}.
|
||||
*/
|
||||
private final LinkedHashMap<Pair<String, String>, IncrementalLeaderboardDTO> leaderboardDifferenceCacheByIdPair;
|
||||
private final TracTracAdapter tracTracAdapter;
|
||||
|
||||
private final SwissTimingAdapter swissTimingAdapter;
|
||||
|
||||
private final SwissTimingReplayService swissTimingReplayService;
|
||||
|
||||
private PolarDataService polarDataService;
|
||||
private final BundleContext context;
|
||||
|
||||
public SailingServiceImpl() {
|
||||
BundleContext context = Activator.getDefault();
|
||||
context = Activator.getDefault();
|
||||
racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context);
|
||||
replicationServiceTracker = createAndOpenReplicationServiceTracker(context);
|
||||
swissTimingAdapterTracker = createAndOpenSwissTimingAdapterTracker(context);
|
||||
tractracAdapterTracker = createAndOpenTracTracAdapterTracker(context);
|
||||
igtimiAdapterTracker = createAndOpenIgtimiTracker(context);
|
||||
baseDomainFactory = getService().getBaseDomainFactory();
|
||||
mongoObjectFactory = getService().getMongoObjectFactory();
|
||||
domainObjectFactory = getService().getDomainObjectFactory();
|
||||
tracTracAdapter = getTracTracAdapter(context);
|
||||
// TODO what about passing on the mongo/domain object factory to obtain an according SwissTimingAdapterPersistence instance similar to how the tractracDomainObjectFactory etc. are created below?
|
||||
swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
||||
swissTimingAdapter = getSwissTimingAdapter(context);
|
||||
swissTimingReplayService = getSwissTimingReplayService(context);
|
||||
scoreCorrectionProviderServiceTracker = createAndOpenScoreCorrectionProviderServiceTracker(context);
|
||||
tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE.createDomainObjectFactory(mongoObjectFactory.getDatabase(), tracTracAdapter.getTracTracDomainFactory());
|
||||
tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE
|
||||
.createDomainObjectFactory(mongoObjectFactory.getDatabase(), getTracTracAdapter()
|
||||
.getTracTracDomainFactory());
|
||||
tractracMongoObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.MongoObjectFactory.INSTANCE;
|
||||
swissTimingFactory = SwissTimingFactory.INSTANCE;
|
||||
countryCodeFactory = com.sap.sailing.domain.common.CountryCodeFactory.INSTANCE;
|
||||
@@ -406,15 +418,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
|
||||
protected SwissTimingReplayService getSwissTimingReplayService(BundleContext context) {
|
||||
return createAndOpenSwissTimingReplayServiceTracker(context).getService().createSwissTimingReplayService(swissTimingAdapter.getSwissTimingDomainFactory());
|
||||
return createAndOpenSwissTimingReplayServiceTracker(context).getService().createSwissTimingReplayService(getSwissTimingAdapter().getSwissTimingDomainFactory());
|
||||
}
|
||||
|
||||
protected SwissTimingAdapter getSwissTimingAdapter(BundleContext context) {
|
||||
return createAndOpenSwissTimingAdapterTracker(context).getService().getOrCreateSwissTimingAdapter(baseDomainFactory, swissTimingAdapterPersistence);
|
||||
protected SwissTimingAdapter getSwissTimingAdapter() {
|
||||
return swissTimingAdapterTracker.getService().getOrCreateSwissTimingAdapter(baseDomainFactory, swissTimingAdapterPersistence);
|
||||
}
|
||||
|
||||
protected TracTracAdapter getTracTracAdapter(BundleContext context) {
|
||||
return createAndOpenTracTracAdapterTracker(context).getService().getOrCreateTracTracAdapter(baseDomainFactory);
|
||||
protected TracTracAdapter getTracTracAdapter() {
|
||||
return tractracAdapterTracker.getService().getOrCreateTracTracAdapter(baseDomainFactory);
|
||||
}
|
||||
|
||||
protected IgtimiConnectionFactory getIgtimiConnectionFactory(BundleContext context) {
|
||||
return createAndOpenIgtimiTracker(context).getService();
|
||||
}
|
||||
|
||||
protected ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> createAndOpenTracTracAdapterTracker(BundleContext context) {
|
||||
@@ -424,6 +440,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory> createAndOpenIgtimiTracker(BundleContext context) {
|
||||
ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory> result = new ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory>(
|
||||
context, IgtimiConnectionFactory.class.getName(), null);
|
||||
result.open();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory> createAndOpenSwissTimingAdapterTracker(
|
||||
BundleContext context) {
|
||||
ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory> result = new ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory>(
|
||||
@@ -895,14 +918,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
}
|
||||
|
||||
private TracTracAdapter getTracTracAdapter() {
|
||||
return tracTracAdapter;
|
||||
}
|
||||
|
||||
private SwissTimingAdapter getSwissTimingAdapter() {
|
||||
return swissTimingAdapter;
|
||||
}
|
||||
|
||||
private SwissTimingReplayService getSwissTimingReplayService() {
|
||||
return swissTimingReplayService;
|
||||
}
|
||||
@@ -921,7 +936,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
|
||||
@Override
|
||||
public void storeTracTracConfiguration(String name, String jsonURL, String liveDataURI, String storedDataURI, String courseDesignUpdateURI, String tracTracUsername, String tracTracPassword) throws Exception {
|
||||
tractracMongoObjectFactory.storeTracTracConfiguration(tracTracAdapter.createTracTracConfiguration(name, jsonURL, liveDataURI, storedDataURI,
|
||||
tractracMongoObjectFactory.storeTracTracConfiguration(getTracTracAdapter().createTracTracConfiguration(name, jsonURL, liveDataURI, storedDataURI,
|
||||
courseDesignUpdateURI, tracTracUsername, tracTracPassword));
|
||||
}
|
||||
|
||||
@@ -1198,7 +1213,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
if (trackedRace != null) {
|
||||
TimePoint fromTimePoint = from == null ? trackedRace.getStartOfTracking() : new MillisecondsTimePoint(from);
|
||||
TimePoint toTimePoint = to == null ? trackedRace.getEndOfRace() : new MillisecondsTimePoint(to);
|
||||
if(fromTimePoint != null && toTimePoint != null) {
|
||||
if (fromTimePoint != null && toTimePoint != null) {
|
||||
int numberOfFixes = (int) ((toTimePoint.asMillis() - fromTimePoint.asMillis())/resolutionInMilliseconds);
|
||||
result = getAveragedWindInfo(fromTimePoint, resolutionInMilliseconds, numberOfFixes, windSourceTypeNames, trackedRace);
|
||||
}
|
||||
@@ -2133,7 +2148,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
List<SwissTimingRaceRecordDTO> result = new ArrayList<SwissTimingRaceRecordDTO>();
|
||||
for (com.sap.sailing.domain.swisstimingadapter.RaceRecord rr : getSwissTimingAdapter().getSwissTimingRaceRecords(hostname, port, canSendRequests)) {
|
||||
SwissTimingRaceRecordDTO swissTimingRaceRecordDTO = new SwissTimingRaceRecordDTO(rr.getRaceID(), rr.getDescription(), rr.getStartTime());
|
||||
BoatClass boatClass = swissTimingAdapter.getSwissTimingDomainFactory().getRaceTypeFromRaceID(rr.getRaceID()).getBoatClass();
|
||||
BoatClass boatClass = getSwissTimingAdapter().getSwissTimingDomainFactory().getRaceTypeFromRaceID(rr.getRaceID()).getBoatClass();
|
||||
swissTimingRaceRecordDTO.boatClass = boatClass != null ? boatClass.getName() : null;
|
||||
swissTimingRaceRecordDTO.discipline = rr.getRaceID().length() >= 3 ? rr.getRaceID().substring(2, 3) : null;
|
||||
swissTimingRaceRecordDTO.hasCourse = rr.hasCourse();
|
||||
@@ -2256,51 +2271,61 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
course.lockForRead(); // make sure the tracked leg survives this call even if a course update is pending
|
||||
try {
|
||||
TrackedLegOfCompetitor trackedLeg = trackedRace.getTrackedLeg(competitor, timePoint);
|
||||
if (trackedLeg != null) {
|
||||
switch (dataType) {
|
||||
case CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
|
||||
SpeedWithBearing speedOverGround = trackedLeg.getSpeedOverGround(timePoint);
|
||||
switch (dataType) {
|
||||
case CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
if (track != null) {
|
||||
SpeedWithBearing speedOverGround = track.getEstimatedSpeed(timePoint);
|
||||
result = (speedOverGround == null) ? null : speedOverGround.getKnots();
|
||||
break;
|
||||
case VELOCITY_MADE_GOOD_IN_KNOTS:
|
||||
}
|
||||
break;
|
||||
case VELOCITY_MADE_GOOD_IN_KNOTS:
|
||||
if (trackedLeg != null) {
|
||||
Speed velocityMadeGood = trackedLeg.getVelocityMadeGood(timePoint);
|
||||
result = (velocityMadeGood == null) ? null : velocityMadeGood.getKnots();
|
||||
break;
|
||||
case DISTANCE_TRAVELED:
|
||||
}
|
||||
break;
|
||||
case DISTANCE_TRAVELED:
|
||||
if (trackedLeg != null) {
|
||||
Distance distanceTraveled = trackedRace.getDistanceTraveled(competitor, timePoint);
|
||||
result = distanceTraveled == null ? null : distanceTraveled.getMeters();
|
||||
break;
|
||||
case GAP_TO_LEADER_IN_SECONDS:
|
||||
}
|
||||
break;
|
||||
case GAP_TO_LEADER_IN_SECONDS:
|
||||
if (trackedLeg != null) {
|
||||
result = trackedLeg.getGapToLeaderInSeconds(timePoint);
|
||||
break;
|
||||
case WINDWARD_DISTANCE_TO_OVERALL_LEADER:
|
||||
}
|
||||
break;
|
||||
case WINDWARD_DISTANCE_TO_OVERALL_LEADER:
|
||||
if (trackedLeg != null) {
|
||||
Distance distanceToLeader = trackedLeg.getWindwardDistanceToOverallLeader(timePoint);
|
||||
result = (distanceToLeader == null) ? null : distanceToLeader.getMeters();
|
||||
break;
|
||||
case RACE_RANK:
|
||||
result = (double) trackedLeg.getRank(timePoint);
|
||||
break;
|
||||
case REGATTA_RANK:
|
||||
if (leaderboardName == null || leaderboardName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
result = leaderboard == null ? null : (double) leaderboard.getTotalRankOfCompetitor(competitor, timePoint);
|
||||
break;
|
||||
case OVERALL_RANK:
|
||||
if (leaderboardGroupName == null || leaderboardGroupName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
LeaderboardGroup group = getService().getLeaderboardGroupByName(leaderboardGroupName);
|
||||
Leaderboard overall = group.getOverallLeaderboard();
|
||||
result = overall == null ? null : (double) overall.getTotalRankOfCompetitor(competitor, timePoint);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Theres currently no support for the enum value '"
|
||||
+ dataType + "' in this method.");
|
||||
}
|
||||
break;
|
||||
case RACE_RANK:
|
||||
if (trackedLeg != null) {
|
||||
result = (double) trackedLeg.getRank(timePoint);
|
||||
}
|
||||
break;
|
||||
case REGATTA_RANK:
|
||||
if (leaderboardName == null || leaderboardName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
result = leaderboard == null ? null : (double) leaderboard.getTotalRankOfCompetitor(competitor,
|
||||
timePoint);
|
||||
break;
|
||||
case OVERALL_RANK:
|
||||
if (leaderboardGroupName == null || leaderboardGroupName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
LeaderboardGroup group = getService().getLeaderboardGroupByName(leaderboardGroupName);
|
||||
Leaderboard overall = group.getOverallLeaderboard();
|
||||
result = overall == null ? null : (double) overall.getTotalRankOfCompetitor(competitor, timePoint);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Theres currently no support for the enum value '" + dataType
|
||||
+ "' in this method.");
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
@@ -2576,10 +2601,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedRace getTrackedRace(RegattaAndRaceIdentifier regattaNameAndRaceName) {
|
||||
public DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier regattaNameAndRaceName) {
|
||||
Regatta regatta = getService().getRegattaByName(regattaNameAndRaceName.getRegattaName());
|
||||
RaceDefinition race = getRaceByName(regatta, regattaNameAndRaceName.getRaceName());
|
||||
TrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getTrackedRace(race);
|
||||
DynamicTrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getTrackedRace(race);
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
@@ -2784,8 +2809,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
return getEventById(eventUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventDTO getEventById(Serializable id) {
|
||||
private EventDTO getEventById(UUID id) {
|
||||
EventDTO result = null;
|
||||
Event event = getService().getEvent(id);
|
||||
if (event != null) {
|
||||
@@ -3580,4 +3604,78 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
return new Pair<Date, Integer>(result.getA().asDate(), result.getB());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getAllIgtimiAccountEmailAddresses() {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (Account account : getIgtimiConnectionFactory().getAllAccounts()) {
|
||||
result.add(account.getUser().getEmail());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IgtimiConnectionFactory getIgtimiConnectionFactory() {
|
||||
return igtimiAdapterTracker.getService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIgtimiAuthorizationUrl() {
|
||||
return getIgtimiConnectionFactory().getAuthorizationUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authorizeAccessToIgtimiUser(String eMailAddress, String password) throws Exception {
|
||||
Account account = getIgtimiConnectionFactory().createAccountToAccessUserData(eMailAddress, password);
|
||||
return account != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIgtimiAccount(String eMailOfAccountToRemove) {
|
||||
getIgtimiConnectionFactory().removeAccount(eMailOfAccountToRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegattaAndRaceIdentifier, Integer> importWindFromIgtimi(List<RaceDTO> selectedRaces) throws IllegalStateException,
|
||||
ClientProtocolException, IOException, org.json.simple.parser.ParseException {
|
||||
final IgtimiConnectionFactory igtimiConnectionFactory = getIgtimiConnectionFactory();
|
||||
final Iterable<DynamicTrackedRace> trackedRaces;
|
||||
if (selectedRaces != null && !selectedRaces.isEmpty()) {
|
||||
List<DynamicTrackedRace> myTrackedRaces = new ArrayList<DynamicTrackedRace>();
|
||||
trackedRaces = myTrackedRaces;
|
||||
for (RaceDTO raceDTO : selectedRaces) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRace(raceDTO.getRaceIdentifier());
|
||||
myTrackedRaces.add(trackedRace);
|
||||
}
|
||||
} else {
|
||||
trackedRaces = getAllTrackedRaces();
|
||||
}
|
||||
Map<RegattaAndRaceIdentifier, Integer> numberOfWindFixesImportedPerRace = new HashMap<RegattaAndRaceIdentifier, Integer>();
|
||||
for (Account account : igtimiConnectionFactory.getAllAccounts()) {
|
||||
IgtimiConnection conn = igtimiConnectionFactory.connect(account);
|
||||
Map<TrackedRace, Integer> resultsForAccounts = conn.importWindIntoRace(trackedRaces);
|
||||
for (Entry<TrackedRace, Integer> resultForAccount : resultsForAccounts.entrySet()) {
|
||||
RegattaAndRaceIdentifier key = resultForAccount.getKey().getRaceIdentifier();
|
||||
Integer i = numberOfWindFixesImportedPerRace.get(key);
|
||||
if (i == null) {
|
||||
i = 0;
|
||||
}
|
||||
numberOfWindFixesImportedPerRace.put(key, i+resultForAccount.getValue());
|
||||
}
|
||||
}
|
||||
return numberOfWindFixesImportedPerRace;
|
||||
}
|
||||
|
||||
private Set<DynamicTrackedRace> getAllTrackedRaces() {
|
||||
Set<DynamicTrackedRace> result = new HashSet<DynamicTrackedRace>();
|
||||
Iterable<Regatta> allRegattas = getService().getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = getService().getTrackedRegatta(regatta);
|
||||
if (trackedRegatta != null) {
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
result.add((DynamicTrackedRace) trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-1
@@ -7,7 +7,6 @@
|
||||
<!-- Inherit the core Web Toolkit stuff. -->
|
||||
<inherits name='com.google.gwt.user.User'/>
|
||||
|
||||
<inherits name='com.google.gwt.debug.Debug'/>
|
||||
<!-- Inherit the default GWT style sheet. You can change -->
|
||||
<!-- the theme of your GWT application by uncommenting -->
|
||||
<!-- any one of the following lines. -->
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="lib/cglib-nodep-2.2.3.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<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>
|
||||
<?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.7"/>
|
||||
<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>
|
||||
@@ -9,5 +9,3 @@ Require-Bundle: org.junit4;bundle-version="4.8.2",
|
||||
org.openqa.selenium.osgi;bundle-version="2.34.0",
|
||||
com.sap.sailing.mongodb;bundle-version="1.0.0",
|
||||
com.mongodb.driver;bundle-version="2.6.2"
|
||||
Bundle-ClassPath: lib/cglib-nodep-2.2.3.jar,
|
||||
.
|
||||
@@ -3,5 +3,4 @@ source.. = src/,\
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
test-environment-configuration.xsd,\
|
||||
lib/cglib-nodep-2.2.3.jar
|
||||
test-environment-configuration.xsd
|
||||
Regular → Executable
File mode changed.
+1
-1
@@ -12,5 +12,5 @@
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.selenium.test"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dselenium.test.environment.configuration=local-test-environment.xml -Dgwt.codesvr=127.0.0.1:9997"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dselenium.test.environment.configuration=local-test-environment.xml -Dgwt.codesvr=gwt.codesvr=127.0.0.1:9997 -Dwebdriver.firefox.profile=Selenium"/>
|
||||
</launchConfiguration>
|
||||
+16
-16
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/com.sap.sailing.selenium.test"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=com.sap.sailing.selenium.test"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.selenium.test"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dselenium.test.environment.configuration=local-test-environment.xml -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dgwt.codesvr=127.0.0.1:9997 -Dwebdriver.firefox.profile=Selenium"/>
|
||||
</launchConfiguration>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/com.sap.sailing.selenium.test"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=com.sap.sailing.selenium.test"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.selenium.test"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dselenium.test.environment.configuration=local-test-environment.xml -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dgwt.codesvr=gwt.codesvr=127.0.0.1:9997 -Dwebdriver.firefox.profile=Selenium"/>
|
||||
</launchConfiguration>
|
||||
Binary file not shown.
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Configuration file for the test environment. This file is used for the configuration of the environment for the
|
||||
executions of the integration tests. For the execution in a local environment you should make a copy of this file,
|
||||
change it accordingly to your local setup (eg. browser(s) to use for the tests) and adjust the property
|
||||
"parameters.integration-tests" in your user specific settings.xml to point to your local copy of this file.
|
||||
-->
|
||||
<test-environment xmlns="http://www.sapsailing.com/test-environment"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.sapsailing.com/test-environment ./test-environment-configuration.xsd ">
|
||||
|
||||
<!--
|
||||
The context root (the server) against which the tests should be executed.
|
||||
-->
|
||||
<context-root>http://riccardo:riccardo@localhost:8889/</context-root>
|
||||
|
||||
<!--
|
||||
<screenshots-folder>file:///C:/Users/D049941/screenshots/</screenshots-folder>
|
||||
-->
|
||||
|
||||
<!--
|
||||
In this section necessary system properties for the different web drivers can be provided if needed. For more
|
||||
information about available properties see the following sides:
|
||||
|
||||
- http://code.google.com/p/selenium/wiki/ChromeDriver
|
||||
- http://code.google.com/p/selenium/wiki/FirefoxDriver
|
||||
- http://code.google.com/p/selenium/wiki/InternetExplorerDriver
|
||||
- http://code.google.com/p/selenium/wiki/OperaDriver
|
||||
- http://code.google.com/p/selenium/wiki/SafariDriver
|
||||
- http://code.google.com/p/selenium/wiki/RemoteWebDriverServer
|
||||
|
||||
NOTE: For the Chrome and the InternetExplorer driver an additional "server", which acts as a bridge between the
|
||||
browser and the driver, is needed.
|
||||
-->
|
||||
<system-properties>
|
||||
<system-property>
|
||||
<name>webdriver.chrome.driver</name>
|
||||
<value>C:\apps\ChromeSeleniumDriver\chromedriver.exe</value>
|
||||
</system-property>
|
||||
<!--
|
||||
<system-property>
|
||||
<name>webdriver.firefox.bin</name>
|
||||
<value>D:/Internet/Firefox/firefox.exe</value>
|
||||
</system-property>
|
||||
-->
|
||||
<system-property>
|
||||
<name>webdriver.firefox.profile</name>
|
||||
<value>Selenium</value>
|
||||
</system-property>
|
||||
</system-properties>
|
||||
|
||||
|
||||
<!--
|
||||
The driver definitions define all web drivers (browsers) which should be used for the execution of the tests. This
|
||||
means that each test will be executed once for each driver defined here. This allows to perform the tests with
|
||||
different browsers to validate the proper functionality of the application across different browsers.
|
||||
|
||||
The capabilities section can be used for fine tuning of the driver (e.g. version). For more informations see the
|
||||
pages mentioned above.
|
||||
-->
|
||||
<!-- -->
|
||||
<driver-definition class="org.openqa.selenium.firefox.FirefoxDriver">
|
||||
<!-- -->
|
||||
<!--
|
||||
<capabilities>
|
||||
<capability>
|
||||
<name>version</name>
|
||||
<value>14.0.0</value>
|
||||
</capability>
|
||||
</capabilities>
|
||||
-->
|
||||
<!-- -->
|
||||
</driver-definition>
|
||||
<!-- -->
|
||||
|
||||
<!--
|
||||
<driver-definition class="org.openqa.selenium.chrome.ChromeDriver" />
|
||||
-->
|
||||
</test-environment>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Configuration file for the test environment. This file is used for the configuration of the environment for the
|
||||
executions of the integration tests. For the execution in a local environment you should make a copy of this file,
|
||||
change it accordingly to your local setup (eg. browser(s) to use for the tests) and adjust the property
|
||||
"parameters.integration-tests" in your user specific settings.xml to point to your local copy of this file.
|
||||
-->
|
||||
<test-environment xmlns="http://www.sapsailing.com/test-environment"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.sapsailing.com/test-environment ./test-environment-configuration.xsd ">
|
||||
|
||||
<!--
|
||||
The context root (the server) against which the tests should be executed.
|
||||
-->
|
||||
<context-root>http://riccardo:riccardo@localhost:8085/</context-root>
|
||||
|
||||
<!--
|
||||
<screenshots-folder>file:///C:/Users/D049941/screenshots/</screenshots-folder>
|
||||
-->
|
||||
|
||||
<!--
|
||||
In this section necessary system properties for the different web drivers can be provided if needed. For more
|
||||
information about available properties see the following sides:
|
||||
|
||||
- http://code.google.com/p/selenium/wiki/ChromeDriver
|
||||
- http://code.google.com/p/selenium/wiki/FirefoxDriver
|
||||
- http://code.google.com/p/selenium/wiki/InternetExplorerDriver
|
||||
- http://code.google.com/p/selenium/wiki/OperaDriver
|
||||
- http://code.google.com/p/selenium/wiki/SafariDriver
|
||||
- http://code.google.com/p/selenium/wiki/RemoteWebDriverServer
|
||||
|
||||
NOTE: For the Chrome and the InternetExplorer driver an additional "server", which acts as a bridge between the
|
||||
browser and the driver, is needed.
|
||||
-->
|
||||
<system-properties>
|
||||
<system-property>
|
||||
<name>webdriver.chrome.driver</name>
|
||||
<value>C:\apps\ChromeSeleniumDriver\chromedriver.exe</value>
|
||||
</system-property>
|
||||
|
||||
<system-property>
|
||||
<name>webdriver.firefox.bin</name>
|
||||
<value>D:/Internet/Firefox/firefox.exe</value>
|
||||
</system-property>
|
||||
|
||||
<system-property>
|
||||
<name>webdriver.firefox.profile</name>
|
||||
<value>Selenium</value>
|
||||
</system-property>
|
||||
</system-properties>
|
||||
|
||||
|
||||
<!--
|
||||
The driver definitions define all web drivers (browsers) which should be used for the execution of the tests. This
|
||||
means that each test will be executed once for each driver defined here. This allows to perform the tests with
|
||||
different browsers to validate the proper functionality of the application across different browsers.
|
||||
|
||||
The capabilities section can be used for fine tuning of the driver (e.g. version). For more informations see the
|
||||
pages mentioned above.
|
||||
-->
|
||||
<!-- -->
|
||||
<driver-definition class="org.openqa.selenium.firefox.FirefoxDriver">
|
||||
<!-- -->
|
||||
<!--
|
||||
<capabilities>
|
||||
<capability>
|
||||
<name>version</name>
|
||||
<value>14.0.0</value>
|
||||
</capability>
|
||||
</capabilities>
|
||||
-->
|
||||
<!-- -->
|
||||
</driver-definition>
|
||||
<!-- -->
|
||||
|
||||
<!--
|
||||
<driver-definition class="org.openqa.selenium.chrome.ChromeDriver" />
|
||||
-->
|
||||
</test-environment>
|
||||
Regular → Executable
+6
-10
@@ -13,7 +13,7 @@
|
||||
<!--
|
||||
The context root (the server) against which the tests should be executed.
|
||||
-->
|
||||
<context-root>http://riccardo:riccardo@localhost:8889/</context-root>
|
||||
<context-root>http://riccardo:riccardo@localhost:8888/</context-root>
|
||||
|
||||
<!--
|
||||
<screenshots-folder>file:///C:/Users/D049941/screenshots/</screenshots-folder>
|
||||
@@ -41,13 +41,9 @@
|
||||
<!--
|
||||
<system-property>
|
||||
<name>webdriver.firefox.bin</name>
|
||||
<value>D:/Internet/Firefox/firefox.exe</value>
|
||||
<value>c:/Program Files (x86)/Mozilla Firefox/firefox.exe</value>
|
||||
</system-property>
|
||||
-->
|
||||
<system-property>
|
||||
<name>webdriver.firefox.profile</name>
|
||||
<value>Selenium</value>
|
||||
</system-property>
|
||||
</system-properties>
|
||||
|
||||
|
||||
@@ -60,8 +56,8 @@
|
||||
pages mentioned above.
|
||||
-->
|
||||
<!-- -->
|
||||
<driver-definition class="org.openqa.selenium.firefox.FirefoxDriver">
|
||||
<!-- -->
|
||||
<driver-definition class="org.openqa.selenium.firefox.FirefoxDriver">
|
||||
<!-- -->
|
||||
<!--
|
||||
<capabilities>
|
||||
<capability>
|
||||
@@ -74,7 +70,7 @@
|
||||
</driver-definition>
|
||||
<!-- -->
|
||||
|
||||
<!--
|
||||
<!--
|
||||
<driver-definition class="org.openqa.selenium.chrome.ChromeDriver" />
|
||||
-->
|
||||
-->
|
||||
</test-environment>
|
||||
@@ -73,13 +73,6 @@
|
||||
</dependencies>
|
||||
|
||||
<bundleStartLevel>
|
||||
<!-- This bundle should only be deployed in a test environment! -->
|
||||
<bundle>
|
||||
<id>com.sap.sailing.server.gatway.test.support</id>
|
||||
<level>5</level>
|
||||
<autoStart>true</autoStart>
|
||||
</bundle>
|
||||
|
||||
<bundle>
|
||||
<id>com.sap.sailing.ess40.resultimport</id>
|
||||
<level>3</level>
|
||||
@@ -132,6 +125,11 @@
|
||||
<level>4</level>
|
||||
<autoStart>true</autoStart>
|
||||
</bundle>
|
||||
<bundle>
|
||||
<id>com.sap.sailing.domain.igtimiadapter</id>
|
||||
<level>4</level>
|
||||
<autoStart>true</autoStart>
|
||||
</bundle>
|
||||
<bundle>
|
||||
<id>com.sap.sailing.xcelsiusadapter</id>
|
||||
<level>4</level>
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class BySeleniumId extends By {
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* <p>Creates a new location mechanism which searches for an element or a list of elements with the given
|
||||
* <p>Creates a new location mechanism which search for an element or a list of elements with the given
|
||||
* identifier.</p>
|
||||
*
|
||||
* @param id
|
||||
|
||||
+3
-3
@@ -6,10 +6,10 @@ import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* <p>Models a condition that might reasonably be expected to eventually evaluate to something that is neither
|
||||
* {@code null} nor {@code false} using a search context. An example would be that an element is visible.</p>
|
||||
* {@code null} nor {@code false} using a search context.</p>
|
||||
*
|
||||
* <p>Note that it is expected that conditions are idempotent. They will be called in a loop by the WebDriverWait
|
||||
* and any modification of the state of the application under test may have unexpected side-effects.</p>
|
||||
* <p>Note that it is expected that conditions are idempotent. They will be called in a loop by the and any modification
|
||||
* of the state of the application under test may have unexpected side-effects.</p>
|
||||
*
|
||||
* @param <T>
|
||||
* The return type
|
||||
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
package com.sap.sailing.selenium.core;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import org.openqa.selenium.internal.Locatable;
|
||||
import org.openqa.selenium.internal.WrapsElement;
|
||||
|
||||
import org.openqa.selenium.support.pagefactory.ElementLocator;
|
||||
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
|
||||
import org.openqa.selenium.support.pagefactory.FieldDecorator;
|
||||
|
||||
import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler;
|
||||
import org.openqa.selenium.support.pagefactory.internal.LocatingElementListHandler;
|
||||
|
||||
public class SeleniumFieldDecorator implements FieldDecorator {
|
||||
private ElementLocatorFactory factory;
|
||||
|
||||
public SeleniumFieldDecorator(ElementLocatorFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decorate(ClassLoader loader, Field field) {
|
||||
ElementLocator locator = this.factory.createLocator(field);
|
||||
|
||||
if (locator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isDecoratableField(field)) {
|
||||
return proxyForElementLocator(loader, locator);
|
||||
}
|
||||
|
||||
if (isDecoratableList(field)) {
|
||||
return proxyForElementsLocator(loader, locator);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isDecoratableField(Field field) {
|
||||
return WebElement.class.isAssignableFrom(field.getType());
|
||||
}
|
||||
|
||||
private boolean isDecoratableList(Field field) {
|
||||
if (!List.class.isAssignableFrom(field.getType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Type erasure in Java isn't complete. Attempt to discover the generic type of the list.
|
||||
Type genericType = field.getGenericType();
|
||||
if (!(genericType instanceof ParameterizedType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type listType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
|
||||
|
||||
if (!WebElement.class.equals(listType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Object proxyForElementLocator(ClassLoader loader, ElementLocator locator) {
|
||||
InvocationHandler handler = new LocatingElementHandler(locator);
|
||||
Object proxy = Proxy.newProxyInstance( loader, new Class[] {WebElement.class, WrapsElement.class, Locatable.class}, handler);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private Object proxyForElementsLocator(ClassLoader loader, ElementLocator locator) {
|
||||
InvocationHandler handler = new LocatingElementListHandler(locator);
|
||||
Object proxy = Proxy.newProxyInstance(loader, new Class[] {List.class}, handler);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
-9
@@ -21,15 +21,6 @@ public interface TestEnvironment {
|
||||
*/
|
||||
public WebDriver getWebDriver();
|
||||
|
||||
/**
|
||||
* <p>Returns the window manager for the used web driver, which can be used to open new windows and switching
|
||||
* between multiple windows.</p>
|
||||
*
|
||||
* @return
|
||||
* The window manager for the used web driver.
|
||||
*/
|
||||
public WindowManager getWindowManager();
|
||||
|
||||
/**
|
||||
* <p>Returns the context root (base URL) against the tests should be executed. The context root identifies the
|
||||
* web application and usually consists of a protocol definition, the host and a path.</p>
|
||||
|
||||
+78
-12
@@ -2,16 +2,36 @@ package com.sap.sailing.selenium.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebDriver.TargetLocator;
|
||||
import org.openqa.selenium.WebDriverException;
|
||||
|
||||
public class WebDriverWindow {
|
||||
|
||||
private static int instanceCount = 0;
|
||||
|
||||
private static final String JAVA_SCRIPT = "var anchorTag = document.createElement('a');" +
|
||||
"anchorTag.setAttribute('id', '%s');" +
|
||||
"anchorTag.setAttribute('href', '%s');" +
|
||||
"anchorTag.setAttribute('target', '_blank');" +
|
||||
"anchorTag.setAttribute('style', 'display:block;');" +
|
||||
"anchorTag.appendChild(document.createTextNode('nwh'));" +
|
||||
"document.getElementsByTagName('body')[0].appendChild(anchorTag);";
|
||||
|
||||
private static String createUniqueName() {
|
||||
return "WebDriverWindow_" + instanceCount++;
|
||||
}
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
private String name;
|
||||
|
||||
private String handle;
|
||||
|
||||
private String parent;
|
||||
|
||||
/**
|
||||
* Creates a new window for given web driver
|
||||
*
|
||||
@@ -20,34 +40,80 @@ public class WebDriverWindow {
|
||||
* @param url
|
||||
* Initial URL to load
|
||||
*/
|
||||
protected WebDriverWindow(WebDriver driver, String handle) {
|
||||
public WebDriverWindow(WebDriver driver, String url) {
|
||||
this.driver = driver;
|
||||
this.handle = handle;
|
||||
this.name = createUniqueName();
|
||||
|
||||
createWindow(url);
|
||||
// Switch to that window and load the url to wait
|
||||
switchToWindow();//.get(url);
|
||||
}
|
||||
|
||||
|
||||
public String getWindowHandle() {
|
||||
return this.handle;
|
||||
}
|
||||
|
||||
public String getParentHandle() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
WebDriver driver = switchToWindow();
|
||||
driver.close();
|
||||
|
||||
this.handle = null;
|
||||
switchToWindow().close();
|
||||
this.handle = "";
|
||||
// Switch back to the parent window
|
||||
this.driver.switchTo().window(this.parent);
|
||||
}
|
||||
|
||||
public WebDriver switchToWindow() {
|
||||
checkForClosed();
|
||||
|
||||
TargetLocator locator = this.driver.switchTo();
|
||||
return switchTo(this.handle);
|
||||
}
|
||||
|
||||
public WebDriver switchToParent() {
|
||||
checkForClosed();
|
||||
|
||||
return locator.window(this.handle);
|
||||
return switchTo(this.parent);
|
||||
}
|
||||
|
||||
private void createWindow(String url) {
|
||||
// Record old handles
|
||||
Set<String> oldHandles = this.driver.getWindowHandles();
|
||||
this.parent = this.driver.getWindowHandle();
|
||||
|
||||
// Inject an anchor element
|
||||
injectAnchorTag(this.name, url);
|
||||
|
||||
// Click on the anchor element
|
||||
this.driver.findElement(By.id(this.name)).click();
|
||||
|
||||
this.handle = getNewHandle(oldHandles);
|
||||
}
|
||||
|
||||
private String getNewHandle(Set<String> oldHandles) {
|
||||
Set<String> newHandles = this.driver.getWindowHandles();
|
||||
newHandles.removeAll(oldHandles);
|
||||
|
||||
// Find the new window
|
||||
for(String handle : newHandles)
|
||||
return handle;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkForClosed() {
|
||||
Set<String> handles = this.driver.getWindowHandles();
|
||||
if(this.handle == null || this.handle.equals(""))
|
||||
throw new WebDriverException("Web Window closed or not initialized");
|
||||
}
|
||||
|
||||
private void injectAnchorTag(String id, String url) {
|
||||
JavascriptExecutor executor = (JavascriptExecutor) this.driver;
|
||||
executor.executeScript(String.format(JAVA_SCRIPT, id, url));
|
||||
}
|
||||
|
||||
private WebDriver switchTo(String handle) {
|
||||
TargetLocator locator = this.driver.switchTo();
|
||||
|
||||
if(!handles.contains(this.handle))
|
||||
throw new WebDriverException("Window closed or not initialized"); //$NON-NLS-1$
|
||||
return locator.window(handle);
|
||||
}
|
||||
}
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
package com.sap.sailing.selenium.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebDriver.TargetLocator;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @author
|
||||
* Riccardo Nimser (D049941)
|
||||
*/
|
||||
public class WindowManager {
|
||||
private static final String JAVA_SCRIPT = "window.open('%s', '_blank')";
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @param driver
|
||||
*
|
||||
*/
|
||||
public WindowManager(WebDriver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public void switchTo(String url) {
|
||||
WebDriverWindow window = findWindow(url);
|
||||
|
||||
if(window == null)
|
||||
throw new RuntimeException("Window not found");
|
||||
|
||||
window.switchToWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns a handle to the window witch is currently active.</p>
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public WebDriverWindow getCurrentWindow() {
|
||||
return new WebDriverWindow(this.driver, this.driver.getWindowHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>Note: If no window is found with the specified URL, </p>
|
||||
*
|
||||
* @param url
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public WebDriverWindow findWindow(String url) {
|
||||
if(url == null)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
TargetLocator locator = this.driver.switchTo();
|
||||
|
||||
for(String handle : this.driver.getWindowHandles()) {
|
||||
locator.window(handle);
|
||||
|
||||
if(url.equals(this.driver.getCurrentUrl()))
|
||||
return new WebDriverWindow(this.driver, handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public WebDriverWindow openNewWindow() {
|
||||
return openNewWindow("");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public WebDriverWindow openNewWindow(String url) {
|
||||
return new WebDriverWindow(this.driver, createWindow(url));
|
||||
}
|
||||
|
||||
private String createWindow(String url) {
|
||||
// Record old handles
|
||||
Set<String> oldHandles = this.driver.getWindowHandles();
|
||||
|
||||
executeScript(url != null ? url : "");
|
||||
|
||||
return getNewHandle(oldHandles);
|
||||
}
|
||||
|
||||
private void executeScript(String url) {
|
||||
JavascriptExecutor executor = (JavascriptExecutor) this.driver;
|
||||
executor.executeScript(String.format(JAVA_SCRIPT, url));
|
||||
}
|
||||
|
||||
private String getNewHandle(Set<String> oldHandles) {
|
||||
Set<String> newHandles = this.driver.getWindowHandles();
|
||||
newHandles.removeAll(oldHandles);
|
||||
|
||||
// Find the new window
|
||||
for(String handle : newHandles)
|
||||
return handle;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-9
@@ -5,7 +5,6 @@ import java.net.URL;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import com.sap.sailing.selenium.core.TestEnvironment;
|
||||
import com.sap.sailing.selenium.core.WindowManager;
|
||||
|
||||
/**
|
||||
* <p>Default implementation of the test environment.</p>
|
||||
@@ -15,7 +14,6 @@ import com.sap.sailing.selenium.core.WindowManager;
|
||||
*/
|
||||
public class TestEnvironmentImpl implements TestEnvironment {
|
||||
private WebDriver driver;
|
||||
private WindowManager manager;
|
||||
private String root;
|
||||
private URL screenshots;
|
||||
|
||||
@@ -33,8 +31,6 @@ public class TestEnvironmentImpl implements TestEnvironment {
|
||||
this.driver = driver;
|
||||
this.root = root;
|
||||
this.screenshots = screenshots;
|
||||
|
||||
this.manager = new WindowManager(driver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,11 +38,6 @@ public class TestEnvironmentImpl implements TestEnvironment {
|
||||
return this.driver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowManager getWindowManager() {
|
||||
return this.manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextRoot() {
|
||||
return this.root;
|
||||
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole;
|
||||
|
||||
import org.openqa.selenium.Alert;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoAlertPresentException;
|
||||
import org.openqa.selenium.SearchContext;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebDriver.TargetLocator;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.ui.FluentWait;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.sap.sailing.selenium.pages.PageObject;
|
||||
|
||||
public class Actions {
|
||||
private static final String ACTION_XPATH = ".//descendant::div[@name='%s']/img";
|
||||
|
||||
public static final String EDIT_ACTION = "ACTION_EDIT";
|
||||
|
||||
public static final String REMOVE_ACTION = "ACTION_REMOVE";
|
||||
|
||||
public static final String EDIT_SCORES_ACTION = "ACTION_EDIT_SCORES";
|
||||
|
||||
public static final String CONFIGURE_URL_ACTION = "ACTION_CONFIGURE_URL";
|
||||
|
||||
public static final String UNLINK_RACE_ACTION = "ACTION_UNLINK";
|
||||
|
||||
public static final String REFRESH_RACE_ACTION = "ACTION_REFRESH_RACE";
|
||||
|
||||
public static WebElement findEditAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, EDIT_ACTION)));
|
||||
}
|
||||
|
||||
public static WebElement findRemoveAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, REMOVE_ACTION)));
|
||||
}
|
||||
|
||||
public static WebElement findEditScoresAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, EDIT_SCORES_ACTION)));
|
||||
}
|
||||
|
||||
public static WebElement findConfigureUrlAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, CONFIGURE_URL_ACTION)));
|
||||
}
|
||||
|
||||
public static WebElement findUnlinkRaceAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, UNLINK_RACE_ACTION)));
|
||||
}
|
||||
|
||||
public static WebElement findRefreshAction(SearchContext context) {
|
||||
return context.findElement(By.xpath(String.format(ACTION_XPATH, REFRESH_RACE_ACTION)));
|
||||
}
|
||||
|
||||
public static void acceptAlert(WebDriver driver) {
|
||||
Alert alert = getAlert(driver);
|
||||
alert.accept();
|
||||
}
|
||||
|
||||
public static void dismissAlert(WebDriver driver) {
|
||||
Alert alert = getAlert(driver);
|
||||
alert.dismiss();
|
||||
}
|
||||
|
||||
public static Alert getAlert(WebDriver driver) {
|
||||
FluentWait<WebDriver> wait = PageObject.createFluentWait(driver, NoAlertPresentException.class);
|
||||
|
||||
Alert alert = wait.until(new Function<WebDriver, Alert>() {
|
||||
@Override
|
||||
public Alert apply(WebDriver driver) {
|
||||
TargetLocator locator = driver.switchTo();
|
||||
|
||||
return locator.alert();
|
||||
}
|
||||
});
|
||||
|
||||
return alert;
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.common.DataEntryDialog;
|
||||
|
||||
public class FlexibleLeaderboardCreateDialog extends DataEntryDialog {
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardNameField")
|
||||
private WebElement nameField;
|
||||
|
||||
public FlexibleLeaderboardCreateDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.nameField.clear();
|
||||
this.nameField.sendKeys(name);
|
||||
}
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.Actions;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaList.RegattaDescriptor;
|
||||
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntry;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTable;
|
||||
|
||||
public class LeaderboardConfigurationPanel extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "CreateFlexibleLeaderboardButton")
|
||||
private WebElement createFlexibleLeaderboardButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "CreateRegattaLeaderboardButton")
|
||||
private WebElement createRegattaLeaderboardButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "AvailableLeaderboardsTable")
|
||||
private WebElement availableLeaderboardsTable;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardDetails")
|
||||
private WebElement leaderboardDetails;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackedRacesList")
|
||||
private WebElement trackedRacesList;
|
||||
|
||||
public LeaderboardConfigurationPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardCreateDialog startCreatingFlexibleLeaderboard() {
|
||||
this.createFlexibleLeaderboardButton.click();
|
||||
// Wait, since we trigger an AJAX-request to get the available events
|
||||
waitForAjaxRequests();
|
||||
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "FlexibleLeaderboardCreateDialog");
|
||||
|
||||
return new FlexibleLeaderboardCreateDialog(this.driver, dialog);
|
||||
}
|
||||
|
||||
// TODO: Extend with display name, scoring system, event, course area and discars
|
||||
public void createFlexibleLeaderboard(String name) {
|
||||
FlexibleLeaderboardCreateDialog dialog = startCreatingFlexibleLeaderboard();
|
||||
dialog.setName(name);
|
||||
dialog.pressOk();
|
||||
}
|
||||
|
||||
public RegattaLeaderboardCreateDialog startCreatingRegattaLeaderboard() {
|
||||
this.createRegattaLeaderboardButton.click();
|
||||
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "RegattaLeaderboardCreateDialog");
|
||||
|
||||
return new RegattaLeaderboardCreateDialog(this.driver, dialog);
|
||||
}
|
||||
|
||||
public void createRegattaLeaderboard(RegattaDescriptor regatta) {
|
||||
RegattaLeaderboardCreateDialog dialog = startCreatingRegattaLeaderboard();
|
||||
dialog.selectRegatta(regatta);
|
||||
dialog.pressOk();
|
||||
}
|
||||
|
||||
public void deleteLeaderboard(String leaderboard) {
|
||||
CellTable<DataEntry> table = getLeaderboardTable();
|
||||
List<DataEntry> entries = table.getEntries();
|
||||
|
||||
for(DataEntry entry : entries) {
|
||||
String name = entry.getColumnContent(0);
|
||||
|
||||
if(!leaderboard.equals(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WebElement removeAction = Actions.findRemoveAction(entry.getWebElement());
|
||||
removeAction.click();
|
||||
|
||||
Actions.acceptAlert(this.driver);
|
||||
|
||||
waitForAjaxRequests();
|
||||
}
|
||||
}
|
||||
|
||||
public String getLeaderboardURL(String leaderboard) {
|
||||
CellTable<DataEntry> table = getLeaderboardTable();
|
||||
List<DataEntry> entries = table.getEntries();
|
||||
|
||||
for(DataEntry entry : entries) {
|
||||
WebElement name = entry.getWebElement().findElement(By.xpath(".//td/div/a"));
|
||||
|
||||
if(!leaderboard.equals(name.getText()))
|
||||
continue;
|
||||
|
||||
return name.getAttribute("href");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getAvailableLeaderboards() {
|
||||
List<String> leaderboards = new ArrayList<>();
|
||||
|
||||
CellTable<DataEntry> table = getLeaderboardTable();
|
||||
List<DataEntry> entries = table.getEntries();
|
||||
|
||||
for(DataEntry entry : entries) {
|
||||
leaderboards.add(entry.getColumnContent(0));
|
||||
}
|
||||
|
||||
return leaderboards;
|
||||
}
|
||||
|
||||
public LeaderboardDetails getLeaderboardDetails(String leaderboard) {
|
||||
CellTable<DataEntry> table = getLeaderboardTable();
|
||||
List<DataEntry> entries = table.getEntries();
|
||||
|
||||
for(DataEntry entry : entries) {
|
||||
String name = entry.getColumnContent(0);
|
||||
|
||||
if(leaderboard.equals(name)) {
|
||||
entry.select();
|
||||
|
||||
return new LeaderboardDetails(this.driver, this.leaderboardDetails);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CellTable<DataEntry> getLeaderboardTable() {
|
||||
return new GenericCellTable<>(this.driver, this.availableLeaderboardsTable, DataEntry.class);
|
||||
}
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.openqa.selenium.By.ByXPath;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.Actions;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesList.TrackedRaceDescriptor;
|
||||
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntry;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTable;
|
||||
|
||||
public class LeaderboardDetails extends PageArea {
|
||||
public static class RaceDescriptor {
|
||||
private final String name;
|
||||
private final String fleet;
|
||||
private final boolean medalRace;
|
||||
private final boolean linked;
|
||||
private final double factor;
|
||||
|
||||
public RaceDescriptor(String name, String fleet, boolean medalRace, boolean linked, double factor) {
|
||||
this.name = name;
|
||||
this.fleet = fleet;
|
||||
this.medalRace = medalRace;
|
||||
this.linked = linked;
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getFleet() {
|
||||
return this.fleet;
|
||||
}
|
||||
|
||||
public boolean isMedalRace() {
|
||||
return this.medalRace;
|
||||
}
|
||||
|
||||
public boolean isLinked() {
|
||||
return this.linked;
|
||||
}
|
||||
|
||||
public double getFactor() {
|
||||
return this.factor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name, this.fleet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object)
|
||||
return true;
|
||||
|
||||
if (object == null)
|
||||
return false;
|
||||
|
||||
if (getClass() != object.getClass())
|
||||
return false;
|
||||
|
||||
RaceDescriptor other = (RaceDescriptor) object;
|
||||
|
||||
if(!Objects.equals(this.name, other.name))
|
||||
return false;
|
||||
|
||||
if(!Objects.equals(this.fleet, other.fleet))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RacesTable")
|
||||
private WebElement racesTable;
|
||||
|
||||
@FindBy(how = ByXPath.class, using = "./../..//*[@selenium-id='TrackedRacesPanel']")
|
||||
private WebElement trackedRacesPanel;
|
||||
|
||||
public LeaderboardDetails(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public List<RaceDescriptor> getRaces() {
|
||||
List<RaceDescriptor> result = new ArrayList<>();
|
||||
|
||||
CellTable<DataEntry> racesTable = getRacesTable();
|
||||
|
||||
for(DataEntry entry : racesTable.getEntries()) {
|
||||
String name = entry.getColumnContent(0);
|
||||
String fleet = entry.getColumnContent(1);
|
||||
//String medalRace = entry.getColumnContent(2);
|
||||
//String linked = entry.getColumnContent(3);
|
||||
//String factor = entry.getColumnContent(4);
|
||||
|
||||
result.add(new RaceDescriptor(name, fleet, false, false, 0.0));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public RaceEditDialog editRace(RaceDescriptor race) {
|
||||
//
|
||||
// WebElement action = Actions.findEditAction(findRace(race));
|
||||
//
|
||||
// action.click();
|
||||
// }
|
||||
|
||||
public void unlinkRace(RaceDescriptor race) {
|
||||
DataEntry entry = findRace(race);
|
||||
|
||||
if(entry != null) {
|
||||
WebElement action = Actions.findUnlinkRaceAction(entry.getWebElement());
|
||||
|
||||
action.click();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshRaceLog(RaceDescriptor race) {
|
||||
DataEntry entry = findRace(race);
|
||||
|
||||
if(entry != null) {
|
||||
WebElement action = Actions.findRefreshAction(entry.getWebElement());
|
||||
|
||||
action.click();
|
||||
|
||||
// QUESTION [D049941]: What else can happen?
|
||||
Actions.acceptAlert(this.driver);
|
||||
}
|
||||
}
|
||||
|
||||
public void linkRace(RaceDescriptor race, TrackedRaceDescriptor tracking) {
|
||||
DataEntry raceRow = findRace(race);
|
||||
DataEntry trackingRow = findTracking(tracking);
|
||||
|
||||
if(raceRow == null || trackingRow == null) {
|
||||
}
|
||||
|
||||
raceRow.select();
|
||||
trackingRow.select();
|
||||
}
|
||||
|
||||
private DataEntry findRace(RaceDescriptor race) {
|
||||
CellTable<DataEntry> racesTable = getRacesTable();
|
||||
|
||||
for(DataEntry entry : racesTable.getEntries()) {
|
||||
String name = entry.getColumnContent(0);
|
||||
String fleet = entry.getColumnContent(1);
|
||||
//String medalRace = entry.getColumnContent(2);
|
||||
//String linked = entry.getColumnContent(3);
|
||||
//String factor = entry.getColumnContent(4);
|
||||
|
||||
RaceDescriptor descriptor = new RaceDescriptor(name, fleet, false, false, 0.0);
|
||||
|
||||
if(descriptor.equals(race))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataEntry findTracking(TrackedRaceDescriptor tracking) {
|
||||
CellTable<DataEntry> trackingTable = getTrackedRacesTable();
|
||||
|
||||
for(DataEntry entry : trackingTable.getEntries()) {
|
||||
String regatta = entry.getColumnContent(0);
|
||||
String boatClass = entry.getColumnContent(1);
|
||||
String raceName = entry.getColumnContent(2);
|
||||
|
||||
TrackedRaceDescriptor descriptor = new TrackedRaceDescriptor(regatta, boatClass, raceName);
|
||||
|
||||
if(descriptor.equals(tracking))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CellTable<DataEntry> getRacesTable() {
|
||||
return new GenericCellTable<>(this.driver, this.racesTable, DataEntry.class);
|
||||
}
|
||||
|
||||
private CellTable<DataEntry> getTrackedRacesTable() {
|
||||
return new GenericCellTable<>(this.driver, findElementBySeleniumId(this.trackedRacesPanel, "TrackedRacesTable"), DataEntry.class);
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import static com.sap.sailing.selenium.pages.gwt.query.Alias.$;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.Actions;
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntry;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.query.Alias;
|
||||
import com.sap.sailing.selenium.pages.gwt.query.TableQuery;
|
||||
|
||||
public class LeaderboardGroupConfigurationPanel extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "CreateLeaderboardGroupButton")
|
||||
private WebElement createLeaderboardGroupButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardGroupsTable")
|
||||
private WebElement leaderboardGroupsTable;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardsCaptionPanel")
|
||||
private WebElement leaderboardsCaptionPanel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardsTable")
|
||||
private WebElement leaderboardsTable;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RefreshLeaderboardsButton")
|
||||
private WebElement refreshLeaderboardsButton;
|
||||
|
||||
public LeaderboardGroupConfigurationPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public LeaderboardGroupCreateDialog startCreatingLeaderboardGroup() {
|
||||
this.createLeaderboardGroupButton.click();
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "LeaderboardGroupCreateDialog");
|
||||
return new LeaderboardGroupCreateDialog(this.driver, dialog);
|
||||
}
|
||||
|
||||
public void createLeaderboardGroup(String name, String description) {
|
||||
LeaderboardGroupCreateDialog dialog = startCreatingLeaderboardGroup();
|
||||
dialog.setName(name);
|
||||
dialog.setDescription(description);
|
||||
dialog.pressOk();
|
||||
}
|
||||
|
||||
public CellTable<DataEntry> getLeaderboardGroupsTable() {
|
||||
return new GenericCellTable<DataEntry>(driver, leaderboardGroupsTable, DataEntry.class);
|
||||
}
|
||||
|
||||
public void deleteLeaderboardGroup(String name) {
|
||||
CellTable<DataEntry> table = getLeaderboardGroupsTable();
|
||||
final DataEntry alias = Alias.alias(DataEntry.class);
|
||||
TableQuery<DataEntry> query = new TableQuery<>();
|
||||
query.from(table)
|
||||
.where(
|
||||
$(alias.getColumnContent("Name")).eq(name)
|
||||
);
|
||||
DataEntry result = query.firstResult();
|
||||
if (result != null) {
|
||||
Actions.findRemoveAction(result.getWebElement()).click();
|
||||
Actions.acceptAlert(this.driver);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshLeaderboards() {
|
||||
refreshLeaderboardsButton.click();
|
||||
|
||||
}
|
||||
|
||||
public CellTable<DataEntry> getLeaderboardsTable() {
|
||||
return new GenericCellTable<DataEntry>(driver, leaderboardsTable, DataEntry.class);
|
||||
}
|
||||
|
||||
public DataEntry findLeaderboardEntry(String name) {
|
||||
CellTable<DataEntry> table = getLeaderboardsTable();
|
||||
final DataEntry alias = Alias.alias(DataEntry.class);
|
||||
TableQuery<DataEntry> query = new TableQuery<>();
|
||||
query.from(table).where($(alias.getColumnContent("Leaderboard Name")).eq(name));
|
||||
return query.firstResult();
|
||||
}
|
||||
|
||||
public void filterLeaderboards(String filterText) {
|
||||
WebElement leaderboardFilterTextField = findElementBySeleniumId(leaderboardsCaptionPanel, "FilterTextField");
|
||||
leaderboardFilterTextField.clear();
|
||||
leaderboardFilterTextField.sendKeys(filterText);
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.common.DataEntryDialog;
|
||||
|
||||
public class LeaderboardGroupCreateDialog extends DataEntryDialog {
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "NameTextBox")
|
||||
private WebElement nameField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "DescriptionTextBox")
|
||||
private WebElement descriptionField;
|
||||
|
||||
public LeaderboardGroupCreateDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.nameField.clear();
|
||||
this.nameField.sendKeys(name);
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.descriptionField.clear();
|
||||
this.descriptionField.sendKeys(description);
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.ui.Select;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaList.RegattaDescriptor;
|
||||
import com.sap.sailing.selenium.pages.common.DataEntryDialog;
|
||||
|
||||
public class RegattaLeaderboardCreateDialog extends DataEntryDialog {
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardNameField")
|
||||
private WebElement nameField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattaDropDown")
|
||||
private WebElement regattaDropDown;
|
||||
|
||||
public RegattaLeaderboardCreateDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void selectRegatta(RegattaDescriptor regatta) {
|
||||
Select dropDown = new Select(this.regattaDropDown);
|
||||
dropDown.selectByValue(regatta.toString());
|
||||
}
|
||||
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.regatta;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.common.DataEntryDialog;
|
||||
|
||||
public class RegattaCreateDialog extends DataEntryDialog {
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattaNameTextField")
|
||||
private WebElement regattaNameTextField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "BoatClassTextField")
|
||||
private WebElement boatClassTextField;
|
||||
|
||||
// @FindBy(how = BySeleniumId.class, using = "ScoringSystemDropDown")
|
||||
// private WebElement scoringSystemDropDown;
|
||||
// @FindBy(how = BySeleniumId.class, using = "EventDropDown")
|
||||
// private WebElement eventDropDown;
|
||||
// @FindBy(how = BySeleniumId.class, using = "CourseAreaDropDown")
|
||||
// private WebElement courseAreaDropDown;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "AddSeriesButton")
|
||||
private WebElement addSeriesButton;
|
||||
|
||||
public RegattaCreateDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void setRegattaName(String name) {
|
||||
this.regattaNameTextField.clear();
|
||||
this.regattaNameTextField.sendKeys(name);
|
||||
}
|
||||
|
||||
public void setBoatClass(String boatClass) {
|
||||
this.boatClassTextField.clear();
|
||||
this.boatClassTextField.sendKeys(boatClass);
|
||||
}
|
||||
|
||||
// TODO: Scoring System, Event and Course Area
|
||||
|
||||
public SeriesCreateDialog addSeries() {
|
||||
this.addSeriesButton.click();
|
||||
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "SeriesCreateDialog");
|
||||
|
||||
return new SeriesCreateDialog(this.driver, dialog);
|
||||
}
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.regatta;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.Actions;
|
||||
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntry;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTable;
|
||||
|
||||
// TODO: Implement if needed
|
||||
public class RegattaDetails extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattaNameLabel")
|
||||
private WebElement regattaNameLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "BoatClassLabel")
|
||||
private WebElement boatClassLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "CourseAreaLabel")
|
||||
private WebElement courseAreaLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "ScoringSystemLabel")
|
||||
private WebElement scoringSystemLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "SeriesTable")
|
||||
private WebElement seriesTable;
|
||||
|
||||
public RegattaDetails(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return this.regattaNameLabel.getText();
|
||||
}
|
||||
|
||||
public String getBoatClass() {
|
||||
return this.boatClassLabel.getText();
|
||||
}
|
||||
|
||||
public String getCouresArea() {
|
||||
return this.courseAreaLabel.getText();
|
||||
}
|
||||
|
||||
public String getScoringSystem() {
|
||||
return this.scoringSystemLabel.getText();
|
||||
}
|
||||
|
||||
// public void getSeries() {
|
||||
//
|
||||
// }
|
||||
|
||||
public SeriesEditDialog editSeries(String series) {
|
||||
DataEntry entry = findSeries(series);
|
||||
|
||||
if(entry != null) {
|
||||
WebElement action = Actions.findEditAction(entry.getWebElement());
|
||||
action.click();
|
||||
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "SeriesEditDialog");
|
||||
|
||||
return new SeriesEditDialog(this.driver, dialog);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteSeries(String series) {
|
||||
DataEntry entry = findSeries(series);
|
||||
|
||||
if(entry != null) {
|
||||
WebElement removeAction = Actions.findRemoveAction(entry.getWebElement());
|
||||
removeAction.click();
|
||||
|
||||
Actions.acceptAlert(this.driver);
|
||||
|
||||
//waitForAjaxRequests();
|
||||
}
|
||||
}
|
||||
|
||||
private DataEntry findSeries(String series) {
|
||||
CellTable<DataEntry> table = getSeriesTable();
|
||||
|
||||
for(DataEntry entry : table.getEntries()) {
|
||||
String name = entry.getColumnContent(0);
|
||||
|
||||
if(series.equals(name))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CellTable<DataEntry> getSeriesTable() {
|
||||
return new GenericCellTable<>(this.driver, this.seriesTable, DataEntry.class);
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.regatta;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
public class RegattaEditDialog extends PageArea {
|
||||
|
||||
public RegattaEditDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
}
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.regatta;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.Actions;
|
||||
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable;
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTable.SortingOrder;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntry;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTable;
|
||||
|
||||
public class RegattaList extends PageArea {
|
||||
public static class RegattaDescriptor {
|
||||
private final String name;
|
||||
private final String boatClass;
|
||||
|
||||
// TODO [D049941]: Mark as a bug and remove this method as soon as possible
|
||||
public static RegattaDescriptor fromString(String name) {
|
||||
if(name == null || name.isEmpty())
|
||||
return null;
|
||||
|
||||
int openingBrace = name.lastIndexOf('(');
|
||||
int closingBrace = name.lastIndexOf(')');
|
||||
|
||||
return new RegattaDescriptor(name.substring(0, openingBrace - 1),
|
||||
name.substring(openingBrace + 1, closingBrace));
|
||||
}
|
||||
|
||||
public RegattaDescriptor(String name, String boatClass) {
|
||||
this.name = name;
|
||||
this.boatClass = boatClass;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getBoatClass() {
|
||||
return this.boatClass;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.name + " (" + this.boatClass + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name, this.boatClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object)
|
||||
return true;
|
||||
|
||||
if (object == null)
|
||||
return false;
|
||||
|
||||
if (getClass() != object.getClass())
|
||||
return false;
|
||||
|
||||
RegattaDescriptor other = (RegattaDescriptor) object;
|
||||
|
||||
if (!Objects.equals(this.boatClass, other.boatClass))
|
||||
return false;
|
||||
|
||||
if (!Objects.equals(this.name, other.name))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FilterRegattasTextField")
|
||||
private WebElement filterRegattasTextField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "NoRegattasLabel")
|
||||
private WebElement noRegattasLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattasTable")
|
||||
private WebElement regattasTable;
|
||||
|
||||
public RegattaList(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void sortByRegattaName(SortingOrder order) {
|
||||
sortRegattaList(0, order);
|
||||
}
|
||||
|
||||
public void sortByBoatClass(SortingOrder order) {
|
||||
sortRegattaList(1, order);
|
||||
}
|
||||
|
||||
public List<RegattaDescriptor> getRegattas() {
|
||||
List<RegattaDescriptor> descriptors = new LinkedList<>();
|
||||
CellTable<DataEntry> table = getRegattasTable();
|
||||
|
||||
for(DataEntry entry : table.getEntries()) {
|
||||
String name = entry.getColumnContent(0);
|
||||
String boatClass = entry.getColumnContent(1);
|
||||
|
||||
descriptors.add(new RegattaDescriptor(name, boatClass));
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public void selectRegatta(RegattaDescriptor regatta) {
|
||||
DataEntry entry = findRegatta(regatta);
|
||||
|
||||
if(entry != null) {
|
||||
entry.select();
|
||||
}
|
||||
}
|
||||
|
||||
// public EditRegattaDialog editRegatta(RegattaDescriptor regatta) {
|
||||
//
|
||||
// }
|
||||
|
||||
public void removeRegatta(RegattaDescriptor regatta) {
|
||||
DataEntry entry = findRegatta(regatta);
|
||||
|
||||
if(entry != null) {
|
||||
WebElement action = Actions.findRemoveAction(entry.getWebElement());
|
||||
action.click();
|
||||
|
||||
waitForAjaxRequests();
|
||||
|
||||
Actions.acceptAlert(this.driver);
|
||||
}
|
||||
}
|
||||
|
||||
private DataEntry findRegatta(RegattaDescriptor regatta) {
|
||||
CellTable<DataEntry> table = getRegattasTable();
|
||||
|
||||
for(DataEntry entry : table.getEntries()) {
|
||||
String name = entry.getColumnContent(0);
|
||||
// String boatClass = columns.getColumnContent(1);
|
||||
//
|
||||
// if(regatta.equals(new RegattaDescriptor(name, boatClass)))
|
||||
// return row;
|
||||
if(regatta.equals(RegattaDescriptor.fromString(name)))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void sortRegattaList(int column, SortingOrder order) {
|
||||
CellTable<DataEntry> table = getRegattasTable();
|
||||
table.sortByColumn(column, order);
|
||||
}
|
||||
|
||||
private CellTable<DataEntry> getRegattasTable() {
|
||||
return new GenericCellTable<>(this.driver, this.regattasTable, DataEntry.class);
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package com.sap.sailing.selenium.pages.adminconsole.regatta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaList.RegattaDescriptor;
|
||||
|
||||
public class RegattaStructureManagementPanel extends PageArea {
|
||||
public static final String DEFAULT_SERIES_NAME = "Default"; //$NON-NLS-1$
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "AddRegattaButton")
|
||||
WebElement addRegattaButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RemoveRegattaButton")
|
||||
WebElement removeRegattaButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattaListSection")
|
||||
WebElement regattaList;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RegattaDetailsSection")
|
||||
WebElement regattaDetails;
|
||||
|
||||
public RegattaStructureManagementPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public RegattaCreateDialog startRegattaCreation() {
|
||||
this.addRegattaButton.click();
|
||||
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "RegattaCreateDialog"); //$NON-NLS-1$
|
||||
|
||||
return new RegattaCreateDialog(this.driver, dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates a regatta with 1 series (named "Default").</p>
|
||||
*
|
||||
* @param regatta
|
||||
*/
|
||||
public void createRegatta(RegattaDescriptor regatta) {
|
||||
RegattaCreateDialog createRegattaDialog = startRegattaCreation();
|
||||
createRegattaDialog.setRegattaName(regatta.getName());
|
||||
createRegattaDialog.setBoatClass(regatta.getBoatClass());
|
||||
|
||||
SeriesCreateDialog addSeriesDialog = createRegattaDialog.addSeries();
|
||||
addSeriesDialog.setSeriesName(DEFAULT_SERIES_NAME);
|
||||
|
||||
addSeriesDialog.pressOk();
|
||||
|
||||
// QUESTION: How do we handle an error (here or in the dialog)?
|
||||
createRegattaDialog.pressOk();
|
||||
}
|
||||
|
||||
public void removeRegatta(RegattaDescriptor regatta) {
|
||||
// Select the regatta and click the remove button
|
||||
}
|
||||
|
||||
public void removeRegattas(List<RegattaDescriptor> regattas) {
|
||||
// Select all regattas and click the remove button
|
||||
}
|
||||
|
||||
public RegattaList getRegattaList() {
|
||||
return new RegattaList(this.driver, this.regattaList);
|
||||
}
|
||||
|
||||
public void selectRegatta(RegattaDescriptor regatta) {
|
||||
|
||||
}
|
||||
|
||||
public RegattaDetails getRegattaDetails(RegattaDescriptor regatta) {
|
||||
RegattaList regattaList = getRegattaList();
|
||||
regattaList.selectRegatta(regatta);
|
||||
|
||||
return getRegattaDetails();
|
||||
}
|
||||
|
||||
public RegattaDetails getRegattaDetails() {
|
||||
if(this.regattaDetails.isDisplayed())
|
||||
return new RegattaDetails(this.driver, this.regattaDetails);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 222 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user